LCOV - code coverage report
Current view: top level - src/wasm - decoder.h (source / functions) Hit Total Coverage
Test: app.info Lines: 77 79 97.5 %
Date: 2017-04-26 Functions: 16 18 88.9 %

          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/utils.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             : #if DEBUG
      23             : #define TRACE(...)                                    \
      24             :   do {                                                \
      25             :     if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
      26             :   } while (false)
      27             : #define TRACE_IF(cond, ...)                                     \
      28             :   do {                                                          \
      29             :     if (FLAG_trace_wasm_decoder && (cond)) PrintF(__VA_ARGS__); \
      30             :   } while (false)
      31             : #else
      32             : #define TRACE(...)
      33             : #define TRACE_IF(...)
      34             : #endif
      35             : 
      36             : // A helper utility to decode bytes, integers, fields, varints, etc, from
      37             : // a buffer of bytes.
      38             : class Decoder {
      39             :  public:
      40             :   Decoder(const byte* start, const byte* end)
      41     3469898 :       : start_(start), pc_(start), end_(end), error_pc_(nullptr) {}
      42             :   Decoder(const byte* start, const byte* pc, const byte* end)
      43       15400 :       : start_(start), pc_(pc), end_(end), error_pc_(nullptr) {}
      44             : 
      45     3485229 :   virtual ~Decoder() {}
      46             : 
      47             :   inline bool check(const byte* pc, unsigned length, const char* msg) {
      48             :     DCHECK_LE(start_, pc);
      49      895032 :     if (V8_UNLIKELY(pc + length > end_)) {
      50             :       error(pc, msg);
      51             :       return false;
      52             :     }
      53             :     return true;
      54             :   }
      55             : 
      56             :   // Reads an 8-bit unsigned integer.
      57             :   template <bool checked>
      58             :   inline uint8_t read_u8(const byte* pc, const char* msg = "expected 1 byte") {
      59      441633 :     return read_little_endian<uint8_t, checked>(pc, msg);
      60             :   }
      61             : 
      62             :   // Reads a 16-bit unsigned integer (little endian).
      63             :   template <bool checked>
      64             :   inline uint16_t read_u16(const byte* pc,
      65             :                            const char* msg = "expected 2 bytes") {
      66             :     return read_little_endian<uint16_t, checked>(pc, msg);
      67             :   }
      68             : 
      69             :   // Reads a 32-bit unsigned integer (little endian).
      70             :   template <bool checked>
      71             :   inline uint32_t read_u32(const byte* pc,
      72             :                            const char* msg = "expected 4 bytes") {
      73      442092 :     return read_little_endian<uint32_t, checked>(pc, msg);
      74             :   }
      75             : 
      76             :   // Reads a 64-bit unsigned integer (little endian).
      77             :   template <bool checked>
      78             :   inline uint64_t read_u64(const byte* pc,
      79             :                            const char* msg = "expected 8 bytes") {
      80       11307 :     return read_little_endian<uint64_t, checked>(pc, msg);
      81             :   }
      82             : 
      83             :   // Reads a variable-length unsigned integer (little endian).
      84             :   template <bool checked>
      85             :   uint32_t read_u32v(const byte* pc, unsigned* length,
      86             :                      const char* name = "LEB32") {
      87     1477737 :     return read_leb<uint32_t, checked, false, false>(pc, length, name);
      88             :   }
      89             : 
      90             :   // Reads a variable-length signed integer (little endian).
      91             :   template <bool checked>
      92             :   int32_t read_i32v(const byte* pc, unsigned* length,
      93             :                     const char* name = "signed LEB32") {
      94      862751 :     return read_leb<int32_t, checked, false, false>(pc, length, name);
      95             :   }
      96             : 
      97             :   // Reads a variable-length unsigned integer (little endian).
      98             :   template <bool checked>
      99             :   uint64_t read_u64v(const byte* pc, unsigned* length,
     100             :                      const char* name = "LEB64") {
     101             :     return read_leb<uint64_t, checked, false, false>(pc, length, name);
     102             :   }
     103             : 
     104             :   // Reads a variable-length signed integer (little endian).
     105             :   template <bool checked>
     106             :   int64_t read_i64v(const byte* pc, unsigned* length,
     107             :                     const char* name = "signed LEB64") {
     108       10376 :     return read_leb<int64_t, checked, false, false>(pc, length, name);
     109             :   }
     110             : 
     111             :   // Reads a 8-bit unsigned integer (byte) and advances {pc_}.
     112             :   uint8_t consume_u8(const char* name = "uint8_t") {
     113     2126521 :     return consume_little_endian<uint8_t>(name);
     114             :   }
     115             : 
     116             :   // Reads a 16-bit unsigned integer (little endian) and advances {pc_}.
     117             :   uint16_t consume_u16(const char* name = "uint16_t") {
     118             :     return consume_little_endian<uint16_t>(name);
     119             :   }
     120             : 
     121             :   // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}.
     122             :   uint32_t consume_u32(const char* name = "uint32_t") {
     123       39172 :     return consume_little_endian<uint32_t>(name);
     124             :   }
     125             : 
     126             :   // Reads a LEB128 variable-length unsigned 32-bit integer and advances {pc_}.
     127             :   uint32_t consume_u32v(const char* name = nullptr) {
     128      942895 :     unsigned length = 0;
     129      942895 :     return read_leb<uint32_t, true, true, true>(pc_, &length, name);
     130             :   }
     131             : 
     132             :   // Reads a LEB128 variable-length signed 32-bit integer and advances {pc_}.
     133             :   int32_t consume_i32v(const char* name = nullptr) {
     134         278 :     unsigned length = 0;
     135         278 :     return read_leb<int32_t, true, true, true>(pc_, &length, name);
     136             :   }
     137             : 
     138             :   // Consume {size} bytes and send them to the bit bucket, advancing {pc_}.
     139      650867 :   void consume_bytes(uint32_t size, const char* name = "skip") {
     140             :     // Only trace if the name is not null.
     141             :     TRACE_IF(name, "  +%d  %-20s: %d bytes\n", static_cast<int>(pc_ - start_),
     142             :              name, size);
     143      650867 :     if (checkAvailable(size)) {
     144      650849 :       pc_ += size;
     145             :     } else {
     146          18 :       pc_ = end_;
     147             :     }
     148      650867 :   }
     149             : 
     150             :   // Check that at least {size} bytes exist between {pc_} and {end_}.
     151     2938636 :   bool checkAvailable(int size) {
     152     2938636 :     intptr_t pc_overflow_value = std::numeric_limits<intptr_t>::max() - size;
     153     2938636 :     if (size < 0 || (intptr_t)pc_ > pc_overflow_value) {
     154           0 :       errorf(pc_, "reading %d bytes would underflow/overflow", size);
     155           0 :       return false;
     156     2938636 :     } else if (pc_ < start_ || end_ < (pc_ + size)) {
     157         613 :       errorf(pc_, "expected %d bytes, fell off end", size);
     158         611 :       return false;
     159             :     } else {
     160             :       return true;
     161             :     }
     162             :   }
     163             : 
     164         347 :   void error(const char* msg) { errorf(pc_, "%s", msg); }
     165             : 
     166        1287 :   void error(const byte* pc, const char* msg) { errorf(pc, "%s", msg); }
     167             : 
     168             :   // Sets internal error state.
     169        3451 :   void PRINTF_FORMAT(3, 4) errorf(const byte* pc, const char* format, ...) {
     170             :     // Only report the first error.
     171        4964 :     if (!ok()) return;
     172             : #if DEBUG
     173             :     if (FLAG_wasm_break_on_decoder_error) {
     174             :       base::OS::DebugBreak();
     175             :     }
     176             : #endif
     177             :     constexpr int kMaxErrorMsg = 256;
     178             :     EmbeddedVector<char, kMaxErrorMsg> buffer;
     179             :     va_list arguments;
     180        1938 :     va_start(arguments, format);
     181        1938 :     int len = VSNPrintF(buffer, format, arguments);
     182        1938 :     CHECK_LT(0, len);
     183        1938 :     va_end(arguments);
     184        1938 :     error_msg_.assign(buffer.start(), len);
     185        1938 :     error_pc_ = pc;
     186        1938 :     onFirstError();
     187             :   }
     188             : 
     189             :   // Behavior triggered on first error, overridden in subclasses.
     190         188 :   virtual void onFirstError() {}
     191             : 
     192             :   // Debugging helper to print a bytes range as hex bytes.
     193             :   void traceByteRange(const byte* start, const byte* end) {
     194             :     DCHECK_LE(start, end);
     195             :     for (const byte* p = start; p < end; ++p) TRACE("%02x ", *p);
     196             :   }
     197             : 
     198             :   // Debugging helper to print bytes up to the end.
     199             :   void traceOffEnd() {
     200             :     traceByteRange(pc_, end_);
     201             :     TRACE("<end>\n");
     202             :   }
     203             : 
     204             :   // Converts the given value to a {Result}, copying the error if necessary.
     205             :   template <typename T, typename U = typename std::remove_reference<T>::type>
     206          78 :   Result<U> toResult(T&& val) {
     207             :     Result<U> result(std::forward<T>(val));
     208      106201 :     if (failed()) {
     209             :       // The error message must not be empty, otherwise Result::failed() will be
     210             :       // false.
     211             :       DCHECK(!error_msg_.empty());
     212             :       TRACE("Result error: %s\n", error_msg_.c_str());
     213             :       DCHECK_GE(error_pc_, start_);
     214       11670 :       result.error_offset = static_cast<uint32_t>(error_pc_ - start_);
     215         888 :       result.error_msg = std::move(error_msg_);
     216             :     }
     217          78 :     return result;
     218             :   }
     219             : 
     220             :   // Resets the boundaries of this decoder.
     221             :   void Reset(const byte* start, const byte* end) {
     222     1413044 :     start_ = start;
     223     1413044 :     pc_ = start;
     224     1413044 :     end_ = end;
     225     1413044 :     error_pc_ = nullptr;
     226     1413044 :     error_msg_.clear();
     227             :   }
     228             : 
     229             :   bool ok() const { return error_msg_.empty(); }
     230             :   bool failed() const { return !ok(); }
     231             :   bool more() const { return pc_ < end_; }
     232             : 
     233             :   const byte* start() const { return start_; }
     234             :   const byte* pc() const { return pc_; }
     235      212939 :   uint32_t pc_offset() const { return static_cast<uint32_t>(pc_ - start_); }
     236             :   const byte* end() const { return end_; }
     237             : 
     238             :  protected:
     239             :   const byte* start_;
     240             :   const byte* pc_;
     241             :   const byte* end_;
     242             :   const byte* error_pc_;
     243             :   std::string error_msg_;
     244             : 
     245             :  private:
     246             :   template <typename IntType, bool checked>
     247      895032 :   inline IntType read_little_endian(const byte* pc, const char* msg) {
     248             :     if (!checked) {
     249             :       DCHECK(check(pc, sizeof(IntType), msg));
     250      895032 :     } else if (!check(pc, sizeof(IntType), msg)) {
     251             :       return IntType{0};
     252             :     }
     253      895032 :     return ReadLittleEndianValue<IntType>(pc);
     254             :   }
     255             : 
     256             :   template <typename IntType>
     257     2165693 :   inline IntType consume_little_endian(const char* name) {
     258             :     TRACE("  +%d  %-20s: ", static_cast<int>(pc_ - start_), name);
     259     2165693 :     if (!checkAvailable(sizeof(IntType))) {
     260             :       traceOffEnd();
     261         410 :       pc_ = end_;
     262             :       return IntType{0};
     263             :     }
     264     2165283 :     IntType val = read_little_endian<IntType, false>(pc_, name);
     265             :     traceByteRange(pc_, pc_ + sizeof(IntType));
     266             :     TRACE("= %d\n", val);
     267     2165283 :     pc_ += sizeof(IntType);
     268             :     return val;
     269             :   }
     270             : 
     271             :   template <typename IntType, bool checked, bool advance_pc, bool trace>
     272     3294044 :   inline IntType read_leb(const byte* pc, unsigned* length,
     273             :                           const char* name = "varint") {
     274             :     DCHECK_IMPLIES(advance_pc, pc == pc_);
     275             :     constexpr bool is_signed = std::is_signed<IntType>::value;
     276             :     TRACE_IF(trace, "  +%d  %-20s: ", static_cast<int>(pc - start_), name);
     277             :     constexpr int kMaxLength = (sizeof(IntType) * 8 + 6) / 7;
     278             :     const byte* ptr = pc;
     279     3294044 :     const byte* end = Min(end_, ptr + kMaxLength);
     280             :     // The end variable is only used if checked == true. MSVC recognizes this.
     281             :     USE(end);
     282             :     int shift = 0;
     283             :     byte b = 0;
     284             :     IntType result = 0;
     285    13438671 :     do {
     286     4302087 :       if (checked && V8_UNLIKELY(ptr >= end)) {
     287             :         TRACE_IF(trace,
     288             :                  ptr == pc + kMaxLength ? "<length overflow> " : "<end> ");
     289         565 :         errorf(ptr, "expected %s", name);
     290             :         result = 0;
     291         565 :         break;
     292             :       }
     293             :       DCHECK_GT(end, ptr);
     294    13438671 :       b = *ptr++;
     295             :       TRACE_IF(trace, "%02x ", b);
     296    13277606 :       result = result | ((static_cast<IntType>(b) & 0x7F) << shift);
     297    13277606 :       shift += 7;
     298             :     } while (b & 0x80);
     299             :     DCHECK_LE(ptr - pc, kMaxLength);
     300    11515693 :     *length = static_cast<unsigned>(ptr - pc);
     301      943169 :     if (advance_pc) pc_ = ptr;
     302     3294044 :     if (*length == kMaxLength) {
     303             :       // A signed-LEB128 must sign-extend the final byte, excluding its
     304             :       // most-significant bit; e.g. for a 32-bit LEB128:
     305             :       //   kExtraBits = 4  (== 32 - (5-1) * 7)
     306             :       // For unsigned values, the extra bits must be all zero.
     307             :       // For signed values, the extra bits *plus* the most significant bit must
     308             :       // either be 0, or all ones.
     309             :       constexpr int kExtraBits = (sizeof(IntType) * 8) - ((kMaxLength - 1) * 7);
     310             :       constexpr int kSignExtBits = kExtraBits - (is_signed ? 1 : 0);
     311      154975 :       const byte checked_bits = b & (0xFF << kSignExtBits);
     312             :       constexpr byte kSignExtendedExtraBits = 0x7f & (0xFF << kSignExtBits);
     313             :       bool valid_extra_bits =
     314             :           checked_bits == 0 ||
     315       42449 :           (is_signed && checked_bits == kSignExtendedExtraBits);
     316             :       if (!checked) {
     317             :         DCHECK(valid_extra_bits);
     318      163152 :       } else if (!valid_extra_bits) {
     319             :         error(ptr, "extra bits in varint");
     320             :         result = 0;
     321             :       }
     322             :     }
     323     1456615 :     if (is_signed && *length < kMaxLength) {
     324     1409196 :       int sign_ext_shift = 8 * sizeof(IntType) - shift;
     325             :       // Perform sign extension.
     326     1409196 :       result = (result << sign_ext_shift) >> sign_ext_shift;
     327             :     }
     328             :     if (trace && is_signed) {
     329             :       TRACE("= %" PRIi64 "\n", static_cast<int64_t>(result));
     330             :     } else if (trace) {
     331             :       TRACE("= %" PRIu64 "\n", static_cast<uint64_t>(result));
     332             :     }
     333     3294029 :     return result;
     334             :   }
     335             : };
     336             : 
     337             : #undef TRACE
     338             : }  // namespace wasm
     339             : }  // namespace internal
     340             : }  // namespace v8
     341             : 
     342             : #endif  // V8_WASM_DECODER_H_

Generated by: LCOV version 1.10