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 "src/base/smart-pointers.h" 9 #include "src/flags.h" 10 #include "src/signature.h" 11 #include "src/wasm/wasm-result.h" 12 #include "src/zone-containers.h" 13 14 namespace v8 { 15 namespace internal { 16 namespace wasm { 17 18 #if DEBUG 19 #define TRACE(...) \ 20 do { \ 21 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ 22 } while (false) 23 #else 24 #define TRACE(...) 25 #endif 26 27 // A helper utility to decode bytes, integers, fields, varints, etc, from 28 // a buffer of bytes. 29 class Decoder { 30 public: 31 Decoder(const byte* start, const byte* end) 32 : start_(start), 33 pc_(start), 34 limit_(end), 35 error_pc_(nullptr), 36 error_pt_(nullptr) {} 37 38 virtual ~Decoder() {} 39 40 // Reads a 8-bit unsigned integer (byte) and advances {pc_}. 41 uint8_t u8(const char* name = nullptr) { 42 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), 43 name ? name : "uint8_t"); 44 if (checkAvailable(1)) { 45 byte val = *(pc_++); 46 TRACE("%02x = %d\n", val, val); 47 return val; 48 } else { 49 error("expected 1 byte, but fell off end"); 50 return traceOffEnd<uint8_t>(); 51 } 52 } 53 54 // Reads a 16-bit unsigned integer (little endian) and advances {pc_}. 55 uint16_t u16(const char* name = nullptr) { 56 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), 57 name ? name : "uint16_t"); 58 if (checkAvailable(2)) { 59 #ifdef V8_TARGET_LITTLE_ENDIAN 60 byte b0 = pc_[0]; 61 byte b1 = pc_[1]; 62 #else 63 byte b1 = pc_[0]; 64 byte b0 = pc_[1]; 65 #endif 66 uint16_t val = static_cast<uint16_t>(b1 << 8) | b0; 67 TRACE("%02x %02x = %d\n", pc_[0], pc_[1], val); 68 pc_ += 2; 69 return val; 70 } else { 71 error("expected 2 bytes, but fell off end"); 72 return traceOffEnd<uint16_t>(); 73 } 74 } 75 76 // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}. 77 uint32_t u32(const char* name = nullptr) { 78 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), 79 name ? name : "uint32_t"); 80 if (checkAvailable(4)) { 81 #ifdef V8_TARGET_LITTLE_ENDIAN 82 byte b0 = pc_[0]; 83 byte b1 = pc_[1]; 84 byte b2 = pc_[2]; 85 byte b3 = pc_[3]; 86 #else 87 byte b3 = pc_[0]; 88 byte b2 = pc_[1]; 89 byte b1 = pc_[2]; 90 byte b0 = pc_[3]; 91 #endif 92 uint32_t val = static_cast<uint32_t>(b3 << 24) | 93 static_cast<uint32_t>(b2 << 16) | 94 static_cast<uint32_t>(b1 << 8) | b0; 95 TRACE("%02x %02x %02x %02x = %u\n", pc_[0], pc_[1], pc_[2], pc_[3], val); 96 pc_ += 4; 97 return val; 98 } else { 99 error("expected 4 bytes, but fell off end"); 100 return traceOffEnd<uint32_t>(); 101 } 102 } 103 104 // Reads a LEB128 variable-length 32-bit integer and advances {pc_}. 105 uint32_t u32v(int* length, const char* name = nullptr) { 106 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), 107 name ? name : "varint"); 108 109 if (!checkAvailable(1)) { 110 error("expected at least 1 byte, but fell off end"); 111 return traceOffEnd<uint32_t>(); 112 } 113 114 const byte* pos = pc_; 115 const byte* end = pc_ + 5; 116 if (end > limit_) end = limit_; 117 118 uint32_t result = 0; 119 int shift = 0; 120 byte b = 0; 121 while (pc_ < end) { 122 b = *pc_++; 123 TRACE("%02x ", b); 124 result = result | ((b & 0x7F) << shift); 125 if ((b & 0x80) == 0) break; 126 shift += 7; 127 } 128 129 *length = static_cast<int>(pc_ - pos); 130 if (pc_ == end && (b & 0x80)) { 131 error(pc_ - 1, "varint too large"); 132 } else { 133 TRACE("= %u\n", result); 134 } 135 return result; 136 } 137 138 // Check that at least {size} bytes exist between {pc_} and {limit_}. 139 bool checkAvailable(int size) { 140 if (pc_ < start_ || (pc_ + size) > limit_) { 141 error(pc_, nullptr, "expected %d bytes, fell off end", size); 142 return false; 143 } else { 144 return true; 145 } 146 } 147 148 void error(const char* msg) { error(pc_, nullptr, msg); } 149 150 void error(const byte* pc, const char* msg) { error(pc, nullptr, msg); } 151 152 // Sets internal error state. 153 void error(const byte* pc, const byte* pt, const char* format, ...) { 154 if (ok()) { 155 #if DEBUG 156 if (FLAG_wasm_break_on_decoder_error) { 157 base::OS::DebugBreak(); 158 } 159 #endif 160 const int kMaxErrorMsg = 256; 161 char* buffer = new char[kMaxErrorMsg]; 162 va_list arguments; 163 va_start(arguments, format); 164 base::OS::VSNPrintF(buffer, kMaxErrorMsg - 1, format, arguments); 165 va_end(arguments); 166 error_msg_.Reset(buffer); 167 error_pc_ = pc; 168 error_pt_ = pt; 169 onFirstError(); 170 } 171 } 172 173 // Behavior triggered on first error, overridden in subclasses. 174 virtual void onFirstError() {} 175 176 // Debugging helper to print bytes up to the end. 177 template <typename T> 178 T traceOffEnd() { 179 T t = 0; 180 for (const byte* ptr = pc_; ptr < limit_; ptr++) { 181 TRACE("%02x ", *ptr); 182 } 183 TRACE("<end>\n"); 184 pc_ = limit_; 185 return t; 186 } 187 188 // Converts the given value to a {Result}, copying the error if necessary. 189 template <typename T> 190 Result<T> toResult(T val) { 191 Result<T> result; 192 if (error_pc_) { 193 result.error_code = kError; 194 result.start = start_; 195 result.error_pc = error_pc_; 196 result.error_pt = error_pt_; 197 result.error_msg = error_msg_; 198 error_msg_.Reset(nullptr); 199 } else { 200 result.error_code = kSuccess; 201 } 202 result.val = val; 203 return result; 204 } 205 206 // Resets the boundaries of this decoder. 207 void Reset(const byte* start, const byte* end) { 208 start_ = start; 209 pc_ = start; 210 limit_ = end; 211 error_pc_ = nullptr; 212 error_pt_ = nullptr; 213 error_msg_.Reset(nullptr); 214 } 215 216 bool ok() const { return error_pc_ == nullptr; } 217 bool failed() const { return error_pc_ != nullptr; } 218 219 protected: 220 const byte* start_; 221 const byte* pc_; 222 const byte* limit_; 223 const byte* error_pc_; 224 const byte* error_pt_; 225 base::SmartArrayPointer<char> error_msg_; 226 }; 227 228 #undef TRACE 229 } // namespace wasm 230 } // namespace internal 231 } // namespace v8 232 233 #endif // V8_WASM_DECODER_H_ 234