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 3416 : : 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 15279811 : : 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 15279851 : 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 2293382 : if (V8_UNLIKELY(length > static_cast<uint32_t>(end_ - pc))) {
62 26 : 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 1309284 : 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 705549 : 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 278549 : 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 5797247 : 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 633380 : 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 9361817 : uint32_t length = 0;
145 : return read_leb<uint32_t, kValidate, kAdvancePc, kTrace>(pc_, &length,
146 5133887 : 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 761 : uint32_t length = 0;
152 761 : 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 3511051 : 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 3511051 : if (checkAvailable(size)) {
160 3509784 : pc_ += size;
161 : } else {
162 1277 : pc_ = end_;
163 : }
164 3511061 : }
165 :
166 : // Check that at least {size} bytes exist between {pc_} and {end_}.
167 11602520 : bool checkAvailable(uint32_t size) {
168 : DCHECK_LE(pc_, end_);
169 11602520 : if (V8_UNLIKELY(size > static_cast<uint32_t>(end_ - pc_))) {
170 141707 : errorf(pc_, "expected %u bytes, fell off end", size);
171 141707 : 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 96868 : void V8_NOINLINE error(const char* msg) { errorf(pc_offset(), "%s", msg); }
179 9300 : void V8_NOINLINE error(const uint8_t* pc, const char* msg) {
180 9300 : errorf(pc_offset(pc), "%s", msg);
181 9300 : }
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 75506 : errorf(uint32_t offset, const char* format, ...) {
188 : va_list args;
189 75506 : va_start(args, format);
190 75506 : verrorf(offset, format, args);
191 75504 : va_end(args);
192 75504 : }
193 :
194 : void V8_NOINLINE PRINTF_FORMAT(3, 4)
195 752490 : errorf(const uint8_t* pc, const char* format, ...) {
196 : va_list args;
197 376245 : va_start(args, format);
198 376245 : verrorf(pc_offset(pc), format, args);
199 376245 : va_end(args);
200 376245 : }
201 :
202 : // Behavior triggered on first error, overridden in subclasses.
203 146169 : 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 1557915 : Result<U> toResult(T&& val) {
220 1557915 : if (failed()) {
221 : TRACE("Result error: %s\n", error_.message().c_str());
222 73465 : return Result<U>{error_};
223 : }
224 295060 : return Result<U>{std::forward<T>(val)};
225 : }
226 :
227 : // Resets the boundaries of this decoder.
228 2403177 : 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 2403177 : start_ = start;
232 2403177 : pc_ = start;
233 2403177 : end_ = end;
234 2403177 : buffer_offset_ = buffer_offset;
235 4806332 : error_ = {};
236 2403155 : }
237 :
238 : void Reset(Vector<const uint8_t> bytes, uint32_t buffer_offset = 0) {
239 1752236 : 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 65 : 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 2610022 : return static_cast<uint32_t>(pc - start_) + buffer_offset_;
257 : }
258 2224477 : 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 1415342 : 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 451750 : void verrorf(uint32_t offset, const char* format, va_list args) {
278 : // Only report the first error.
279 683315 : 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 220185 : int len = VSNPrintF(buffer, format, args);
288 220188 : CHECK_LT(0, len);
289 660576 : error_ = {offset, {buffer.start(), static_cast<size_t>(len)}};
290 220196 : onFirstError();
291 : }
292 :
293 : template <typename IntType, bool validate>
294 2293382 : inline IntType read_little_endian(const byte* pc, const char* msg) {
295 : if (!validate) {
296 : DCHECK(validate_size(pc, sizeof(IntType), msg));
297 2293383 : } else if (!validate_size(pc, sizeof(IntType), msg)) {
298 : return IntType{0};
299 : }
300 2293357 : return ReadLittleEndianValue<IntType>(reinterpret_cast<Address>(pc));
301 : }
302 :
303 : template <typename IntType>
304 6430614 : inline IntType consume_little_endian(const char* name) {
305 : TRACE(" +%u %-20s: ", pc_offset(), name);
306 6430614 : if (!checkAvailable(sizeof(IntType))) {
307 : traceOffEnd();
308 15423 : pc_ = end_;
309 : return IntType{0};
310 : }
311 6415248 : IntType val = read_little_endian<IntType, false>(pc_, name);
312 : traceByteRange(pc_, pc_ + sizeof(IntType));
313 : TRACE("= %d\n", val);
314 6415248 : 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 76772730 : name, 0);
326 : }
327 :
328 : template <typename IntType, ValidateFlag validate, AdvancePCFlag advance_pc,
329 : TraceFlag trace, int byte_index>
330 105822620 : 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 40158924 : const bool at_end = validate && pc == end_;
339 : byte b = 0;
340 40158924 : if (!at_end) {
341 : DCHECK_LT(pc, end_);
342 107487907 : b = *pc;
343 : TRACE_IF(trace, "%02x ", b);
344 109177241 : result = result | ((static_cast<IntType>(b) & 0x7f) << shift);
345 : }
346 103082140 : if (!is_last_byte && (b & 0x80)) {
347 : // Make sure that we only instantiate the template for valid byte indexes.
348 : // Compilers are not smart enough to figure out statically that the
349 : // following call is unreachable if is_last_byte is false.
350 : constexpr int next_byte_index = byte_index + (is_last_byte ? 0 : 1);
351 : return read_leb_tail<IntType, validate, advance_pc, trace,
352 30741073 : next_byte_index>(pc + 1, length, name, result);
353 : }
354 9362613 : if (advance_pc) pc_ = pc + (at_end ? 0 : 1);
355 76770089 : *length = byte_index + (at_end ? 0 : 1);
356 20674220 : if (validate && (at_end || (b & 0x80))) {
357 : TRACE_IF(trace, at_end ? "<end> " : "<length overflow> ");
358 23828 : errorf(pc, "expected %s", name);
359 : result = 0;
360 : }
361 : if (is_last_byte) {
362 : // A signed-LEB128 must sign-extend the final byte, excluding its
363 : // most-significant bit; e.g. for a 32-bit LEB128:
364 : // kExtraBits = 4 (== 32 - (5-1) * 7)
365 : // For unsigned values, the extra bits must be all zero.
366 : // For signed values, the extra bits *plus* the most significant bit must
367 : // either be 0, or all ones.
368 : constexpr int kExtraBits = (sizeof(IntType) * 8) - ((kMaxLength - 1) * 7);
369 : constexpr int kSignExtBits = kExtraBits - (is_signed ? 1 : 0);
370 4380267 : const byte checked_bits = b & (0xFF << kSignExtBits);
371 : constexpr byte kSignExtendedExtraBits = 0x7f & (0xFF << kSignExtBits);
372 : bool valid_extra_bits =
373 : checked_bits == 0 ||
374 2747636 : (is_signed && checked_bits == kSignExtendedExtraBits);
375 : if (!validate) {
376 : DCHECK(valid_extra_bits);
377 4430626 : } else if (!valid_extra_bits) {
378 556 : error(pc, "extra bits in varint");
379 : result = 0;
380 : }
381 : }
382 : constexpr int sign_ext_shift =
383 : is_signed ? Max(0, int{8 * sizeof(IntType)} - shift - 7) : 0;
384 : // Perform sign extension.
385 11220297 : result = (result << sign_ext_shift) >> sign_ext_shift;
386 : if (trace && is_signed) {
387 : TRACE("= %" PRIi64 "\n", static_cast<int64_t>(result));
388 : } else if (trace) {
389 : TRACE("= %" PRIu64 "\n", static_cast<uint64_t>(result));
390 : }
391 16243862 : return result;
392 : }
393 : };
394 :
395 : #undef TRACE
396 : } // namespace wasm
397 : } // namespace internal
398 : } // namespace v8
399 :
400 : #endif // V8_WASM_DECODER_H_
|