Coverage Report

Created: 2018-11-16 02:38

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/include/llvm/Support/BinaryStreamReader.h
Line
Count
Source (jump to first uncovered line)
1
//===- BinaryStreamReader.h - Reads objects from a binary stream *- C++ -*-===//
2
//
3
//                     The LLVM Compiler Infrastructure
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
10
#ifndef LLVM_SUPPORT_BINARYSTREAMREADER_H
11
#define LLVM_SUPPORT_BINARYSTREAMREADER_H
12
13
#include "llvm/ADT/ArrayRef.h"
14
#include "llvm/ADT/STLExtras.h"
15
#include "llvm/Support/BinaryStreamArray.h"
16
#include "llvm/Support/BinaryStreamRef.h"
17
#include "llvm/Support/ConvertUTF.h"
18
#include "llvm/Support/Endian.h"
19
#include "llvm/Support/Error.h"
20
#include "llvm/Support/type_traits.h"
21
22
#include <string>
23
#include <type_traits>
24
25
namespace llvm {
26
27
/// Provides read only access to a subclass of `BinaryStream`.  Provides
28
/// bounds checking and helpers for writing certain common data types such as
29
/// null-terminated strings, integers in various flavors of endianness, etc.
30
/// Can be subclassed to provide reading of custom datatypes, although no
31
/// are overridable.
32
class BinaryStreamReader {
33
public:
34
  BinaryStreamReader() = default;
35
  explicit BinaryStreamReader(BinaryStreamRef Ref);
36
  explicit BinaryStreamReader(BinaryStream &Stream);
37
  explicit BinaryStreamReader(ArrayRef<uint8_t> Data,
38
                              llvm::support::endianness Endian);
39
  explicit BinaryStreamReader(StringRef Data, llvm::support::endianness Endian);
40
41
  BinaryStreamReader(const BinaryStreamReader &Other)
42
3.56k
      : Stream(Other.Stream), Offset(Other.Offset) {}
43
44
  BinaryStreamReader &operator=(const BinaryStreamReader &Other) {
45
    Stream = Other.Stream;
46
    Offset = Other.Offset;
47
    return *this;
48
  }
49
50
57.1k
  virtual ~BinaryStreamReader() {}
51
52
  /// Read as much as possible from the underlying string at the current offset
53
  /// without invoking a copy, and set \p Buffer to the resulting data slice.
54
  /// Updates the stream's offset to point after the newly read data.
55
  ///
56
  /// \returns a success error code if the data was successfully read, otherwise
57
  /// returns an appropriate error code.
58
  Error readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer);
59
60
  /// Read \p Size bytes from the underlying stream at the current offset and
61
  /// and set \p Buffer to the resulting data slice.  Whether a copy occurs
62
  /// depends on the implementation of the underlying stream.  Updates the
63
  /// stream's offset to point after the newly read data.
64
  ///
65
  /// \returns a success error code if the data was successfully read, otherwise
66
  /// returns an appropriate error code.
67
  Error readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size);
68
69
  /// Read an integer of the specified endianness into \p Dest and update the
70
  /// stream's offset.  The data is always copied from the stream's underlying
71
  /// buffer into \p Dest. Updates the stream's offset to point after the newly
72
  /// read data.
73
  ///
74
  /// \returns a success error code if the data was successfully read, otherwise
75
  /// returns an appropriate error code.
76
117k
  template <typename T> Error readInteger(T &Dest) {
77
117k
    static_assert(std::is_integral<T>::value,
78
117k
                  "Cannot call readInteger with non-integral value!");
79
117k
80
117k
    ArrayRef<uint8_t> Bytes;
81
117k
    if (auto EC = readBytes(Bytes, sizeof(T)))
82
0
      return EC;
83
117k
84
117k
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
85
117k
        Bytes.data(), Stream.getEndian());
86
117k
    return Error::success();
87
117k
  }
llvm::Error llvm::BinaryStreamReader::readInteger<unsigned short>(unsigned short&)
Line
Count
Source
76
54.9k
  template <typename T> Error readInteger(T &Dest) {
77
54.9k
    static_assert(std::is_integral<T>::value,
78
54.9k
                  "Cannot call readInteger with non-integral value!");
79
54.9k
80
54.9k
    ArrayRef<uint8_t> Bytes;
81
54.9k
    if (auto EC = readBytes(Bytes, sizeof(T)))
82
0
      return EC;
83
54.9k
84
54.9k
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
85
54.9k
        Bytes.data(), Stream.getEndian());
86
54.9k
    return Error::success();
87
54.9k
  }
llvm::Error llvm::BinaryStreamReader::readInteger<unsigned int>(unsigned int&)
Line
Count
Source
76
54.9k
  template <typename T> Error readInteger(T &Dest) {
77
54.9k
    static_assert(std::is_integral<T>::value,
78
54.9k
                  "Cannot call readInteger with non-integral value!");
79
54.9k
80
54.9k
    ArrayRef<uint8_t> Bytes;
81
54.9k
    if (auto EC = readBytes(Bytes, sizeof(T)))
82
0
      return EC;
83
54.9k
84
54.9k
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
85
54.9k
        Bytes.data(), Stream.getEndian());
86
54.9k
    return Error::success();
87
54.9k
  }
llvm::Error llvm::BinaryStreamReader::readInteger<signed char>(signed char&)
Line
Count
Source
76
4
  template <typename T> Error readInteger(T &Dest) {
77
4
    static_assert(std::is_integral<T>::value,
78
4
                  "Cannot call readInteger with non-integral value!");
79
4
80
4
    ArrayRef<uint8_t> Bytes;
81
4
    if (auto EC = readBytes(Bytes, sizeof(T)))
82
0
      return EC;
83
4
84
4
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
85
4
        Bytes.data(), Stream.getEndian());
86
4
    return Error::success();
87
4
  }
llvm::Error llvm::BinaryStreamReader::readInteger<short>(short&)
Line
Count
Source
76
8
  template <typename T> Error readInteger(T &Dest) {
77
8
    static_assert(std::is_integral<T>::value,
78
8
                  "Cannot call readInteger with non-integral value!");
79
8
80
8
    ArrayRef<uint8_t> Bytes;
81
8
    if (auto EC = readBytes(Bytes, sizeof(T)))
82
0
      return EC;
83
8
84
8
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
85
8
        Bytes.data(), Stream.getEndian());
86
8
    return Error::success();
87
8
  }
llvm::Error llvm::BinaryStreamReader::readInteger<int>(int&)
Line
Count
Source
76
2.13k
  template <typename T> Error readInteger(T &Dest) {
77
2.13k
    static_assert(std::is_integral<T>::value,
78
2.13k
                  "Cannot call readInteger with non-integral value!");
79
2.13k
80
2.13k
    ArrayRef<uint8_t> Bytes;
81
2.13k
    if (auto EC = readBytes(Bytes, sizeof(T)))
82
0
      return EC;
83
2.13k
84
2.13k
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
85
2.13k
        Bytes.data(), Stream.getEndian());
86
2.13k
    return Error::success();
87
2.13k
  }
llvm::Error llvm::BinaryStreamReader::readInteger<long long>(long long&)
Line
Count
Source
76
20
  template <typename T> Error readInteger(T &Dest) {
77
20
    static_assert(std::is_integral<T>::value,
78
20
                  "Cannot call readInteger with non-integral value!");
79
20
80
20
    ArrayRef<uint8_t> Bytes;
81
20
    if (auto EC = readBytes(Bytes, sizeof(T)))
82
0
      return EC;
83
20
84
20
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
85
20
        Bytes.data(), Stream.getEndian());
86
20
    return Error::success();
87
20
  }
llvm::Error llvm::BinaryStreamReader::readInteger<unsigned long long>(unsigned long long&)
Line
Count
Source
76
2
  template <typename T> Error readInteger(T &Dest) {
77
2
    static_assert(std::is_integral<T>::value,
78
2
                  "Cannot call readInteger with non-integral value!");
79
2
80
2
    ArrayRef<uint8_t> Bytes;
81
2
    if (auto EC = readBytes(Bytes, sizeof(T)))
82
0
      return EC;
83
2
84
2
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
85
2
        Bytes.data(), Stream.getEndian());
86
2
    return Error::success();
87
2
  }
llvm::Error llvm::BinaryStreamReader::readInteger<unsigned char>(unsigned char&)
Line
Count
Source
76
5.37k
  template <typename T> Error readInteger(T &Dest) {
77
5.37k
    static_assert(std::is_integral<T>::value,
78
5.37k
                  "Cannot call readInteger with non-integral value!");
79
5.37k
80
5.37k
    ArrayRef<uint8_t> Bytes;
81
5.37k
    if (auto EC = readBytes(Bytes, sizeof(T)))
82
0
      return EC;
83
5.37k
84
5.37k
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
85
5.37k
        Bytes.data(), Stream.getEndian());
86
5.37k
    return Error::success();
87
5.37k
  }
88
89
  /// Similar to readInteger.
90
10.2k
  template <typename T> Error readEnum(T &Dest) {
91
10.2k
    static_assert(std::is_enum<T>::value,
92
10.2k
                  "Cannot call readEnum with non-enum value!");
93
10.2k
    typename std::underlying_type<T>::type N;
94
10.2k
    if (auto EC = readInteger(N))
95
0
      return EC;
96
10.2k
    Dest = static_cast<T>(N);
97
10.2k
    return Error::success();
98
10.2k
  }
99
100
  /// Read a null terminated string from \p Dest.  Whether a copy occurs depends
101
  /// on the implementation of the underlying stream.  Updates the stream's
102
  /// offset to point after the newly read data.
103
  ///
104
  /// \returns a success error code if the data was successfully read, otherwise
105
  /// returns an appropriate error code.
106
  Error readCString(StringRef &Dest);
107
108
  /// Similar to readCString, however read a null-terminated UTF16 string
109
  /// instead.
110
  ///
111
  /// \returns a success error code if the data was successfully read, otherwise
112
  /// returns an appropriate error code.
113
  Error readWideString(ArrayRef<UTF16> &Dest);
114
115
  /// Read a \p Length byte string into \p Dest.  Whether a copy occurs depends
116
  /// on the implementation of the underlying stream.  Updates the stream's
117
  /// offset to point after the newly read data.
118
  ///
119
  /// \returns a success error code if the data was successfully read, otherwise
120
  /// returns an appropriate error code.
121
  Error readFixedString(StringRef &Dest, uint32_t Length);
122
123
  /// Read the entire remainder of the underlying stream into \p Ref.  This is
124
  /// equivalent to calling getUnderlyingStream().slice(Offset).  Updates the
125
  /// stream's offset to point to the end of the stream.  Never causes a copy.
126
  ///
127
  /// \returns a success error code if the data was successfully read, otherwise
128
  /// returns an appropriate error code.
129
  Error readStreamRef(BinaryStreamRef &Ref);
130
131
  /// Read \p Length bytes from the underlying stream into \p Ref.  This is
132
  /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
133
  /// Updates the stream's offset to point after the newly read object.  Never
134
  /// causes a copy.
135
  ///
136
  /// \returns a success error code if the data was successfully read, otherwise
137
  /// returns an appropriate error code.
138
  Error readStreamRef(BinaryStreamRef &Ref, uint32_t Length);
139
140
  /// Read \p Length bytes from the underlying stream into \p Stream.  This is
141
  /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
142
  /// Updates the stream's offset to point after the newly read object.  Never
143
  /// causes a copy.
144
  ///
145
  /// \returns a success error code if the data was successfully read, otherwise
146
  /// returns an appropriate error code.
147
  Error readSubstream(BinarySubstreamRef &Stream, uint32_t Size);
148
149
  /// Get a pointer to an object of type T from the underlying stream, as if by
150
  /// memcpy, and store the result into \p Dest.  It is up to the caller to
151
  /// ensure that objects of type T can be safely treated in this manner.
152
  /// Updates the stream's offset to point after the newly read object.  Whether
153
  /// a copy occurs depends upon the implementation of the underlying
154
  /// stream.
155
  ///
156
  /// \returns a success error code if the data was successfully read, otherwise
157
  /// returns an appropriate error code.
158
19.8k
  template <typename T> Error readObject(const T *&Dest) {
159
19.8k
    ArrayRef<uint8_t> Buffer;
160
19.8k
    if (auto EC = readBytes(Buffer, sizeof(T)))
161
1
      return EC;
162
19.8k
    Dest = reinterpret_cast<const T *>(Buffer.data());
163
19.8k
    return Error::success();
164
19.8k
  }
llvm::Error llvm::BinaryStreamReader::readObject<unsigned short>(unsigned short const*&)
Line
Count
Source
158
1.34k
  template <typename T> Error readObject(const T *&Dest) {
159
1.34k
    ArrayRef<uint8_t> Buffer;
160
1.34k
    if (auto EC = readBytes(Buffer, sizeof(T)))
161
0
      return EC;
162
1.34k
    Dest = reinterpret_cast<const T *>(Buffer.data());
163
1.34k
    return Error::success();
164
1.34k
  }
llvm::Error llvm::BinaryStreamReader::readObject<llvm::object::coff_resource_dir_table>(llvm::object::coff_resource_dir_table const*&)
Line
Count
Source
158
131
  template <typename T> Error readObject(const T *&Dest) {
159
131
    ArrayRef<uint8_t> Buffer;
160
131
    if (auto EC = readBytes(Buffer, sizeof(T)))
161
0
      return EC;
162
131
    Dest = reinterpret_cast<const T *>(Buffer.data());
163
131
    return Error::success();
164
131
  }
llvm::Error llvm::BinaryStreamReader::readObject<llvm::object::WinResHeaderPrefix>(llvm::object::WinResHeaderPrefix const*&)
Line
Count
Source
158
316
  template <typename T> Error readObject(const T *&Dest) {
159
316
    ArrayRef<uint8_t> Buffer;
160
316
    if (auto EC = readBytes(Buffer, sizeof(T)))
161
0
      return EC;
162
316
    Dest = reinterpret_cast<const T *>(Buffer.data());
163
316
    return Error::success();
164
316
  }
llvm::Error llvm::BinaryStreamReader::readObject<llvm::object::WinResHeaderSuffix>(llvm::object::WinResHeaderSuffix const*&)
Line
Count
Source
158
316
  template <typename T> Error readObject(const T *&Dest) {
159
316
    ArrayRef<uint8_t> Buffer;
160
316
    if (auto EC = readBytes(Buffer, sizeof(T)))
161
0
      return EC;
162
316
    Dest = reinterpret_cast<const T *>(Buffer.data());
163
316
    return Error::success();
164
316
  }
llvm::Error llvm::BinaryStreamReader::readObject<llvm::codeview::RecordPrefix>(llvm::codeview::RecordPrefix const*&)
Line
Count
Source
158
17.2k
  template <typename T> Error readObject(const T *&Dest) {
159
17.2k
    ArrayRef<uint8_t> Buffer;
160
17.2k
    if (auto EC = readBytes(Buffer, sizeof(T)))
161
1
      return EC;
162
17.2k
    Dest = reinterpret_cast<const T *>(Buffer.data());
163
17.2k
    return Error::success();
164
17.2k
  }
llvm::Error llvm::BinaryStreamReader::readObject<llvm::support::detail::packed_endian_specific_integral<unsigned short, (llvm::support::endianness)1, 1ul> >(llvm::support::detail::packed_endian_specific_integral<unsigned short, (llvm::support::endianness)1, 1ul> const*&)
Line
Count
Source
158
128
  template <typename T> Error readObject(const T *&Dest) {
159
128
    ArrayRef<uint8_t> Buffer;
160
128
    if (auto EC = readBytes(Buffer, sizeof(T)))
161
0
      return EC;
162
128
    Dest = reinterpret_cast<const T *>(Buffer.data());
163
128
    return Error::success();
164
128
  }
llvm::Error llvm::BinaryStreamReader::readObject<llvm::support::detail::packed_endian_specific_integral<int, (llvm::support::endianness)1, 1ul> >(llvm::support::detail::packed_endian_specific_integral<int, (llvm::support::endianness)1, 1ul> const*&)
Line
Count
Source
158
12
  template <typename T> Error readObject(const T *&Dest) {
159
12
    ArrayRef<uint8_t> Buffer;
160
12
    if (auto EC = readBytes(Buffer, sizeof(T)))
161
0
      return EC;
162
12
    Dest = reinterpret_cast<const T *>(Buffer.data());
163
12
    return Error::success();
164
12
  }
llvm::Error llvm::BinaryStreamReader::readObject<llvm::support::detail::packed_endian_specific_integral<unsigned int, (llvm::support::endianness)1, 1ul> >(llvm::support::detail::packed_endian_specific_integral<unsigned int, (llvm::support::endianness)1, 1ul> const*&)
Line
Count
Source
158
381
  template <typename T> Error readObject(const T *&Dest) {
159
381
    ArrayRef<uint8_t> Buffer;
160
381
    if (auto EC = readBytes(Buffer, sizeof(T)))
161
0
      return EC;
162
381
    Dest = reinterpret_cast<const T *>(Buffer.data());
163
381
    return Error::success();
164
381
  }
165
166
  /// Get a reference to a \p NumElements element array of objects of type T
167
  /// from the underlying stream as if by memcpy, and store the resulting array
168
  /// slice into \p array.  It is up to the caller to ensure that objects of
169
  /// type T can be safely treated in this manner.  Updates the stream's offset
170
  /// to point after the newly read object.  Whether a copy occurs depends upon
171
  /// the implementation of the underlying stream.
172
  ///
173
  /// \returns a success error code if the data was successfully read, otherwise
174
  /// returns an appropriate error code.
175
  template <typename T>
176
544
  Error readArray(ArrayRef<T> &Array, uint32_t NumElements) {
177
544
    ArrayRef<uint8_t> Bytes;
178
544
    if (NumElements == 0) {
179
1
      Array = ArrayRef<T>();
180
1
      return Error::success();
181
1
    }
182
543
183
543
    if (NumElements > UINT32_MAX / sizeof(T))
184
0
      return make_error<BinaryStreamError>(
185
0
          stream_error_code::invalid_array_size);
186
543
187
543
    if (auto EC = readBytes(Bytes, NumElements * sizeof(T)))
188
0
      return EC;
189
543
190
543
    assert(alignmentAdjustment(Bytes.data(), alignof(T)) == 0 &&
191
543
           "Reading at invalid alignment!");
192
543
193
543
    Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements);
194
543
    return Error::success();
195
543
  }
llvm::Error llvm::BinaryStreamReader::readArray<unsigned short>(llvm::ArrayRef<unsigned short>&, unsigned int)
Line
Count
Source
176
170
  Error readArray(ArrayRef<T> &Array, uint32_t NumElements) {
177
170
    ArrayRef<uint8_t> Bytes;
178
170
    if (NumElements == 0) {
179
0
      Array = ArrayRef<T>();
180
0
      return Error::success();
181
0
    }
182
170
183
170
    if (NumElements > UINT32_MAX / sizeof(T))
184
0
      return make_error<BinaryStreamError>(
185
0
          stream_error_code::invalid_array_size);
186
170
187
170
    if (auto EC = readBytes(Bytes, NumElements * sizeof(T)))
188
0
      return EC;
189
170
190
170
    assert(alignmentAdjustment(Bytes.data(), alignof(T)) == 0 &&
191
170
           "Reading at invalid alignment!");
192
170
193
170
    Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements);
194
170
    return Error::success();
195
170
  }
llvm::Error llvm::BinaryStreamReader::readArray<unsigned char>(llvm::ArrayRef<unsigned char>&, unsigned int)
Line
Count
Source
176
374
  Error readArray(ArrayRef<T> &Array, uint32_t NumElements) {
177
374
    ArrayRef<uint8_t> Bytes;
178
374
    if (NumElements == 0) {
179
1
      Array = ArrayRef<T>();
180
1
      return Error::success();
181
1
    }
182
373
183
373
    if (NumElements > UINT32_MAX / sizeof(T))
184
0
      return make_error<BinaryStreamError>(
185
0
          stream_error_code::invalid_array_size);
186
373
187
373
    if (auto EC = readBytes(Bytes, NumElements * sizeof(T)))
188
0
      return EC;
189
373
190
373
    assert(alignmentAdjustment(Bytes.data(), alignof(T)) == 0 &&
191
373
           "Reading at invalid alignment!");
192
373
193
373
    Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements);
194
373
    return Error::success();
195
373
  }
196
197
  /// Read a VarStreamArray of size \p Size bytes and store the result into
198
  /// \p Array.  Updates the stream's offset to point after the newly read
199
  /// array.  Never causes a copy (although iterating the elements of the
200
  /// VarStreamArray may, depending upon the implementation of the underlying
201
  /// stream).
202
  ///
203
  /// \returns a success error code if the data was successfully read, otherwise
204
  /// returns an appropriate error code.
205
  template <typename T, typename U>
206
  Error readArray(VarStreamArray<T, U> &Array, uint32_t Size) {
207
    BinaryStreamRef S;
208
    if (auto EC = readStreamRef(S, Size))
209
      return EC;
210
    Array.setUnderlyingStream(S);
211
    return Error::success();
212
  }
213
214
  /// Read a FixedStreamArray of \p NumItems elements and store the result into
215
  /// \p Array.  Updates the stream's offset to point after the newly read
216
  /// array.  Never causes a copy (although iterating the elements of the
217
  /// FixedStreamArray may, depending upon the implementation of the underlying
218
  /// stream).
219
  ///
220
  /// \returns a success error code if the data was successfully read, otherwise
221
  /// returns an appropriate error code.
222
  template <typename T>
223
416
  Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) {
224
416
    if (NumItems == 0) {
225
0
      Array = FixedStreamArray<T>();
226
0
      return Error::success();
227
0
    }
228
416
229
416
    if (NumItems > UINT32_MAX / sizeof(T))
230
0
      return make_error<BinaryStreamError>(
231
0
          stream_error_code::invalid_array_size);
232
416
233
416
    BinaryStreamRef View;
234
416
    if (auto EC = readStreamRef(View, NumItems * sizeof(T)))
235
0
      return EC;
236
416
237
416
    Array = FixedStreamArray<T>(View);
238
416
    return Error::success();
239
416
  }
240
241
13.4k
  bool empty() const { return bytesRemaining() == 0; }
242
108k
  void setOffset(uint32_t Off) { Offset = Off; }
243
176k
  uint32_t getOffset() const { return Offset; }
244
51.2k
  uint32_t getLength() const { return Stream.getLength(); }
245
50.7k
  uint32_t bytesRemaining() const { return getLength() - getOffset(); }
246
247
  /// Advance the stream's offset by \p Amount bytes.
248
  ///
249
  /// \returns a success error code if at least \p Amount bytes remain in the
250
  /// stream, otherwise returns an appropriate error code.
251
  Error skip(uint32_t Amount);
252
253
  /// Examine the next byte of the underlying stream without advancing the
254
  /// stream's offset.  If the stream is empty the behavior is undefined.
255
  ///
256
  /// \returns the next byte in the stream.
257
  uint8_t peek() const;
258
259
  Error padToAlignment(uint32_t Align);
260
261
  std::pair<BinaryStreamReader, BinaryStreamReader>
262
  split(uint32_t Offset) const;
263
264
private:
265
  BinaryStreamRef Stream;
266
  uint32_t Offset = 0;
267
};
268
} // namespace llvm
269
270
#endif // LLVM_SUPPORT_BINARYSTREAMREADER_H