blob: 0e88eda022de439228b6f862098dff55376ae954 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
14namespace v8 {
15namespace internal {
16namespace 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
Ben Murdoch097c5b22016-05-18 11:27:45 +010027#if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM)
28#define UNALIGNED_ACCESS_OK 1
29#else
30#define UNALIGNED_ACCESS_OK 0
31#endif
32
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000033// A helper utility to decode bytes, integers, fields, varints, etc, from
34// a buffer of bytes.
35class Decoder {
36 public:
37 Decoder(const byte* start, const byte* end)
38 : start_(start),
39 pc_(start),
40 limit_(end),
Ben Murdoch097c5b22016-05-18 11:27:45 +010041 end_(end),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042 error_pc_(nullptr),
43 error_pt_(nullptr) {}
44
45 virtual ~Decoder() {}
46
Ben Murdoch097c5b22016-05-18 11:27:45 +010047 inline bool check(const byte* base, int offset, int length, const char* msg) {
48 DCHECK_GE(base, start_);
49 if ((base + offset + length) > limit_) {
50 error(base, base + offset, msg);
51 return false;
52 }
53 return true;
54 }
55
56 // Reads a single 8-bit byte, reporting an error if out of bounds.
57 inline uint8_t checked_read_u8(const byte* base, int offset,
58 const char* msg = "expected 1 byte") {
59 return check(base, offset, 1, msg) ? base[offset] : 0;
60 }
61
62 // Reads 16-bit word, reporting an error if out of bounds.
63 inline uint16_t checked_read_u16(const byte* base, int offset,
64 const char* msg = "expected 2 bytes") {
65 return check(base, offset, 2, msg) ? read_u16(base + offset) : 0;
66 }
67
68 // Reads 32-bit word, reporting an error if out of bounds.
69 inline uint32_t checked_read_u32(const byte* base, int offset,
70 const char* msg = "expected 4 bytes") {
71 return check(base, offset, 4, msg) ? read_u32(base + offset) : 0;
72 }
73
74 // Reads 64-bit word, reporting an error if out of bounds.
75 inline uint64_t checked_read_u64(const byte* base, int offset,
76 const char* msg = "expected 8 bytes") {
77 return check(base, offset, 8, msg) ? read_u64(base + offset) : 0;
78 }
79
80 uint32_t checked_read_u32v(const byte* base, int offset, int* length,
81 const char* msg = "expected LEB128") {
82 if (!check(base, offset, 1, msg)) {
83 *length = 0;
84 return 0;
85 }
86
87 const ptrdiff_t kMaxDiff = 5; // maximum 5 bytes.
88 const byte* ptr = base + offset;
89 const byte* end = ptr + kMaxDiff;
90 if (end > limit_) end = limit_;
91 int shift = 0;
92 byte b = 0;
93 uint32_t result = 0;
94 while (ptr < end) {
95 b = *ptr++;
96 result = result | ((b & 0x7F) << shift);
97 if ((b & 0x80) == 0) break;
98 shift += 7;
99 }
100 DCHECK_LE(ptr - (base + offset), kMaxDiff);
101 *length = static_cast<int>(ptr - (base + offset));
102 if (ptr == end && (b & 0x80)) {
103 error(base, ptr, msg);
104 return 0;
105 }
106 return result;
107 }
108
109 // Reads a single 16-bit unsigned integer (little endian).
110 inline uint16_t read_u16(const byte* ptr) {
111 DCHECK(ptr >= start_ && (ptr + 2) <= end_);
112#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
113 return *reinterpret_cast<const uint16_t*>(ptr);
114#else
115 uint16_t b0 = ptr[0];
116 uint16_t b1 = ptr[1];
117 return (b1 << 8) | b0;
118#endif
119 }
120
121 // Reads a single 32-bit unsigned integer (little endian).
122 inline uint32_t read_u32(const byte* ptr) {
123 DCHECK(ptr >= start_ && (ptr + 4) <= end_);
124#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
125 return *reinterpret_cast<const uint32_t*>(ptr);
126#else
127 uint32_t b0 = ptr[0];
128 uint32_t b1 = ptr[1];
129 uint32_t b2 = ptr[2];
130 uint32_t b3 = ptr[3];
131 return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
132#endif
133 }
134
135 // Reads a single 64-bit unsigned integer (little endian).
136 inline uint64_t read_u64(const byte* ptr) {
137 DCHECK(ptr >= start_ && (ptr + 8) <= end_);
138#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
139 return *reinterpret_cast<const uint64_t*>(ptr);
140#else
141 uint32_t b0 = ptr[0];
142 uint32_t b1 = ptr[1];
143 uint32_t b2 = ptr[2];
144 uint32_t b3 = ptr[3];
145 uint32_t low = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
146 uint32_t b4 = ptr[4];
147 uint32_t b5 = ptr[5];
148 uint32_t b6 = ptr[6];
149 uint32_t b7 = ptr[7];
150 uint64_t high = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4;
151 return (high << 32) | low;
152#endif
153 }
154
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000155 // Reads a 8-bit unsigned integer (byte) and advances {pc_}.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100156 uint8_t consume_u8(const char* name = nullptr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000157 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
158 name ? name : "uint8_t");
159 if (checkAvailable(1)) {
160 byte val = *(pc_++);
161 TRACE("%02x = %d\n", val, val);
162 return val;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000163 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100164 return traceOffEnd<uint8_t>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000165 }
166
167 // Reads a 16-bit unsigned integer (little endian) and advances {pc_}.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100168 uint16_t consume_u16(const char* name = nullptr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000169 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
170 name ? name : "uint16_t");
171 if (checkAvailable(2)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100172 uint16_t val = read_u16(pc_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000173 TRACE("%02x %02x = %d\n", pc_[0], pc_[1], val);
174 pc_ += 2;
175 return val;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100177 return traceOffEnd<uint16_t>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000178 }
179
180 // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100181 uint32_t consume_u32(const char* name = nullptr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000182 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
183 name ? name : "uint32_t");
184 if (checkAvailable(4)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100185 uint32_t val = read_u32(pc_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000186 TRACE("%02x %02x %02x %02x = %u\n", pc_[0], pc_[1], pc_[2], pc_[3], val);
187 pc_ += 4;
188 return val;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000189 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100190 return traceOffEnd<uint32_t>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000191 }
192
193 // Reads a LEB128 variable-length 32-bit integer and advances {pc_}.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100194 uint32_t consume_u32v(int* length, const char* name = nullptr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000195 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
196 name ? name : "varint");
197
Ben Murdoch097c5b22016-05-18 11:27:45 +0100198 if (checkAvailable(1)) {
199 const byte* pos = pc_;
200 const byte* end = pc_ + 5;
201 if (end > limit_) end = limit_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000202
Ben Murdoch097c5b22016-05-18 11:27:45 +0100203 uint32_t result = 0;
204 int shift = 0;
205 byte b = 0;
206 while (pc_ < end) {
207 b = *pc_++;
208 TRACE("%02x ", b);
209 result = result | ((b & 0x7F) << shift);
210 if ((b & 0x80) == 0) break;
211 shift += 7;
212 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000213
Ben Murdoch097c5b22016-05-18 11:27:45 +0100214 *length = static_cast<int>(pc_ - pos);
215 if (pc_ == end && (b & 0x80)) {
216 error(pc_ - 1, "varint too large");
217 } else {
218 TRACE("= %u\n", result);
219 }
220 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100222 return traceOffEnd<uint32_t>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000223 }
224
225 // Check that at least {size} bytes exist between {pc_} and {limit_}.
226 bool checkAvailable(int size) {
227 if (pc_ < start_ || (pc_ + size) > limit_) {
228 error(pc_, nullptr, "expected %d bytes, fell off end", size);
229 return false;
230 } else {
231 return true;
232 }
233 }
234
Ben Murdoch097c5b22016-05-18 11:27:45 +0100235 bool RangeOk(const byte* pc, int length) {
236 if (pc < start_ || pc_ >= limit_) return false;
237 if ((pc + length) >= limit_) return false;
238 return true;
239 }
240
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000241 void error(const char* msg) { error(pc_, nullptr, msg); }
242
243 void error(const byte* pc, const char* msg) { error(pc, nullptr, msg); }
244
245 // Sets internal error state.
246 void error(const byte* pc, const byte* pt, const char* format, ...) {
247 if (ok()) {
248#if DEBUG
249 if (FLAG_wasm_break_on_decoder_error) {
250 base::OS::DebugBreak();
251 }
252#endif
253 const int kMaxErrorMsg = 256;
254 char* buffer = new char[kMaxErrorMsg];
255 va_list arguments;
256 va_start(arguments, format);
257 base::OS::VSNPrintF(buffer, kMaxErrorMsg - 1, format, arguments);
258 va_end(arguments);
259 error_msg_.Reset(buffer);
260 error_pc_ = pc;
261 error_pt_ = pt;
262 onFirstError();
263 }
264 }
265
266 // Behavior triggered on first error, overridden in subclasses.
267 virtual void onFirstError() {}
268
269 // Debugging helper to print bytes up to the end.
270 template <typename T>
271 T traceOffEnd() {
272 T t = 0;
273 for (const byte* ptr = pc_; ptr < limit_; ptr++) {
274 TRACE("%02x ", *ptr);
275 }
276 TRACE("<end>\n");
277 pc_ = limit_;
278 return t;
279 }
280
281 // Converts the given value to a {Result}, copying the error if necessary.
282 template <typename T>
283 Result<T> toResult(T val) {
284 Result<T> result;
285 if (error_pc_) {
286 result.error_code = kError;
287 result.start = start_;
288 result.error_pc = error_pc_;
289 result.error_pt = error_pt_;
290 result.error_msg = error_msg_;
291 error_msg_.Reset(nullptr);
292 } else {
293 result.error_code = kSuccess;
294 }
295 result.val = val;
296 return result;
297 }
298
299 // Resets the boundaries of this decoder.
300 void Reset(const byte* start, const byte* end) {
301 start_ = start;
302 pc_ = start;
303 limit_ = end;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100304 end_ = end;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000305 error_pc_ = nullptr;
306 error_pt_ = nullptr;
307 error_msg_.Reset(nullptr);
308 }
309
310 bool ok() const { return error_pc_ == nullptr; }
311 bool failed() const { return error_pc_ != nullptr; }
312
313 protected:
314 const byte* start_;
315 const byte* pc_;
316 const byte* limit_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100317 const byte* end_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318 const byte* error_pc_;
319 const byte* error_pt_;
320 base::SmartArrayPointer<char> error_msg_;
321};
322
323#undef TRACE
324} // namespace wasm
325} // namespace internal
326} // namespace v8
327
328#endif // V8_WASM_DECODER_H_