decoder.h 13.5 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_WASM_DECODER_H_
#define V8_WASM_DECODER_H_

8
#include <cstdarg>
9 10
#include <memory>

jfb's avatar
jfb committed
11
#include "src/base/compiler-specific.h"
12 13
#include "src/flags.h"
#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 19 20 21 22 23 24 25

namespace v8 {
namespace internal {
namespace wasm {

#define TRACE(...)                                    \
  do {                                                \
    if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
  } while (false)
26 27 28 29
#define TRACE_IF(cond, ...)                                     \
  do {                                                          \
    if (FLAG_trace_wasm_decoder && (cond)) PrintF(__VA_ARGS__); \
  } while (false)
30

31 32
// A {DecodeResult} only stores the failure / success status, but no data.
using DecodeResult = VoidResult;
33

34 35 36 37
// A helper utility to decode bytes, integers, fields, varints, etc, from
// a buffer of bytes.
class Decoder {
 public:
38 39 40 41 42 43
  enum ValidateFlag : bool { kValidate = true, kNoValidate = false };

  enum AdvancePCFlag : bool { kAdvancePc = true, kNoAdvancePc = false };

  enum TraceFlag : bool { kTrace = true, kNoTrace = false };

44
  Decoder(const byte* start, const byte* end, uint32_t buffer_offset = 0)
45
      : Decoder(start, start, end, buffer_offset) {}
46 47
  explicit Decoder(const Vector<const byte> bytes, uint32_t buffer_offset = 0)
      : Decoder(bytes.start(), bytes.start() + bytes.length(), buffer_offset) {}
48 49
  Decoder(const byte* start, const byte* pc, const byte* end,
          uint32_t buffer_offset = 0)
50 51 52 53 54
      : start_(start), pc_(pc), end_(end), buffer_offset_(buffer_offset) {
    DCHECK_LE(start, pc);
    DCHECK_LE(pc, end);
    DCHECK_EQ(static_cast<uint32_t>(end - start), end - start);
  }
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 64 65 66 67
      return false;
    }
    return true;
  }

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 77
  inline uint16_t read_u16(const byte* pc,
                           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 84
  inline uint32_t read_u32(const byte* pc,
                           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 91
  inline uint64_t read_u64(const byte* pc,
                           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 100
    return read_leb<uint32_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
                                                                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 108
    return read_leb<int32_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
                                                               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 116
    return read_leb<uint64_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
                                                                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 124
    return read_leb<int64_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
                                                               name);
125 126
  }

127
  // Reads a 8-bit unsigned integer (byte) and advances {pc_}.
128 129
  uint8_t consume_u8(const char* name = "uint8_t") {
    return consume_little_endian<uint8_t>(name);
130 131 132
  }

  // Reads a 16-bit unsigned integer (little endian) and advances {pc_}.
133 134
  uint16_t consume_u16(const char* name = "uint16_t") {
    return consume_little_endian<uint16_t>(name);
135 136 137
  }

  // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}.
138 139
  uint32_t consume_u32(const char* name = "uint32_t") {
    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 146
    return read_leb<uint32_t, kValidate, kAdvancePc, kTrace>(pc_, &length,
                                                             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 156
  }

  // Consume {size} bytes and send them to the bit bucket, advancing {pc_}.
  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 160 161
    if (checkAvailable(size)) {
      pc_ += size;
    } 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 172
      return false;
    }
173
    return true;
174 175
  }

176 177 178 179 180 181
  void error(const char* msg) { errorf(pc_, "%s", msg); }

  void error(const byte* pc, const char* msg) { errorf(pc, "%s", msg); }

  // Sets internal error state.
  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 186
    if (FLAG_wasm_break_on_decoder_error) {
      base::OS::DebugBreak();
187
    }
188
#endif
189 190 191 192 193 194 195 196 197 198 199
    constexpr int kMaxErrorMsg = 256;
    EmbeddedVector<char, kMaxErrorMsg> buffer;
    va_list arguments;
    va_start(arguments, format);
    int len = VSNPrintF(buffer, format, arguments);
    CHECK_LT(0, len);
    va_end(arguments);
    error_msg_.assign(buffer.start(), len);
    DCHECK_GE(pc, start_);
    error_offset_ = static_cast<uint32_t>(pc - start_) + buffer_offset_;
    onFirstError();
200 201 202 203 204
  }

  // Behavior triggered on first error, overridden in subclasses.
  virtual void onFirstError() {}

205 206 207 208 209 210
  // Debugging helper to print a bytes range as hex bytes.
  void traceByteRange(const byte* start, const byte* end) {
    DCHECK_LE(start, end);
    for (const byte* p = start; p < end; ++p) TRACE("%02x ", *p);
  }

211
  // Debugging helper to print bytes up to the end.
212 213
  void traceOffEnd() {
    traceByteRange(pc_, end_);
214 215 216 217
    TRACE("<end>\n");
  }

  // Converts the given value to a {Result}, copying the error if necessary.
218 219
  template <typename T, typename U = typename std::remove_reference<T>::type>
  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 230
    DCHECK_LE(start, end);
    DCHECK_EQ(static_cast<uint32_t>(end - start), end - start);
231 232
    start_ = start;
    pc_ = start;
233
    end_ = end;
234
    buffer_offset_ = buffer_offset;
235
    error_offset_ = 0;
236
    error_msg_.clear();
237 238
  }

239 240 241 242
  void Reset(Vector<const uint8_t> bytes, uint32_t buffer_offset = 0) {
    Reset(bytes.begin(), bytes.end(), buffer_offset);
  }

243
  bool ok() const { return error_msg_.empty(); }
244
  bool failed() const { return !ok(); }
245
  bool more() const { return pc_ < end_; }
246

247 248
  const byte* start() const { return start_; }
  const byte* pc() const { return pc_; }
249
  uint32_t position() const { return static_cast<uint32_t>(pc_ - start_); }
250 251
  uint32_t pc_offset() const {
    return static_cast<uint32_t>(pc_ - start_) + buffer_offset_;
252 253 254 255 256 257 258 259
  }
  uint32_t buffer_offset() const { return buffer_offset_; }
  // Takes an offset relative to the module start and returns an offset relative
  // to the current buffer of the decoder.
  uint32_t GetBufferRelativeOffset(uint32_t offset) const {
    DCHECK_LE(buffer_offset_, offset);
    return offset - buffer_offset_;
  }
260
  const byte* end() const { return end_; }
261

262 263 264
 protected:
  const byte* start_;
  const byte* pc_;
265
  const byte* end_;
266 267 268
  // The offset of the current buffer in the module. Needed for streaming.
  uint32_t buffer_offset_;
  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 275 276
    if (!validate) {
      DCHECK(validate_size(pc, sizeof(IntType), msg));
    } else if (!validate_size(pc, sizeof(IntType), msg)) {
277 278
      return IntType{0};
    }
279
    return ReadLittleEndianValue<IntType>(reinterpret_cast<Address>(pc));
280 281 282 283
  }

  template <typename IntType>
  inline IntType consume_little_endian(const char* name) {
284
    TRACE("  +%u  %-20s: ", pc_offset(), name);
285 286 287 288 289 290 291 292 293 294 295 296
    if (!checkAvailable(sizeof(IntType))) {
      traceOffEnd();
      pc_ = end_;
      return IntType{0};
    }
    IntType val = read_little_endian<IntType, false>(pc_, name);
    traceByteRange(pc_, pc_ + sizeof(IntType));
    TRACE("= %d\n", val);
    pc_ += sizeof(IntType);
    return val;
  }

297 298
  template <typename IntType, ValidateFlag validate, AdvancePCFlag advance_pc,
            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 304
    return read_leb_tail<IntType, validate, advance_pc, trace, 0>(pc, length,
                                                                  name, 0);
305 306
  }

307 308
  template <typename IntType, ValidateFlag validate, AdvancePCFlag advance_pc,
            TraceFlag trace, int byte_index>
309 310 311
  IntType read_leb_tail(const byte* pc, uint32_t* length, const char* name,
                        IntType result) {
    constexpr bool is_signed = std::is_signed<IntType>::value;
312
    constexpr int kMaxLength = (sizeof(IntType) * 8 + 6) / 7;
313 314 315
    static_assert(byte_index < kMaxLength, "invalid template instantiation");
    constexpr int shift = byte_index * 7;
    constexpr bool is_last_byte = byte_index == kMaxLength - 1;
316 317
    DCHECK_LE(pc, end_);
    const bool at_end = validate && pc == end_;
318
    byte b = 0;
319
    if (!at_end) {
Clemens Hammacher's avatar
Clemens Hammacher committed
320
      DCHECK_LT(pc, end_);
321
      b = *pc;
322
      TRACE_IF(trace, "%02x ", b);
323 324 325 326 327 328 329
      result = result | ((static_cast<IntType>(b) & 0x7f) << shift);
    }
    if (!is_last_byte && (b & 0x80)) {
      // Make sure that we only instantiate the template for valid byte indexes.
      // Compilers are not smart enough to figure out statically that the
      // following call is unreachable if is_last_byte is false.
      constexpr int next_byte_index = byte_index + (is_last_byte ? 0 : 1);
330
      return read_leb_tail<IntType, validate, advance_pc, trace,
331 332 333 334
                           next_byte_index>(pc + 1, length, name, result);
    }
    if (advance_pc) pc_ = pc + (at_end ? 0 : 1);
    *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 339 340
      result = 0;
    }
    if (is_last_byte) {
341 342 343 344 345 346 347 348 349 350
      // A signed-LEB128 must sign-extend the final byte, excluding its
      // most-significant bit; e.g. for a 32-bit LEB128:
      //   kExtraBits = 4  (== 32 - (5-1) * 7)
      // For unsigned values, the extra bits must be all zero.
      // For signed values, the extra bits *plus* the most significant bit must
      // either be 0, or all ones.
      constexpr int kExtraBits = (sizeof(IntType) * 8) - ((kMaxLength - 1) * 7);
      constexpr int kSignExtBits = kExtraBits - (is_signed ? 1 : 0);
      const byte checked_bits = b & (0xFF << kSignExtBits);
      constexpr byte kSignExtendedExtraBits = 0x7f & (0xFF << kSignExtBits);
351 352 353
      bool valid_extra_bits =
          checked_bits == 0 ||
          (is_signed && checked_bits == kSignExtendedExtraBits);
354
      if (!validate) {
355 356
        DCHECK(valid_extra_bits);
      } 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 364
    // Perform sign extension.
    result = (result << sign_ext_shift) >> sign_ext_shift;
365 366 367 368
    if (trace && is_signed) {
      TRACE("= %" PRIi64 "\n", static_cast<int64_t>(result));
    } else if (trace) {
      TRACE("= %" PRIu64 "\n", static_cast<uint64_t>(result));
369
    }
370
    return result;
371
  }
372 373 374 375 376 377 378 379
};

#undef TRACE
}  // namespace wasm
}  // namespace internal
}  // namespace v8

#endif  // V8_WASM_DECODER_H_