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/v8memory.h"
16 : #include "src/vector.h"
17 : #include "src/wasm/wasm-result.h"
18 : #include "src/zone/zone-containers.h"
19 :
20 : namespace v8 {
21 : namespace internal {
22 : namespace wasm {
23 :
24 : #define TRACE(...) \
25 : do { \
26 : if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
27 : } while (false)
28 : #define TRACE_IF(cond, ...) \
29 : do { \
30 : if (FLAG_trace_wasm_decoder && (cond)) PrintF(__VA_ARGS__); \
31 : } while (false)
32 :
33 : // A {DecodeResult} only stores the failure / success status, but no data.
34 : using DecodeResult = VoidResult;
35 :
36 : // A helper utility to decode bytes, integers, fields, varints, etc, from
37 : // a buffer of bytes.
38 : class Decoder {
39 : public:
40 : enum ValidateFlag : bool { kValidate = true, kNoValidate = false };
41 :
42 : enum AdvancePCFlag : bool { kAdvancePc = true, kNoAdvancePc = false };
43 :
44 : enum TraceFlag : bool { kTrace = true, kNoTrace = false };
45 :
46 : Decoder(const byte* start, const byte* end, uint32_t buffer_offset = 0)
47 : : Decoder(start, start, end, buffer_offset) {}
48 : explicit Decoder(const Vector<const byte> bytes, uint32_t buffer_offset = 0)
49 3769 : : Decoder(bytes.start(), bytes.start() + bytes.length(), buffer_offset) {}
50 : Decoder(const byte* start, const byte* pc, const byte* end,
51 : uint32_t buffer_offset = 0)
52 11459183 : : start_(start), pc_(pc), end_(end), buffer_offset_(buffer_offset) {
53 : DCHECK_LE(start, pc);
54 : DCHECK_LE(pc, end);
55 : DCHECK_EQ(static_cast<uint32_t>(end - start), end - start);
56 : }
57 :
58 22792598 : virtual ~Decoder() = default;
59 :
60 : inline bool validate_size(const byte* pc, uint32_t length, const char* msg) {
61 : DCHECK_LE(start_, pc);
62 1820943 : if (V8_UNLIKELY(pc > end_ || length > static_cast<uint32_t>(end_ - pc))) {
63 34 : 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 : 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 : 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 : 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 5385487 : 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 572649 : 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 7868617 : uint32_t length = 0;
146 4063010 : return read_leb<uint32_t, kValidate, kAdvancePc, kTrace>(pc_, &length,
147 : 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 691 : uint32_t length = 0;
153 691 : 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 3213396 : 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 3213401 : if (checkAvailable(size)) {
161 3211835 : pc_ += size;
162 : } else {
163 1566 : pc_ = end_;
164 : }
165 3213401 : }
166 :
167 : // Check that at least {size} bytes exist between {pc_} and {end_}.
168 : bool checkAvailable(uint32_t size) {
169 : DCHECK_LE(pc_, end_);
170 10669390 : if (V8_UNLIKELY(size > static_cast<uint32_t>(end_ - pc_))) {
171 127152 : errorf(pc_, "expected %u bytes, fell off end", size);
172 : return false;
173 : }
174 : return true;
175 : }
176 :
177 : // Do not inline error methods. This has measurable impact on validation time,
178 : // see https://crbug.com/910432.
179 100328 : void V8_NOINLINE error(const char* msg) { errorf(pc_offset(), "%s", msg); }
180 13114 : void V8_NOINLINE error(const uint8_t* pc, const char* msg) {
181 13114 : errorf(pc_offset(pc), "%s", msg);
182 13115 : }
183 : void V8_NOINLINE error(uint32_t offset, const char* msg) {
184 : errorf(offset, "%s", msg);
185 : }
186 :
187 : void V8_NOINLINE PRINTF_FORMAT(3, 4)
188 79195 : errorf(uint32_t offset, const char* format, ...) {
189 : va_list args;
190 79195 : va_start(args, format);
191 79195 : verrorf(offset, format, args);
192 79108 : va_end(args);
193 79108 : }
194 :
195 : void V8_NOINLINE PRINTF_FORMAT(3, 4)
196 352418 : errorf(const uint8_t* pc, const char* format, ...) {
197 : va_list args;
198 352418 : va_start(args, format);
199 352418 : verrorf(pc_offset(pc), format, args);
200 352445 : va_end(args);
201 352445 : }
202 :
203 : // Behavior triggered on first error, overridden in subclasses.
204 132674 : virtual void onFirstError() {}
205 :
206 : // Debugging helper to print a bytes range as hex bytes.
207 : void traceByteRange(const byte* start, const byte* end) {
208 : DCHECK_LE(start, end);
209 : for (const byte* p = start; p < end; ++p) TRACE("%02x ", *p);
210 : }
211 :
212 : // Debugging helper to print bytes up to the end.
213 : void traceOffEnd() {
214 : traceByteRange(pc_, end_);
215 : TRACE("<end>\n");
216 : }
217 :
218 : // Converts the given value to a {Result}, copying the error if necessary.
219 : template <typename T, typename U = typename std::remove_reference<T>::type>
220 1081212 : Result<U> toResult(T&& val) {
221 1081212 : if (failed()) {
222 : TRACE("Result error: %s\n", error_.message().c_str());
223 123171 : return Result<U>{error_};
224 : }
225 1019642 : return Result<U>{std::forward<T>(val)};
226 : }
227 :
228 : // Resets the boundaries of this decoder.
229 2313231 : void Reset(const byte* start, const byte* end, uint32_t buffer_offset = 0) {
230 : DCHECK_LE(start, end);
231 : DCHECK_EQ(static_cast<uint32_t>(end - start), end - start);
232 2313231 : start_ = start;
233 2313231 : pc_ = start;
234 2313231 : end_ = end;
235 2313231 : buffer_offset_ = buffer_offset;
236 4626470 : error_ = {};
237 2313239 : }
238 :
239 : void Reset(Vector<const uint8_t> bytes, uint32_t buffer_offset = 0) {
240 1581308 : Reset(bytes.begin(), bytes.end(), buffer_offset);
241 : }
242 :
243 : bool ok() const { return error_.empty(); }
244 : bool failed() const { return !ok(); }
245 : bool more() const { return pc_ < end_; }
246 : const WasmError& error() const { return error_; }
247 :
248 : const byte* start() const { return start_; }
249 : const byte* pc() const { return pc_; }
250 : uint32_t V8_INLINE position() const {
251 264 : return static_cast<uint32_t>(pc_ - start_);
252 : }
253 : // This needs to be inlined for performance (see https://crbug.com/910432).
254 : uint32_t V8_INLINE pc_offset(const uint8_t* pc) const {
255 : DCHECK_LE(start_, pc);
256 : DCHECK_GE(kMaxUInt32 - buffer_offset_, pc - start_);
257 2327846 : return static_cast<uint32_t>(pc - start_) + buffer_offset_;
258 : }
259 1961922 : uint32_t pc_offset() const { return pc_offset(pc_); }
260 : uint32_t buffer_offset() const { return buffer_offset_; }
261 : // Takes an offset relative to the module start and returns an offset relative
262 : // to the current buffer of the decoder.
263 : uint32_t GetBufferRelativeOffset(uint32_t offset) const {
264 : DCHECK_LE(buffer_offset_, offset);
265 1265856 : return offset - buffer_offset_;
266 : }
267 : const byte* end() const { return end_; }
268 :
269 : protected:
270 : const byte* start_;
271 : const byte* pc_;
272 : const byte* end_;
273 : // The offset of the current buffer in the module. Needed for streaming.
274 : uint32_t buffer_offset_;
275 : WasmError error_;
276 :
277 : private:
278 431580 : void verrorf(uint32_t offset, const char* format, va_list args) {
279 : // Only report the first error.
280 653086 : if (!ok()) return;
281 : #if DEBUG
282 : if (FLAG_wasm_break_on_decoder_error) {
283 : base::OS::DebugBreak();
284 : }
285 : #endif
286 : constexpr int kMaxErrorMsg = 256;
287 : EmbeddedVector<char, kMaxErrorMsg> buffer;
288 210074 : int len = VSNPrintF(buffer, format, args);
289 210146 : CHECK_LT(0, len);
290 630530 : error_ = {offset, {buffer.start(), static_cast<size_t>(len)}};
291 210192 : onFirstError();
292 : }
293 :
294 : template <typename IntType, bool validate>
295 : inline IntType read_little_endian(const byte* pc, const char* msg) {
296 : if (!validate) {
297 : DCHECK(validate_size(pc, sizeof(IntType), msg));
298 1821095 : } else if (!validate_size(pc, sizeof(IntType), msg)) {
299 : return IntType{0};
300 : }
301 : return ReadLittleEndianValue<IntType>(reinterpret_cast<Address>(pc));
302 : }
303 :
304 : template <typename IntType>
305 5958114 : inline IntType consume_little_endian(const char* name) {
306 : TRACE(" +%u %-20s: ", pc_offset(), name);
307 5958119 : if (!checkAvailable(sizeof(IntType))) {
308 : traceOffEnd();
309 13750 : pc_ = end_;
310 : return IntType{0};
311 : }
312 5944369 : IntType val = read_little_endian<IntType, false>(pc_, name);
313 : traceByteRange(pc_, pc_ + sizeof(IntType));
314 : TRACE("= %d\n", val);
315 5944369 : pc_ += sizeof(IntType);
316 : return val;
317 : }
318 :
319 : template <typename IntType, ValidateFlag validate, AdvancePCFlag advance_pc,
320 : TraceFlag trace>
321 : inline IntType read_leb(const byte* pc, uint32_t* length,
322 : const char* name = "varint") {
323 : DCHECK_IMPLIES(advance_pc, pc == pc_);
324 : TRACE_IF(trace, " +%u %-20s: ", pc_offset(), name);
325 : return read_leb_tail<IntType, validate, advance_pc, trace, 0>(pc, length,
326 24500704 : name, 0);
327 : }
328 :
329 : template <typename IntType, ValidateFlag validate, AdvancePCFlag advance_pc,
330 : TraceFlag trace, int byte_index>
331 44566417 : IntType read_leb_tail(const byte* pc, uint32_t* length, const char* name,
332 : IntType result) {
333 : constexpr bool is_signed = std::is_signed<IntType>::value;
334 : constexpr int kMaxLength = (sizeof(IntType) * 8 + 6) / 7;
335 : static_assert(byte_index < kMaxLength, "invalid template instantiation");
336 : constexpr int shift = byte_index * 7;
337 : constexpr bool is_last_byte = byte_index == kMaxLength - 1;
338 29303248 : const bool at_end = validate && pc >= end_;
339 : byte b = 0;
340 29303248 : if (!at_end) {
341 : DCHECK_LT(pc, end_);
342 79435810 : b = *pc;
343 : TRACE_IF(trace, "%02x ", b);
344 : using Unsigned = typename std::make_unsigned<IntType>::type;
345 81078966 : result = result |
346 : (static_cast<Unsigned>(static_cast<IntType>(b) & 0x7f) << shift);
347 : }
348 76425876 : 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 20068769 : next_byte_index>(pc + 1, length, name, result);
355 : }
356 7869600 : if (advance_pc) pc_ = pc + (at_end ? 0 : 1);
357 56099158 : *length = byte_index + (at_end ? 0 : 1);
358 15825684 : if (validate && (at_end || (b & 0x80))) {
359 : TRACE_IF(trace, at_end ? "<end> " : "<length overflow> ");
360 23783 : 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 2985572 : const byte checked_bits = b & (0xFF << kSignExtBits);
373 : constexpr byte kSignExtendedExtraBits = 0x7f & (0xFF << kSignExtBits);
374 : bool valid_extra_bits =
375 : checked_bits == 0 ||
376 1524077 : (is_signed && checked_bits == kSignExtendedExtraBits);
377 : if (!validate) {
378 : DCHECK(valid_extra_bits);
379 3034731 : } 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 9061629 : 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 12791471 : return result;
394 : }
395 : };
396 :
397 : #undef TRACE
398 : } // namespace wasm
399 : } // namespace internal
400 : } // namespace v8
401 :
402 : #endif // V8_WASM_DECODER_H_
|