LCOV - code coverage report
Current view: top level - src/wasm - decoder.h (source / functions) Hit Total Coverage
Test: app.info Lines: 86 86 100.0 %
Date: 2019-02-19 Functions: 116 123 94.3 %

          Line data    Source code
       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        3101 :       : 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    11482396 :       : 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    11482382 :   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     1751475 :     if (V8_UNLIKELY(length > static_cast<uint32_t>(end_ - pc))) {
      62          24 :       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      830080 :     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      675223 :     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      246183 :     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     5346266 :     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      566309 :     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     7804096 :     uint32_t length = 0;
     145             :     return read_leb<uint32_t, kValidate, kAdvancePc, kTrace>(pc_, &length,
     146     4035811 :                                                              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         691 :     uint32_t length = 0;
     152         691 :     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     3180368 :   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     3180368 :     if (checkAvailable(size)) {
     160     3179051 :       pc_ += size;
     161             :     } else {
     162        1326 :       pc_ = end_;
     163             :     }
     164     3180377 :   }
     165             : 
     166             :   // Check that at least {size} bytes exist between {pc_} and {end_}.
     167    10570539 :   bool checkAvailable(uint32_t size) {
     168             :     DCHECK_LE(pc_, end_);
     169    10570539 :     if (V8_UNLIKELY(size > static_cast<uint32_t>(end_ - pc_))) {
     170      126510 :       errorf(pc_, "expected %u bytes, fell off end", size);
     171      126510 :       return false;
     172             :     }
     173             :     return true;
     174             :   }
     175             : 
     176             :   // Do not inline error methods. This has measurable impact on validation time,
     177             :   // see https://crbug.com/910432.
     178       94970 :   void V8_NOINLINE error(const char* msg) { errorf(pc_offset(), "%s", msg); }
     179        9494 :   void V8_NOINLINE error(const uint8_t* pc, const char* msg) {
     180        9494 :     errorf(pc_offset(pc), "%s", msg);
     181        9494 :   }
     182             :   void V8_NOINLINE error(uint32_t offset, const char* msg) {
     183             :     errorf(offset, "%s", msg);
     184             :   }
     185             : 
     186             :   void V8_NOINLINE PRINTF_FORMAT(3, 4)
     187       74247 :       errorf(uint32_t offset, const char* format, ...) {
     188             :     va_list args;
     189       74247 :     va_start(args, format);
     190       74247 :     verrorf(offset, format, args);
     191       74253 :     va_end(args);
     192       74253 :   }
     193             : 
     194             :   void V8_NOINLINE PRINTF_FORMAT(3, 4)
     195      683958 :       errorf(const uint8_t* pc, const char* format, ...) {
     196             :     va_list args;
     197      341979 :     va_start(args, format);
     198      341979 :     verrorf(pc_offset(pc), format, args);
     199      341978 :     va_end(args);
     200      341978 :   }
     201             : 
     202             :   // Behavior triggered on first error, overridden in subclasses.
     203      131926 :   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      944421 :   Result<U> toResult(T&& val) {
     220      944421 :     if (failed()) {
     221             :       TRACE("Result error: %s\n", error_.message().c_str());
     222       68820 :       return Result<U>{error_};
     223             :     }
     224      263773 :     return Result<U>{std::forward<T>(val)};
     225             :   }
     226             : 
     227             :   // Resets the boundaries of this decoder.
     228     2149654 :   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     2149654 :     start_ = start;
     232     2149654 :     pc_ = start;
     233     2149654 :     end_ = end;
     234     2149654 :     buffer_offset_ = buffer_offset;
     235     4299308 :     error_ = {};
     236     2149654 :   }
     237             : 
     238             :   void Reset(Vector<const uint8_t> bytes, uint32_t buffer_offset = 0) {
     239     1563879 :     Reset(bytes.begin(), bytes.end(), buffer_offset);
     240             :   }
     241             : 
     242             :   bool ok() const { return error_.empty(); }
     243             :   bool failed() const { return !ok(); }
     244             :   bool more() const { return pc_ < end_; }
     245             :   const WasmError& error() const { return error_; }
     246             : 
     247             :   const byte* start() const { return start_; }
     248             :   const byte* pc() const { return pc_; }
     249             :   uint32_t V8_INLINE position() const {
     250          56 :     return static_cast<uint32_t>(pc_ - start_);
     251             :   }
     252             :   // This needs to be inlined for performance (see https://crbug.com/910432).
     253             :   uint32_t V8_INLINE pc_offset(const uint8_t* pc) const {
     254             :     DCHECK_LE(start_, pc);
     255             :     DCHECK_GE(kMaxUInt32 - buffer_offset_, pc - start_);
     256     2298391 :     return static_cast<uint32_t>(pc - start_) + buffer_offset_;
     257             :   }
     258     1946918 :   uint32_t pc_offset() const { return pc_offset(pc_); }
     259             :   uint32_t buffer_offset() const { return buffer_offset_; }
     260             :   // Takes an offset relative to the module start and returns an offset relative
     261             :   // to the current buffer of the decoder.
     262             :   uint32_t GetBufferRelativeOffset(uint32_t offset) const {
     263             :     DCHECK_LE(buffer_offset_, offset);
     264     1262104 :     return offset - buffer_offset_;
     265             :   }
     266             :   const byte* end() const { return end_; }
     267             : 
     268             :  protected:
     269             :   const byte* start_;
     270             :   const byte* pc_;
     271             :   const byte* end_;
     272             :   // The offset of the current buffer in the module. Needed for streaming.
     273             :   uint32_t buffer_offset_;
     274             :   WasmError error_;
     275             : 
     276             :  private:
     277      416228 :   void verrorf(uint32_t offset, const char* format, va_list args) {
     278             :     // Only report the first error.
     279      629121 :     if (!ok()) return;
     280             : #if DEBUG
     281             :     if (FLAG_wasm_break_on_decoder_error) {
     282             :       base::OS::DebugBreak();
     283             :     }
     284             : #endif
     285             :     constexpr int kMaxErrorMsg = 256;
     286             :     EmbeddedVector<char, kMaxErrorMsg> buffer;
     287      203335 :     int len = VSNPrintF(buffer, format, args);
     288      203356 :     CHECK_LT(0, len);
     289      610086 :     error_ = {offset, {buffer.start(), static_cast<size_t>(len)}};
     290      203367 :     onFirstError();
     291             :   }
     292             : 
     293             :   template <typename IntType, bool validate>
     294     1751475 :   inline IntType read_little_endian(const byte* pc, const char* msg) {
     295             :     if (!validate) {
     296             :       DCHECK(validate_size(pc, sizeof(IntType), msg));
     297     1751480 :     } else if (!validate_size(pc, sizeof(IntType), msg)) {
     298             :       return IntType{0};
     299             :     }
     300     1751456 :     return ReadLittleEndianValue<IntType>(reinterpret_cast<Address>(pc));
     301             :   }
     302             : 
     303             :   template <typename IntType>
     304     5912569 :   inline IntType consume_little_endian(const char* name) {
     305             :     TRACE("  +%u  %-20s: ", pc_offset(), name);
     306     5912569 :     if (!checkAvailable(sizeof(IntType))) {
     307             :       traceOffEnd();
     308       13737 :       pc_ = end_;
     309             :       return IntType{0};
     310             :     }
     311     5898854 :     IntType val = read_little_endian<IntType, false>(pc_, name);
     312             :     traceByteRange(pc_, pc_ + sizeof(IntType));
     313             :     TRACE("= %d\n", val);
     314     5898854 :     pc_ += sizeof(IntType);
     315             :     return val;
     316             :   }
     317             : 
     318             :   template <typename IntType, ValidateFlag validate, AdvancePCFlag advance_pc,
     319             :             TraceFlag trace>
     320             :   inline IntType read_leb(const byte* pc, uint32_t* length,
     321             :                           const char* name = "varint") {
     322             :     DCHECK_IMPLIES(advance_pc, pc == pc_);
     323             :     TRACE_IF(trace, "  +%u  %-20s: ", pc_offset(), name);
     324             :     return read_leb_tail<IntType, validate, advance_pc, trace, 0>(pc, length,
     325    60960963 :                                                                   name, 0);
     326             :   }
     327             : 
     328             :   template <typename IntType, ValidateFlag validate, AdvancePCFlag advance_pc,
     329             :             TraceFlag trace, int byte_index>
     330    82100306 :   IntType read_leb_tail(const byte* pc, uint32_t* length, const char* name,
     331             :                         IntType result) {
     332             :     constexpr bool is_signed = std::is_signed<IntType>::value;
     333             :     constexpr int kMaxLength = (sizeof(IntType) * 8 + 6) / 7;
     334             :     static_assert(byte_index < kMaxLength, "invalid template instantiation");
     335             :     constexpr int shift = byte_index * 7;
     336             :     constexpr bool is_last_byte = byte_index == kMaxLength - 1;
     337             :     DCHECK_LE(pc, end_);
     338    29447717 :     const bool at_end = validate && pc == end_;
     339             :     byte b = 0;
     340    29447717 :     if (!at_end) {
     341             :       DCHECK_LT(pc, end_);
     342    83430172 :       b = *pc;
     343             :       TRACE_IF(trace, "%02x ", b);
     344             :       typedef typename std::make_unsigned<IntType>::type Unsigned;
     345    84782084 :       result = result |
     346             :                (static_cast<Unsigned>(static_cast<IntType>(b) & 0x7f) << shift);
     347             :     }
     348    80412387 :     if (!is_last_byte && (b & 0x80)) {
     349             :       // Make sure that we only instantiate the template for valid byte indexes.
     350             :       // Compilers are not smart enough to figure out statically that the
     351             :       // following call is unreachable if is_last_byte is false.
     352             :       constexpr int next_byte_index = byte_index + (is_last_byte ? 0 : 1);
     353             :       return read_leb_tail<IntType, validate, advance_pc, trace,
     354    22491688 :                            next_byte_index>(pc + 1, length, name, result);
     355             :     }
     356     7804802 :     if (advance_pc) pc_ = pc + (at_end ? 0 : 1);
     357    60959879 :     *length = byte_index + (at_end ? 0 : 1);
     358    15963845 :     if (validate && (at_end || (b & 0x80))) {
     359             :       TRACE_IF(trace, at_end ? "<end> " : "<length overflow> ");
     360       22635 :       errorf(pc, "expected %s", name);
     361             :       result = 0;
     362             :     }
     363             :     if (is_last_byte) {
     364             :       // A signed-LEB128 must sign-extend the final byte, excluding its
     365             :       // most-significant bit; e.g. for a 32-bit LEB128:
     366             :       //   kExtraBits = 4  (== 32 - (5-1) * 7)
     367             :       // For unsigned values, the extra bits must be all zero.
     368             :       // For signed values, the extra bits *plus* the most significant bit must
     369             :       // either be 0, or all ones.
     370             :       constexpr int kExtraBits = (sizeof(IntType) * 8) - ((kMaxLength - 1) * 7);
     371             :       constexpr int kSignExtBits = kExtraBits - (is_signed ? 1 : 0);
     372     2998173 :       const byte checked_bits = b & (0xFF << kSignExtBits);
     373             :       constexpr byte kSignExtendedExtraBits = 0x7f & (0xFF << kSignExtBits);
     374             :       bool valid_extra_bits =
     375             :           checked_bits == 0 ||
     376     1539654 :           (is_signed && checked_bits == kSignExtendedExtraBits);
     377             :       if (!validate) {
     378             :         DCHECK(valid_extra_bits);
     379     3040505 :       } else if (!valid_extra_bits) {
     380         512 :         error(pc, "extra bits in varint");
     381             :         result = 0;
     382             :       }
     383             :     }
     384             :     constexpr int sign_ext_shift =
     385             :         is_signed ? Max(0, int{8 * sizeof(IntType)} - shift - 7) : 0;
     386             :     // Perform sign extension.
     387     8922791 :     result = (result << sign_ext_shift) >> sign_ext_shift;
     388             :     if (trace && is_signed) {
     389             :       TRACE("= %" PRIi64 "\n", static_cast<int64_t>(result));
     390             :     } else if (trace) {
     391             :       TRACE("= %" PRIu64 "\n", static_cast<uint64_t>(result));
     392             :     }
     393    12923549 :     return result;
     394             :   }
     395             : };
     396             : 
     397             : #undef TRACE
     398             : }  // namespace wasm
     399             : }  // namespace internal
     400             : }  // namespace v8
     401             : 
     402             : #endif  // V8_WASM_DECODER_H_

Generated by: LCOV version 1.10