LCOV - code coverage report
Current view: top level - src/wasm - decoder.h (source / functions) Hit Total Coverage
Test: app.info Lines: 76 78 97.4 %
Date: 2017-10-20 Functions: 103 116 88.8 %

          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 {DecodeResult} only stores the failure / success status, but no data. Thus
      37             : // we use {nullptr_t} as data value, such that the only valid data stored in
      38             : // this type is a nullptr.
      39             : // Storing {void} would require template specialization.
      40             : using DecodeResult = Result<std::nullptr_t>;
      41             : 
      42             : // A helper utility to decode bytes, integers, fields, varints, etc, from
      43             : // a buffer of bytes.
      44             : class Decoder {
      45             :  public:
      46             :   enum ValidateFlag : bool { kValidate = true, kNoValidate = false };
      47             : 
      48             :   enum AdvancePCFlag : bool { kAdvancePc = true, kNoAdvancePc = false };
      49             : 
      50             :   enum TraceFlag : bool { kTrace = true, kNoTrace = false };
      51             : 
      52             :   Decoder(const byte* start, const byte* end, uint32_t buffer_offset = 0)
      53     4189819 :       : start_(start), pc_(start), end_(end), buffer_offset_(buffer_offset) {}
      54             :   Decoder(const byte* start, const byte* pc, const byte* end,
      55             :           uint32_t buffer_offset = 0)
      56       10442 :       : start_(start), pc_(pc), end_(end), buffer_offset_(buffer_offset) {}
      57             : 
      58     4200102 :   virtual ~Decoder() {}
      59             : 
      60             :   inline bool validate_size(const byte* pc, uint32_t length, const char* msg) {
      61             :     DCHECK_LE(start_, pc);
      62     1642128 :     if (V8_UNLIKELY(pc + length > end_)) {
      63             :       error(pc, msg);
      64             :       return false;
      65             :     }
      66             :     return true;
      67             :   }
      68             : 
      69             :   // Reads an 8-bit unsigned integer.
      70             :   template <ValidateFlag validate>
      71             :   inline uint8_t read_u8(const byte* pc, const char* msg = "expected 1 byte") {
      72      609943 :     return read_little_endian<uint8_t, validate>(pc, msg);
      73             :   }
      74             : 
      75             :   // Reads a 16-bit unsigned integer (little endian).
      76             :   template <ValidateFlag validate>
      77             :   inline uint16_t read_u16(const byte* pc,
      78             :                            const char* msg = "expected 2 bytes") {
      79             :     return read_little_endian<uint16_t, validate>(pc, msg);
      80             :   }
      81             : 
      82             :   // Reads a 32-bit unsigned integer (little endian).
      83             :   template <ValidateFlag validate>
      84             :   inline uint32_t read_u32(const byte* pc,
      85             :                            const char* msg = "expected 4 bytes") {
      86      728563 :     return read_little_endian<uint32_t, validate>(pc, msg);
      87             :   }
      88             : 
      89             :   // Reads a 64-bit unsigned integer (little endian).
      90             :   template <ValidateFlag validate>
      91             :   inline uint64_t read_u64(const byte* pc,
      92             :                            const char* msg = "expected 8 bytes") {
      93      303622 :     return read_little_endian<uint64_t, validate>(pc, msg);
      94             :   }
      95             : 
      96             :   // Reads a variable-length unsigned integer (little endian).
      97             :   template <ValidateFlag validate>
      98             :   uint32_t read_u32v(const byte* pc, uint32_t* length,
      99             :                      const char* name = "LEB32") {
     100             :     return read_leb<uint32_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
     101             :                                                                 name);
     102             :   }
     103             : 
     104             :   // Reads a variable-length signed integer (little endian).
     105             :   template <ValidateFlag validate>
     106             :   int32_t read_i32v(const byte* pc, uint32_t* length,
     107             :                     const char* name = "signed LEB32") {
     108             :     return read_leb<int32_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
     109             :                                                                name);
     110             :   }
     111             : 
     112             :   // Reads a variable-length unsigned integer (little endian).
     113             :   template <ValidateFlag validate>
     114             :   uint64_t read_u64v(const byte* pc, uint32_t* length,
     115             :                      const char* name = "LEB64") {
     116             :     return read_leb<uint64_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
     117             :                                                                 name);
     118             :   }
     119             : 
     120             :   // Reads a variable-length signed integer (little endian).
     121             :   template <ValidateFlag validate>
     122             :   int64_t read_i64v(const byte* pc, uint32_t* length,
     123             :                     const char* name = "signed LEB64") {
     124             :     return read_leb<int64_t, validate, kNoAdvancePc, kNoTrace>(pc, length,
     125             :                                                                name);
     126             :   }
     127             : 
     128             :   // Reads a 8-bit unsigned integer (byte) and advances {pc_}.
     129             :   uint8_t consume_u8(const char* name = "uint8_t") {
     130     5393896 :     return consume_little_endian<uint8_t>(name);
     131             :   }
     132             : 
     133             :   // Reads a 16-bit unsigned integer (little endian) and advances {pc_}.
     134             :   uint16_t consume_u16(const char* name = "uint16_t") {
     135             :     return consume_little_endian<uint16_t>(name);
     136             :   }
     137             : 
     138             :   // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}.
     139             :   uint32_t consume_u32(const char* name = "uint32_t") {
     140      618676 :     return consume_little_endian<uint32_t>(name);
     141             :   }
     142             : 
     143             :   // Reads a LEB128 variable-length unsigned 32-bit integer and advances {pc_}.
     144             :   uint32_t consume_u32v(const char* name = nullptr) {
     145     7113892 :     uint32_t length = 0;
     146             :     return read_leb<uint32_t, kValidate, kAdvancePc, kTrace>(pc_, &length,
     147     3507566 :                                                              name);
     148             :   }
     149             : 
     150             :   // Reads a LEB128 variable-length signed 32-bit integer and advances {pc_}.
     151             :   int32_t consume_i32v(const char* name = nullptr) {
     152         455 :     uint32_t length = 0;
     153         455 :     return read_leb<int32_t, kValidate, kAdvancePc, kTrace>(pc_, &length, name);
     154             :   }
     155             : 
     156             :   // Consume {size} bytes and send them to the bit bucket, advancing {pc_}.
     157     3217078 :   void consume_bytes(uint32_t size, const char* name = "skip") {
     158             :     // Only trace if the name is not null.
     159             :     TRACE_IF(name, "  +%u  %-20s: %u bytes\n", pc_offset(), name, size);
     160     3217078 :     if (checkAvailable(size)) {
     161     3217024 :       pc_ += size;
     162             :     } else {
     163          54 :       pc_ = end_;
     164             :     }
     165     3217078 :   }
     166             : 
     167             :   // Check that at least {size} bytes exist between {pc_} and {end_}.
     168    10719016 :   bool checkAvailable(uint32_t size) {
     169    10719016 :     uintptr_t pc_overflow_value = std::numeric_limits<uintptr_t>::max() - size;
     170    10719016 :     if ((uintptr_t)pc_ > pc_overflow_value) {
     171           0 :       errorf(pc_, "reading %u bytes would underflow/overflow", size);
     172           0 :       return false;
     173    10719016 :     } else if (pc_ < start_ || end_ < (pc_ + size)) {
     174        8242 :       errorf(pc_, "expected %u bytes, fell off end", size);
     175        8243 :       return false;
     176             :     } else {
     177             :       return true;
     178             :     }
     179             :   }
     180             : 
     181         852 :   void error(const char* msg) { errorf(pc_, "%s", msg); }
     182             : 
     183        3545 :   void error(const byte* pc, const char* msg) { errorf(pc, "%s", msg); }
     184             : 
     185             :   // Sets internal error state.
     186       84980 :   void PRINTF_FORMAT(3, 4) errorf(const byte* pc, const char* format, ...) {
     187             :     // Only report the first error.
     188      121671 :     if (!ok()) return;
     189             : #if DEBUG
     190             :     if (FLAG_wasm_break_on_decoder_error) {
     191             :       base::OS::DebugBreak();
     192             :     }
     193             : #endif
     194             :     constexpr int kMaxErrorMsg = 256;
     195             :     EmbeddedVector<char, kMaxErrorMsg> buffer;
     196             :     va_list arguments;
     197       48289 :     va_start(arguments, format);
     198       48289 :     int len = VSNPrintF(buffer, format, arguments);
     199       48289 :     CHECK_LT(0, len);
     200       48289 :     va_end(arguments);
     201       48289 :     error_msg_.assign(buffer.start(), len);
     202             :     DCHECK_GE(pc, start_);
     203       48289 :     error_offset_ = static_cast<uint32_t>(pc - start_) + buffer_offset_;
     204       48289 :     onFirstError();
     205             :   }
     206             : 
     207             :   // Behavior triggered on first error, overridden in subclasses.
     208       16856 :   virtual void onFirstError() {}
     209             : 
     210             :   // Debugging helper to print a bytes range as hex bytes.
     211             :   void traceByteRange(const byte* start, const byte* end) {
     212             :     DCHECK_LE(start, end);
     213             :     for (const byte* p = start; p < end; ++p) TRACE("%02x ", *p);
     214             :   }
     215             : 
     216             :   // Debugging helper to print bytes up to the end.
     217             :   void traceOffEnd() {
     218             :     traceByteRange(pc_, end_);
     219             :     TRACE("<end>\n");
     220             :   }
     221             : 
     222             :   // Converts the given value to a {Result}, copying the error if necessary.
     223             :   template <typename T, typename U = typename std::remove_reference<T>::type>
     224      713618 :   Result<U> toResult(T&& val) {
     225             :     Result<U> result(std::forward<T>(val));
     226      713618 :     if (failed()) {
     227             :       TRACE("Result error: %s\n", error_msg_.c_str());
     228       70142 :       result.error(error_offset_, std::move(error_msg_));
     229             :     }
     230      713618 :     return result;
     231             :   }
     232             : 
     233             :   // Resets the boundaries of this decoder.
     234             :   void Reset(const byte* start, const byte* end, uint32_t buffer_offset = 0) {
     235     2954970 :     start_ = start;
     236     2954971 :     pc_ = start;
     237     2954971 :     end_ = end;
     238     2954971 :     buffer_offset_ = buffer_offset;
     239     2954971 :     error_offset_ = 0;
     240     2953359 :     error_msg_.clear();
     241             :   }
     242             : 
     243             :   void Reset(Vector<const uint8_t> bytes, uint32_t buffer_offset = 0) {
     244             :     Reset(bytes.begin(), bytes.end(), buffer_offset);
     245             :   }
     246             : 
     247             :   bool ok() const { return error_msg_.empty(); }
     248             :   bool failed() const { return !ok(); }
     249             :   bool more() const { return pc_ < end_; }
     250             : 
     251             :   const byte* start() const { return start_; }
     252             :   const byte* pc() const { return pc_; }
     253             :   uint32_t pc_offset() const {
     254     1625113 :     return static_cast<uint32_t>(pc_ - start_) + buffer_offset_;
     255             :   }
     256             :   uint32_t buffer_offset() const { return buffer_offset_; }
     257             :   // Takes an offset relative to the module start and returns an offset relative
     258             :   // to the current buffer of the decoder.
     259             :   uint32_t GetBufferRelativeOffset(uint32_t offset) const {
     260             :     DCHECK_LE(buffer_offset_, offset);
     261      786866 :     return offset - buffer_offset_;
     262             :   }
     263             :   const byte* end() const { return end_; }
     264             : 
     265             :  protected:
     266             :   const byte* start_;
     267             :   const byte* pc_;
     268             :   const byte* end_;
     269             :   // The offset of the current buffer in the module. Needed for streaming.
     270             :   uint32_t buffer_offset_;
     271             :   uint32_t error_offset_ = 0;
     272             :   std::string error_msg_;
     273             : 
     274             :  private:
     275             :   template <typename IntType, bool validate>
     276     1642128 :   inline IntType read_little_endian(const byte* pc, const char* msg) {
     277             :     if (!validate) {
     278             :       DCHECK(validate_size(pc, sizeof(IntType), msg));
     279     1642130 :     } else if (!validate_size(pc, sizeof(IntType), msg)) {
     280             :       return IntType{0};
     281             :     }
     282     1642130 :     return ReadLittleEndianValue<IntType>(pc);
     283             :   }
     284             : 
     285             :   template <typename IntType>
     286     6012572 :   inline IntType consume_little_endian(const char* name) {
     287             :     TRACE("  +%u  %-20s: ", pc_offset(), name);
     288     6012572 :     if (!checkAvailable(sizeof(IntType))) {
     289             :       traceOffEnd();
     290        8032 :       pc_ = end_;
     291             :       return IntType{0};
     292             :     }
     293     6004540 :     IntType val = read_little_endian<IntType, false>(pc_, name);
     294             :     traceByteRange(pc_, pc_ + sizeof(IntType));
     295             :     TRACE("= %d\n", val);
     296     6004540 :     pc_ += sizeof(IntType);
     297             :     return val;
     298             :   }
     299             : 
     300             :   template <typename IntType, ValidateFlag validate, AdvancePCFlag advance_pc,
     301             :             TraceFlag trace>
     302             :   inline IntType read_leb(const byte* pc, uint32_t* length,
     303             :                           const char* name = "varint") {
     304             :     DCHECK_IMPLIES(advance_pc, pc == pc_);
     305             :     TRACE_IF(trace, "  +%u  %-20s: ", pc_offset(), name);
     306             :     return read_leb_tail<IntType, validate, advance_pc, trace, 0>(pc, length,
     307    20986570 :                                                                   name, 0);
     308             :   }
     309             : 
     310             :   template <typename IntType, ValidateFlag validate, AdvancePCFlag advance_pc,
     311             :             TraceFlag trace, int byte_index>
     312    29932850 :   IntType read_leb_tail(const byte* pc, uint32_t* length, const char* name,
     313             :                         IntType result) {
     314             :     constexpr bool is_signed = std::is_signed<IntType>::value;
     315             :     constexpr int kMaxLength = (sizeof(IntType) * 8 + 6) / 7;
     316             :     static_assert(byte_index < kMaxLength, "invalid template instantiation");
     317             :     constexpr int shift = byte_index * 7;
     318             :     constexpr bool is_last_byte = byte_index == kMaxLength - 1;
     319    20370291 :     const bool at_end = validate && pc >= end_;
     320             :     byte b = 0;
     321    20370291 :     if (!at_end) {
     322             :       DCHECK_LT(pc, end_);
     323    29918377 :       b = *pc;
     324             :       TRACE_IF(trace, "%02x ", b);
     325    29927119 :       result = result | ((static_cast<IntType>(b) & 0x7f) << shift);
     326             :     }
     327    28019772 :     if (!is_last_byte && (b & 0x80)) {
     328             :       // Make sure that we only instantiate the template for valid byte indexes.
     329             :       // Compilers are not smart enough to figure out statically that the
     330             :       // following call is unreachable if is_last_byte is false.
     331             :       constexpr int next_byte_index = byte_index + (is_last_byte ? 0 : 1);
     332             :       return read_leb_tail<IntType, validate, advance_pc, trace,
     333     8955032 :                            next_byte_index>(pc + 1, length, name, result);
     334             :     }
     335     7114382 :     if (advance_pc) pc_ = pc + (at_end ? 0 : 1);
     336    20985627 :     *length = byte_index + (at_end ? 0 : 1);
     337    11936977 :     if (validate && (at_end || (b & 0x80))) {
     338             :       TRACE_IF(trace, at_end ? "<end> " : "<length overflow> ");
     339       24212 :       errorf(pc, "expected %s", name);
     340             :       result = 0;
     341             :     }
     342             :     if (is_last_byte) {
     343             :       // A signed-LEB128 must sign-extend the final byte, excluding its
     344             :       // most-significant bit; e.g. for a 32-bit LEB128:
     345             :       //   kExtraBits = 4  (== 32 - (5-1) * 7)
     346             :       // For unsigned values, the extra bits must be all zero.
     347             :       // For signed values, the extra bits *plus* the most significant bit must
     348             :       // either be 0, or all ones.
     349             :       constexpr int kExtraBits = (sizeof(IntType) * 8) - ((kMaxLength - 1) * 7);
     350             :       constexpr int kSignExtBits = kExtraBits - (is_signed ? 1 : 0);
     351     1870174 :       const byte checked_bits = b & (0xFF << kSignExtBits);
     352             :       constexpr byte kSignExtendedExtraBits = 0x7f & (0xFF << kSignExtBits);
     353             :       bool valid_extra_bits =
     354             :           checked_bits == 0 ||
     355      123048 :           (is_signed && checked_bits == kSignExtendedExtraBits);
     356             :       if (!validate) {
     357             :         DCHECK(valid_extra_bits);
     358     1922760 :       } else if (!valid_extra_bits) {
     359             :         error(pc, "extra bits in varint");
     360             :         result = 0;
     361             :       }
     362             :     }
     363             :     constexpr int sign_ext_shift =
     364             :         is_signed ? Max(0, int{8 * sizeof(IntType)} - shift - 7) : 0;
     365             :     // Perform sign extension.
     366     2105799 :     result = (result << sign_ext_shift) >> sign_ext_shift;
     367             :     if (trace && is_signed) {
     368             :       TRACE("= %" PRIi64 "\n", static_cast<int64_t>(result));
     369             :     } else if (trace) {
     370             :       TRACE("= %" PRIu64 "\n", static_cast<uint64_t>(result));
     371             :     }
     372    10014243 :     return result;
     373             :   }
     374             : };
     375             : 
     376             : // Reference to a string in the wire bytes.
     377             : class WireBytesRef {
     378             :  public:
     379             :   WireBytesRef() : WireBytesRef(0, 0) {}
     380             :   WireBytesRef(uint32_t offset, uint32_t length)
     381     1646562 :       : offset_(offset), length_(length) {
     382             :     DCHECK_IMPLIES(offset_ == 0, length_ == 0);
     383             :     DCHECK_LE(offset_, offset_ + length_);  // no uint32_t overflow.
     384             :   }
     385             : 
     386          54 :   uint32_t offset() const { return offset_; }
     387             :   uint32_t length() const { return length_; }
     388      387085 :   uint32_t end_offset() const { return offset_ + length_; }
     389             :   bool is_empty() const { return length_ == 0; }
     390             :   bool is_set() const { return offset_ != 0; }
     391             : 
     392             :  private:
     393             :   uint32_t offset_;
     394             :   uint32_t length_;
     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