V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
decoder.h
1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_WASM_DECODER_H_
6 #define V8_WASM_DECODER_H_
7 
8 #include <cstdarg>
9 #include <memory>
10 
11 #include "src/base/compiler-specific.h"
12 #include "src/flags.h"
13 #include "src/signature.h"
14 #include "src/v8memory.h"
15 #include "src/wasm/wasm-result.h"
16 #include "src/zone/zone-containers.h"
17 
18 namespace v8 {
19 namespace internal {
20 namespace wasm {
21 
22 #define TRACE(...) \
23  do { \
24  if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
25  } while (false)
26 #define TRACE_IF(cond, ...) \
27  do { \
28  if (FLAG_trace_wasm_decoder && (cond)) PrintF(__VA_ARGS__); \
29  } while (false)
30 
31 // A {DecodeResult} only stores the failure / success status, but no data.
32 using DecodeResult = VoidResult;
33 
34 // A helper utility to decode bytes, integers, fields, varints, etc, from
35 // a buffer of bytes.
36 class Decoder {
37  public:
38  enum ValidateFlag : bool { kValidate = true, kNoValidate = false };
39 
40  enum AdvancePCFlag : bool { kAdvancePc = true, kNoAdvancePc = false };
41 
42  enum TraceFlag : bool { kTrace = true, kNoTrace = false };
43 
44  Decoder(const byte* start, const byte* end, uint32_t buffer_offset = 0)
45  : Decoder(start, start, end, buffer_offset) {}
46  explicit Decoder(const Vector<const byte> bytes, uint32_t buffer_offset = 0)
47  : Decoder(bytes.start(), bytes.start() + bytes.length(), buffer_offset) {}
48  Decoder(const byte* start, const byte* pc, const byte* end,
49  uint32_t buffer_offset = 0)
50  : start_(start), pc_(pc), end_(end), buffer_offset_(buffer_offset) {
51  DCHECK_LE(start, pc);
52  DCHECK_LE(pc, end);
53  DCHECK_EQ(static_cast<uint32_t>(end - start), end - start);
54  }
55 
56  virtual ~Decoder() = default;
57 
58  inline bool validate_size(const byte* pc, uint32_t length, const char* msg) {
59  DCHECK_LE(start_, pc);
60  DCHECK_LE(pc, end_);
61  if (V8_UNLIKELY(length > static_cast<uint32_t>(end_ - pc))) {
62  error(pc, msg);
63  return false;
64  }
65  return true;
66  }
67 
68  // Reads an 8-bit unsigned integer.
69  template <ValidateFlag validate>
70  inline uint8_t read_u8(const byte* pc, const char* msg = "expected 1 byte") {
71  return read_little_endian<uint8_t, validate>(pc, msg);
72  }
73 
74  // Reads a 16-bit unsigned integer (little endian).
75  template <ValidateFlag validate>
76  inline uint16_t read_u16(const byte* pc,
77  const char* msg = "expected 2 bytes") {
78  return read_little_endian<uint16_t, validate>(pc, msg);
79  }
80 
81  // Reads a 32-bit unsigned integer (little endian).
82  template <ValidateFlag validate>
83  inline uint32_t read_u32(const byte* pc,
84  const char* msg = "expected 4 bytes") {
85  return read_little_endian<uint32_t, validate>(pc, msg);
86  }
87 
88  // Reads a 64-bit unsigned integer (little endian).
89  template <ValidateFlag validate>
90  inline uint64_t read_u64(const byte* pc,
91  const char* msg = "expected 8 bytes") {
92  return read_little_endian<uint64_t, validate>(pc, msg);
93  }
94 
95  // Reads a variable-length unsigned integer (little endian).
96  template <ValidateFlag validate>
97  uint32_t read_u32v(const byte* pc, uint32_t* length,
98  const char* name = "LEB32") {
99  return read_leb<uint32_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
100  name);
101  }
102 
103  // Reads a variable-length signed integer (little endian).
104  template <ValidateFlag validate>
105  int32_t read_i32v(const byte* pc, uint32_t* length,
106  const char* name = "signed LEB32") {
107  return read_leb<int32_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
108  name);
109  }
110 
111  // Reads a variable-length unsigned integer (little endian).
112  template <ValidateFlag validate>
113  uint64_t read_u64v(const byte* pc, uint32_t* length,
114  const char* name = "LEB64") {
115  return read_leb<uint64_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
116  name);
117  }
118 
119  // Reads a variable-length signed integer (little endian).
120  template <ValidateFlag validate>
121  int64_t read_i64v(const byte* pc, uint32_t* length,
122  const char* name = "signed LEB64") {
123  return read_leb<int64_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
124  name);
125  }
126 
127  // Reads a 8-bit unsigned integer (byte) and advances {pc_}.
128  uint8_t consume_u8(const char* name = "uint8_t") {
129  return consume_little_endian<uint8_t>(name);
130  }
131 
132  // Reads a 16-bit unsigned integer (little endian) and advances {pc_}.
133  uint16_t consume_u16(const char* name = "uint16_t") {
134  return consume_little_endian<uint16_t>(name);
135  }
136 
137  // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}.
138  uint32_t consume_u32(const char* name = "uint32_t") {
139  return consume_little_endian<uint32_t>(name);
140  }
141 
142  // Reads a LEB128 variable-length unsigned 32-bit integer and advances {pc_}.
143  uint32_t consume_u32v(const char* name = nullptr) {
144  uint32_t length = 0;
145  return read_leb<uint32_t, kValidate, kAdvancePc, kTrace>(pc_, &length,
146  name);
147  }
148 
149  // Reads a LEB128 variable-length signed 32-bit integer and advances {pc_}.
150  int32_t consume_i32v(const char* name = nullptr) {
151  uint32_t length = 0;
152  return read_leb<int32_t, kValidate, kAdvancePc, kTrace>(pc_, &length, name);
153  }
154 
155  // Consume {size} bytes and send them to the bit bucket, advancing {pc_}.
156  void consume_bytes(uint32_t size, const char* name = "skip") {
157  // Only trace if the name is not null.
158  TRACE_IF(name, " +%u %-20s: %u bytes\n", pc_offset(), name, size);
159  if (checkAvailable(size)) {
160  pc_ += size;
161  } else {
162  pc_ = end_;
163  }
164  }
165 
166  // Check that at least {size} bytes exist between {pc_} and {end_}.
167  bool checkAvailable(uint32_t size) {
168  DCHECK_LE(pc_, end_);
169  if (V8_UNLIKELY(size > static_cast<uint32_t>(end_ - pc_))) {
170  errorf(pc_, "expected %u bytes, fell off end", size);
171  return false;
172  }
173  return true;
174  }
175 
176  void error(const char* msg) { errorf(pc_, "%s", msg); }
177 
178  void error(const byte* pc, const char* msg) { errorf(pc, "%s", msg); }
179 
180  // Sets internal error state.
181  void PRINTF_FORMAT(3, 4) errorf(const byte* pc, const char* format, ...) {
182  // Only report the first error.
183  if (!ok()) return;
184 #if DEBUG
185  if (FLAG_wasm_break_on_decoder_error) {
186  base::OS::DebugBreak();
187  }
188 #endif
189  constexpr int kMaxErrorMsg = 256;
191  va_list arguments;
192  va_start(arguments, format);
193  int len = VSNPrintF(buffer, format, arguments);
194  CHECK_LT(0, len);
195  va_end(arguments);
196  error_msg_.assign(buffer.start(), len);
197  DCHECK_GE(pc, start_);
198  error_offset_ = static_cast<uint32_t>(pc - start_) + buffer_offset_;
199  onFirstError();
200  }
201 
202  // Behavior triggered on first error, overridden in subclasses.
203  virtual void onFirstError() {}
204 
205  // Debugging helper to print a bytes range as hex bytes.
206  void traceByteRange(const byte* start, const byte* end) {
207  DCHECK_LE(start, end);
208  for (const byte* p = start; p < end; ++p) TRACE("%02x ", *p);
209  }
210 
211  // Debugging helper to print bytes up to the end.
212  void traceOffEnd() {
213  traceByteRange(pc_, end_);
214  TRACE("<end>\n");
215  }
216 
217  // Converts the given value to a {Result}, copying the error if necessary.
218  template <typename T, typename U = typename std::remove_reference<T>::type>
219  Result<U> toResult(T&& val) {
220  if (failed()) {
221  TRACE("Result error: %s\n", error_msg_.c_str());
222  return Result<U>::Error(error_offset_, std::move(error_msg_));
223  }
224  return Result<U>(std::forward<T>(val));
225  }
226 
227  // Resets the boundaries of this decoder.
228  void Reset(const byte* start, const byte* end, uint32_t buffer_offset = 0) {
229  DCHECK_LE(start, end);
230  DCHECK_EQ(static_cast<uint32_t>(end - start), end - start);
231  start_ = start;
232  pc_ = start;
233  end_ = end;
234  buffer_offset_ = buffer_offset;
235  error_offset_ = 0;
236  error_msg_.clear();
237  }
238 
239  void Reset(Vector<const uint8_t> bytes, uint32_t buffer_offset = 0) {
240  Reset(bytes.begin(), bytes.end(), buffer_offset);
241  }
242 
243  bool ok() const { return error_msg_.empty(); }
244  bool failed() const { return !ok(); }
245  bool more() const { return pc_ < end_; }
246 
247  const byte* start() const { return start_; }
248  const byte* pc() const { return pc_; }
249  uint32_t position() const { return static_cast<uint32_t>(pc_ - start_); }
250  uint32_t pc_offset() const {
251  return static_cast<uint32_t>(pc_ - start_) + buffer_offset_;
252  }
253  uint32_t buffer_offset() const { return buffer_offset_; }
254  // Takes an offset relative to the module start and returns an offset relative
255  // to the current buffer of the decoder.
256  uint32_t GetBufferRelativeOffset(uint32_t offset) const {
257  DCHECK_LE(buffer_offset_, offset);
258  return offset - buffer_offset_;
259  }
260  const byte* end() const { return end_; }
261 
262  protected:
263  const byte* start_;
264  const byte* pc_;
265  const byte* end_;
266  // The offset of the current buffer in the module. Needed for streaming.
267  uint32_t buffer_offset_;
268  uint32_t error_offset_ = 0;
269  std::string error_msg_;
270 
271  private:
272  template <typename IntType, bool validate>
273  inline IntType read_little_endian(const byte* pc, const char* msg) {
274  if (!validate) {
275  DCHECK(validate_size(pc, sizeof(IntType), msg));
276  } else if (!validate_size(pc, sizeof(IntType), msg)) {
277  return IntType{0};
278  }
279  return ReadLittleEndianValue<IntType>(reinterpret_cast<Address>(pc));
280  }
281 
282  template <typename IntType>
283  inline IntType consume_little_endian(const char* name) {
284  TRACE(" +%u %-20s: ", pc_offset(), name);
285  if (!checkAvailable(sizeof(IntType))) {
286  traceOffEnd();
287  pc_ = end_;
288  return IntType{0};
289  }
290  IntType val = read_little_endian<IntType, false>(pc_, name);
291  traceByteRange(pc_, pc_ + sizeof(IntType));
292  TRACE("= %d\n", val);
293  pc_ += sizeof(IntType);
294  return val;
295  }
296 
297  template <typename IntType, ValidateFlag validate, AdvancePCFlag advance_pc,
298  TraceFlag trace>
299  inline IntType read_leb(const byte* pc, uint32_t* length,
300  const char* name = "varint") {
301  DCHECK_IMPLIES(advance_pc, pc == pc_);
302  TRACE_IF(trace, " +%u %-20s: ", pc_offset(), name);
303  return read_leb_tail<IntType, validate, advance_pc, trace, 0>(pc, length,
304  name, 0);
305  }
306 
307  template <typename IntType, ValidateFlag validate, AdvancePCFlag advance_pc,
308  TraceFlag trace, int byte_index>
309  IntType read_leb_tail(const byte* pc, uint32_t* length, const char* name,
310  IntType result) {
311  constexpr bool is_signed = std::is_signed<IntType>::value;
312  constexpr int kMaxLength = (sizeof(IntType) * 8 + 6) / 7;
313  static_assert(byte_index < kMaxLength, "invalid template instantiation");
314  constexpr int shift = byte_index * 7;
315  constexpr bool is_last_byte = byte_index == kMaxLength - 1;
316  DCHECK_LE(pc, end_);
317  const bool at_end = validate && pc == end_;
318  byte b = 0;
319  if (!at_end) {
320  DCHECK_LT(pc, end_);
321  b = *pc;
322  TRACE_IF(trace, "%02x ", b);
323  result = result | ((static_cast<IntType>(b) & 0x7f) << shift);
324  }
325  if (!is_last_byte && (b & 0x80)) {
326  // Make sure that we only instantiate the template for valid byte indexes.
327  // Compilers are not smart enough to figure out statically that the
328  // following call is unreachable if is_last_byte is false.
329  constexpr int next_byte_index = byte_index + (is_last_byte ? 0 : 1);
330  return read_leb_tail<IntType, validate, advance_pc, trace,
331  next_byte_index>(pc + 1, length, name, result);
332  }
333  if (advance_pc) pc_ = pc + (at_end ? 0 : 1);
334  *length = byte_index + (at_end ? 0 : 1);
335  if (validate && (at_end || (b & 0x80))) {
336  TRACE_IF(trace, at_end ? "<end> " : "<length overflow> ");
337  errorf(pc, "expected %s", name);
338  result = 0;
339  }
340  if (is_last_byte) {
341  // A signed-LEB128 must sign-extend the final byte, excluding its
342  // most-significant bit; e.g. for a 32-bit LEB128:
343  // kExtraBits = 4 (== 32 - (5-1) * 7)
344  // For unsigned values, the extra bits must be all zero.
345  // For signed values, the extra bits *plus* the most significant bit must
346  // either be 0, or all ones.
347  constexpr int kExtraBits = (sizeof(IntType) * 8) - ((kMaxLength - 1) * 7);
348  constexpr int kSignExtBits = kExtraBits - (is_signed ? 1 : 0);
349  const byte checked_bits = b & (0xFF << kSignExtBits);
350  constexpr byte kSignExtendedExtraBits = 0x7f & (0xFF << kSignExtBits);
351  bool valid_extra_bits =
352  checked_bits == 0 ||
353  (is_signed && checked_bits == kSignExtendedExtraBits);
354  if (!validate) {
355  DCHECK(valid_extra_bits);
356  } else if (!valid_extra_bits) {
357  error(pc, "extra bits in varint");
358  result = 0;
359  }
360  }
361  constexpr int sign_ext_shift =
362  is_signed ? Max(0, int{8 * sizeof(IntType)} - shift - 7) : 0;
363  // Perform sign extension.
364  result = (result << sign_ext_shift) >> sign_ext_shift;
365  if (trace && is_signed) {
366  TRACE("= %" PRIi64 "\n", static_cast<int64_t>(result));
367  } else if (trace) {
368  TRACE("= %" PRIu64 "\n", static_cast<uint64_t>(result));
369  }
370  return result;
371  }
372 };
373 
374 #undef TRACE
375 } // namespace wasm
376 } // namespace internal
377 } // namespace v8
378 
379 #endif // V8_WASM_DECODER_H_
Definition: libplatform.h:13