Coverage Report

Created: 2019-02-23 12:57

/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
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#ifndef LLVM_SUPPORT_BINARYSTREAMREADER_H
10
#define LLVM_SUPPORT_BINARYSTREAMREADER_H
11
12
#include "llvm/ADT/ArrayRef.h"
13
#include "llvm/ADT/STLExtras.h"
14
#include "llvm/Support/BinaryStreamArray.h"
15
#include "llvm/Support/BinaryStreamRef.h"
16
#include "llvm/Support/ConvertUTF.h"
17
#include "llvm/Support/Endian.h"
18
#include "llvm/Support/Error.h"
19
#include "llvm/Support/type_traits.h"
20
21
#include <string>
22
#include <type_traits>
23
24
namespace llvm {
25
26
/// Provides read only access to a subclass of `BinaryStream`.  Provides
27
/// bounds checking and helpers for writing certain common data types such as
28
/// null-terminated strings, integers in various flavors of endianness, etc.
29
/// Can be subclassed to provide reading of custom datatypes, although no
30
/// are overridable.
31
class BinaryStreamReader {
32
public:
33
  BinaryStreamReader() = default;
34
  explicit BinaryStreamReader(BinaryStreamRef Ref);
35
  explicit BinaryStreamReader(BinaryStream &Stream);
36
  explicit BinaryStreamReader(ArrayRef<uint8_t> Data,
37
                              llvm::support::endianness Endian);
38
  explicit BinaryStreamReader(StringRef Data, llvm::support::endianness Endian);
39
40
  BinaryStreamReader(const BinaryStreamReader &Other)
41
3.75k
      : Stream(Other.Stream), Offset(Other.Offset) {}
42
43
  BinaryStreamReader &operator=(const BinaryStreamReader &Other) {
44
    Stream = Other.Stream;
45
    Offset = Other.Offset;
46
    return *this;
47
  }
48
49
59.3k
  virtual ~BinaryStreamReader() {}
50
51
  /// Read as much as possible from the underlying string at the current offset
52
  /// without invoking a copy, and set \p Buffer to the resulting data slice.
53
  /// Updates the stream's offset to point after the newly read data.
54
  ///
55
  /// \returns a success error code if the data was successfully read, otherwise
56
  /// returns an appropriate error code.
57
  Error readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer);
58
59
  /// Read \p Size bytes from the underlying stream at the current offset and
60
  /// and set \p Buffer to the resulting data slice.  Whether a copy occurs
61
  /// depends on the implementation of the underlying stream.  Updates the
62
  /// stream's offset to point after the newly read data.
63
  ///
64
  /// \returns a success error code if the data was successfully read, otherwise
65
  /// returns an appropriate error code.
66
  Error readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size);
67
68
  /// Read an integer of the specified endianness into \p Dest and update the
69
  /// stream's offset.  The data is always copied from the stream's underlying
70
  /// buffer into \p Dest. Updates the stream's offset to point after the newly
71
  /// read data.
72
  ///
73
  /// \returns a success error code if the data was successfully read, otherwise
74
  /// returns an appropriate error code.
75
119k
  template <typename T> Error readInteger(T &Dest) {
76
119k
    static_assert(std::is_integral<T>::value,
77
119k
                  "Cannot call readInteger with non-integral value!");
78
119k
79
119k
    ArrayRef<uint8_t> Bytes;
80
119k
    if (auto EC = readBytes(Bytes, sizeof(T)))
81
0
      return EC;
82
119k
83
119k
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
84
119k
        Bytes.data(), Stream.getEndian());
85
119k
    return Error::success();
86
119k
  }
llvm::Error llvm::BinaryStreamReader::readInteger<unsigned short>(unsigned short&)
Line
Count
Source
75
56.1k
  template <typename T> Error readInteger(T &Dest) {
76
56.1k
    static_assert(std::is_integral<T>::value,
77
56.1k
                  "Cannot call readInteger with non-integral value!");
78
56.1k
79
56.1k
    ArrayRef<uint8_t> Bytes;
80
56.1k
    if (auto EC = readBytes(Bytes, sizeof(T)))
81
0
      return EC;
82
56.1k
83
56.1k
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
84
56.1k
        Bytes.data(), Stream.getEndian());
85
56.1k
    return Error::success();
86
56.1k
  }
llvm::Error llvm::BinaryStreamReader::readInteger<unsigned int>(unsigned int&)
Line
Count
Source
75
56.0k
  template <typename T> Error readInteger(T &Dest) {
76
56.0k
    static_assert(std::is_integral<T>::value,
77
56.0k
                  "Cannot call readInteger with non-integral value!");
78
56.0k
79
56.0k
    ArrayRef<uint8_t> Bytes;
80
56.0k
    if (auto EC = readBytes(Bytes, sizeof(T)))
81
0
      return EC;
82
56.0k
83
56.0k
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
84
56.0k
        Bytes.data(), Stream.getEndian());
85
56.0k
    return Error::success();
86
56.0k
  }
llvm::Error llvm::BinaryStreamReader::readInteger<signed char>(signed char&)
Line
Count
Source
75
4
  template <typename T> Error readInteger(T &Dest) {
76
4
    static_assert(std::is_integral<T>::value,
77
4
                  "Cannot call readInteger with non-integral value!");
78
4
79
4
    ArrayRef<uint8_t> Bytes;
80
4
    if (auto EC = readBytes(Bytes, sizeof(T)))
81
0
      return EC;
82
4
83
4
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
84
4
        Bytes.data(), Stream.getEndian());
85
4
    return Error::success();
86
4
  }
llvm::Error llvm::BinaryStreamReader::readInteger<short>(short&)
Line
Count
Source
75
8
  template <typename T> Error readInteger(T &Dest) {
76
8
    static_assert(std::is_integral<T>::value,
77
8
                  "Cannot call readInteger with non-integral value!");
78
8
79
8
    ArrayRef<uint8_t> Bytes;
80
8
    if (auto EC = readBytes(Bytes, sizeof(T)))
81
0
      return EC;
82
8
83
8
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
84
8
        Bytes.data(), Stream.getEndian());
85
8
    return Error::success();
86
8
  }
llvm::Error llvm::BinaryStreamReader::readInteger<int>(int&)
Line
Count
Source
75
2.15k
  template <typename T> Error readInteger(T &Dest) {
76
2.15k
    static_assert(std::is_integral<T>::value,
77
2.15k
                  "Cannot call readInteger with non-integral value!");
78
2.15k
79
2.15k
    ArrayRef<uint8_t> Bytes;
80
2.15k
    if (auto EC = readBytes(Bytes, sizeof(T)))
81
0
      return EC;
82
2.15k
83
2.15k
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
84
2.15k
        Bytes.data(), Stream.getEndian());
85
2.15k
    return Error::success();
86
2.15k
  }
llvm::Error llvm::BinaryStreamReader::readInteger<long long>(long long&)
Line
Count
Source
75
20
  template <typename T> Error readInteger(T &Dest) {
76
20
    static_assert(std::is_integral<T>::value,
77
20
                  "Cannot call readInteger with non-integral value!");
78
20
79
20
    ArrayRef<uint8_t> Bytes;
80
20
    if (auto EC = readBytes(Bytes, sizeof(T)))
81
0
      return EC;
82
20
83
20
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
84
20
        Bytes.data(), Stream.getEndian());
85
20
    return Error::success();
86
20
  }
llvm::Error llvm::BinaryStreamReader::readInteger<unsigned long long>(unsigned long long&)
Line
Count
Source
75
2
  template <typename T> Error readInteger(T &Dest) {
76
2
    static_assert(std::is_integral<T>::value,
77
2
                  "Cannot call readInteger with non-integral value!");
78
2
79
2
    ArrayRef<uint8_t> Bytes;
80
2
    if (auto EC = readBytes(Bytes, sizeof(T)))
81
0
      return EC;
82
2
83
2
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
84
2
        Bytes.data(), Stream.getEndian());
85
2
    return Error::success();
86
2
  }
llvm::Error llvm::BinaryStreamReader::readInteger<unsigned char>(unsigned char&)
Line
Count
Source
75
5.43k
  template <typename T> Error readInteger(T &Dest) {
76
5.43k
    static_assert(std::is_integral<T>::value,
77
5.43k
                  "Cannot call readInteger with non-integral value!");
78
5.43k
79
5.43k
    ArrayRef<uint8_t> Bytes;
80
5.43k
    if (auto EC = readBytes(Bytes, sizeof(T)))
81
0
      return EC;
82
5.43k
83
5.43k
    Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
84
5.43k
        Bytes.data(), Stream.getEndian());
85
5.43k
    return Error::success();
86
5.43k
  }
87
88
  /// Similar to readInteger.
89
10.3k
  template <typename T> Error readEnum(T &Dest) {
90
10.3k
    static_assert(std::is_enum<T>::value,
91
10.3k
                  "Cannot call readEnum with non-enum value!");
92
10.3k
    typename std::underlying_type<T>::type N;
93
10.3k
    if (auto EC = readInteger(N))
94
0
      return EC;
95
10.3k
    Dest = static_cast<T>(N);
96
10.3k
    return Error::success();
97
10.3k
  }
98
99
  /// Read a null terminated string from \p Dest.  Whether a copy occurs depends
100
  /// on the implementation of the underlying stream.  Updates the stream's
101
  /// offset to point after the newly read data.
102
  ///
103
  /// \returns a success error code if the data was successfully read, otherwise
104
  /// returns an appropriate error code.
105
  Error readCString(StringRef &Dest);
106
107
  /// Similar to readCString, however read a null-terminated UTF16 string
108
  /// instead.
109
  ///
110
  /// \returns a success error code if the data was successfully read, otherwise
111
  /// returns an appropriate error code.
112
  Error readWideString(ArrayRef<UTF16> &Dest);
113
114
  /// Read a \p Length byte string into \p Dest.  Whether a copy occurs depends
115
  /// on the implementation of the underlying stream.  Updates the stream's
116
  /// offset to point after the newly read data.
117
  ///
118
  /// \returns a success error code if the data was successfully read, otherwise
119
  /// returns an appropriate error code.
120
  Error readFixedString(StringRef &Dest, uint32_t Length);
121
122
  /// Read the entire remainder of the underlying stream into \p Ref.  This is
123
  /// equivalent to calling getUnderlyingStream().slice(Offset).  Updates the
124
  /// stream's offset to point to the end of the stream.  Never causes a copy.
125
  ///
126
  /// \returns a success error code if the data was successfully read, otherwise
127
  /// returns an appropriate error code.
128
  Error readStreamRef(BinaryStreamRef &Ref);
129
130
  /// Read \p Length bytes from the underlying stream into \p Ref.  This is
131
  /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
132
  /// Updates the stream's offset to point after the newly read object.  Never
133
  /// causes a copy.
134
  ///
135
  /// \returns a success error code if the data was successfully read, otherwise
136
  /// returns an appropriate error code.
137
  Error readStreamRef(BinaryStreamRef &Ref, uint32_t Length);
138
139
  /// Read \p Length bytes from the underlying stream into \p Stream.  This is
140
  /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
141
  /// Updates the stream's offset to point after the newly read object.  Never
142
  /// causes a copy.
143
  ///
144
  /// \returns a success error code if the data was successfully read, otherwise
145
  /// returns an appropriate error code.
146
  Error readSubstream(BinarySubstreamRef &Stream, uint32_t Size);
147
148
  /// Get a pointer to an object of type T from the underlying stream, as if by
149
  /// memcpy, and store the result into \p Dest.  It is up to the caller to
150
  /// ensure that objects of type T can be safely treated in this manner.
151
  /// Updates the stream's offset to point after the newly read object.  Whether
152
  /// a copy occurs depends upon the implementation of the underlying
153
  /// stream.
154
  ///
155
  /// \returns a success error code if the data was successfully read, otherwise
156
  /// returns an appropriate error code.
157
20.7k
  template <typename T> Error readObject(const T *&Dest) {
158
20.7k
    ArrayRef<uint8_t> Buffer;
159
20.7k
    if (auto EC = readBytes(Buffer, sizeof(T)))
160
88
      return EC;
161
20.6k
    Dest = reinterpret_cast<const T *>(Buffer.data());
162
20.6k
    return Error::success();
163
20.6k
  }
llvm::Error llvm::BinaryStreamReader::readObject<unsigned short>(unsigned short const*&)
Line
Count
Source
157
1.35k
  template <typename T> Error readObject(const T *&Dest) {
158
1.35k
    ArrayRef<uint8_t> Buffer;
159
1.35k
    if (auto EC = readBytes(Buffer, sizeof(T)))
160
0
      return EC;
161
1.35k
    Dest = reinterpret_cast<const T *>(Buffer.data());
162
1.35k
    return Error::success();
163
1.35k
  }
llvm::Error llvm::BinaryStreamReader::readObject<llvm::object::coff_resource_dir_table>(llvm::object::coff_resource_dir_table const*&)
Line
Count
Source
157
131
  template <typename T> Error readObject(const T *&Dest) {
158
131
    ArrayRef<uint8_t> Buffer;
159
131
    if (auto EC = readBytes(Buffer, sizeof(T)))
160
0
      return EC;
161
131
    Dest = reinterpret_cast<const T *>(Buffer.data());
162
131
    return Error::success();
163
131
  }
llvm::Error llvm::BinaryStreamReader::readObject<llvm::object::WinResHeaderPrefix>(llvm::object::WinResHeaderPrefix const*&)
Line
Count
Source
157
321
  template <typename T> Error readObject(const T *&Dest) {
158
321
    ArrayRef<uint8_t> Buffer;
159
321
    if (auto EC = readBytes(Buffer, sizeof(T)))
160
0
      return EC;
161
321
    Dest = reinterpret_cast<const T *>(Buffer.data());
162
321
    return Error::success();
163
321
  }
llvm::Error llvm::BinaryStreamReader::readObject<llvm::object::WinResHeaderSuffix>(llvm::object::WinResHeaderSuffix const*&)
Line
Count
Source
157
321
  template <typename T> Error readObject(const T *&Dest) {
158
321
    ArrayRef<uint8_t> Buffer;
159
321
    if (auto EC = readBytes(Buffer, sizeof(T)))
160
0
      return EC;
161
321
    Dest = reinterpret_cast<const T *>(Buffer.data());
162
321
    return Error::success();
163
321
  }
llvm::Error llvm::BinaryStreamReader::readObject<llvm::codeview::RecordPrefix>(llvm::codeview::RecordPrefix const*&)
Line
Count
Source
157
18.0k
  template <typename T> Error readObject(const T *&Dest) {
158
18.0k
    ArrayRef<uint8_t> Buffer;
159
18.0k
    if (auto EC = readBytes(Buffer, sizeof(T)))
160
88
      return EC;
161
17.9k
    Dest = reinterpret_cast<const T *>(Buffer.data());
162
17.9k
    return Error::success();
163
17.9k
  }
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
157
128
  template <typename T> Error readObject(const T *&Dest) {
158
128
    ArrayRef<uint8_t> Buffer;
159
128
    if (auto EC = readBytes(Buffer, sizeof(T)))
160
0
      return EC;
161
128
    Dest = reinterpret_cast<const T *>(Buffer.data());
162
128
    return Error::success();
163
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
157
12
  template <typename T> Error readObject(const T *&Dest) {
158
12
    ArrayRef<uint8_t> Buffer;
159
12
    if (auto EC = readBytes(Buffer, sizeof(T)))
160
0
      return EC;
161
12
    Dest = reinterpret_cast<const T *>(Buffer.data());
162
12
    return Error::success();
163
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
157
489
  template <typename T> Error readObject(const T *&Dest) {
158
489
    ArrayRef<uint8_t> Buffer;
159
489
    if (auto EC = readBytes(Buffer, sizeof(T)))
160
0
      return EC;
161
489
    Dest = reinterpret_cast<const T *>(Buffer.data());
162
489
    return Error::success();
163
489
  }
164
165
  /// Get a reference to a \p NumElements element array of objects of type T
166
  /// from the underlying stream as if by memcpy, and store the resulting array
167
  /// slice into \p array.  It is up to the caller to ensure that objects of
168
  /// type T can be safely treated in this manner.  Updates the stream's offset
169
  /// to point after the newly read object.  Whether a copy occurs depends upon
170
  /// the implementation of the underlying stream.
171
  ///
172
  /// \returns a success error code if the data was successfully read, otherwise
173
  /// returns an appropriate error code.
174
  template <typename T>
175
550
  Error readArray(ArrayRef<T> &Array, uint32_t NumElements) {
176
550
    ArrayRef<uint8_t> Bytes;
177
550
    if (NumElements == 0) {
178
1
      Array = ArrayRef<T>();
179
1
      return Error::success();
180
1
    }
181
549
182
549
    if (NumElements > UINT32_MAX / sizeof(T))
183
0
      return make_error<BinaryStreamError>(
184
0
          stream_error_code::invalid_array_size);
185
549
186
549
    if (auto EC = readBytes(Bytes, NumElements * sizeof(T)))
187
0
      return EC;
188
549
189
549
    assert(alignmentAdjustment(Bytes.data(), alignof(T)) == 0 &&
190
549
           "Reading at invalid alignment!");
191
549
192
549
    Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements);
193
549
    return Error::success();
194
549
  }
llvm::Error llvm::BinaryStreamReader::readArray<unsigned short>(llvm::ArrayRef<unsigned short>&, unsigned int)
Line
Count
Source
175
171
  Error readArray(ArrayRef<T> &Array, uint32_t NumElements) {
176
171
    ArrayRef<uint8_t> Bytes;
177
171
    if (NumElements == 0) {
178
0
      Array = ArrayRef<T>();
179
0
      return Error::success();
180
0
    }
181
171
182
171
    if (NumElements > UINT32_MAX / sizeof(T))
183
0
      return make_error<BinaryStreamError>(
184
0
          stream_error_code::invalid_array_size);
185
171
186
171
    if (auto EC = readBytes(Bytes, NumElements * sizeof(T)))
187
0
      return EC;
188
171
189
171
    assert(alignmentAdjustment(Bytes.data(), alignof(T)) == 0 &&
190
171
           "Reading at invalid alignment!");
191
171
192
171
    Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements);
193
171
    return Error::success();
194
171
  }
llvm::Error llvm::BinaryStreamReader::readArray<unsigned char>(llvm::ArrayRef<unsigned char>&, unsigned int)
Line
Count
Source
175
379
  Error readArray(ArrayRef<T> &Array, uint32_t NumElements) {
176
379
    ArrayRef<uint8_t> Bytes;
177
379
    if (NumElements == 0) {
178
1
      Array = ArrayRef<T>();
179
1
      return Error::success();
180
1
    }
181
378
182
378
    if (NumElements > UINT32_MAX / sizeof(T))
183
0
      return make_error<BinaryStreamError>(
184
0
          stream_error_code::invalid_array_size);
185
378
186
378
    if (auto EC = readBytes(Bytes, NumElements * sizeof(T)))
187
0
      return EC;
188
378
189
378
    assert(alignmentAdjustment(Bytes.data(), alignof(T)) == 0 &&
190
378
           "Reading at invalid alignment!");
191
378
192
378
    Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements);
193
378
    return Error::success();
194
378
  }
195
196
  /// Read a VarStreamArray of size \p Size bytes and store the result into
197
  /// \p Array.  Updates the stream's offset to point after the newly read
198
  /// array.  Never causes a copy (although iterating the elements of the
199
  /// VarStreamArray may, depending upon the implementation of the underlying
200
  /// stream).
201
  ///
202
  /// \returns a success error code if the data was successfully read, otherwise
203
  /// returns an appropriate error code.
204
  template <typename T, typename U>
205
  Error readArray(VarStreamArray<T, U> &Array, uint32_t Size,
206
                  uint32_t Skew = 0) {
207
    BinaryStreamRef S;
208
    if (auto EC = readStreamRef(S, Size))
209
      return EC;
210
    Array.setUnderlyingStream(S, Skew);
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
422
  Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) {
224
422
    if (NumItems == 0) {
225
0
      Array = FixedStreamArray<T>();
226
0
      return Error::success();
227
0
    }
228
422
229
422
    if (NumItems > UINT32_MAX / sizeof(T))
230
0
      return make_error<BinaryStreamError>(
231
0
          stream_error_code::invalid_array_size);
232
422
233
422
    BinaryStreamRef View;
234
422
    if (auto EC = readStreamRef(View, NumItems * sizeof(T)))
235
0
      return EC;
236
422
237
422
    Array = FixedStreamArray<T>(View);
238
422
    return Error::success();
239
422
  }
240
241
13.5k
  bool empty() const { return bytesRemaining() == 0; }
242
111k
  void setOffset(uint32_t Off) { Offset = Off; }
243
178k
  uint32_t getOffset() const { return Offset; }
244
52.2k
  uint32_t getLength() const { return Stream.getLength(); }
245
51.6k
  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