OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_WASM_DECODER_H_ | 5 #ifndef V8_WASM_DECODER_H_ |
6 #define V8_WASM_DECODER_H_ | 6 #define V8_WASM_DECODER_H_ |
7 | 7 |
8 #include <memory> | 8 #include <memory> |
9 | 9 |
10 #include "src/base/compiler-specific.h" | 10 #include "src/base/compiler-specific.h" |
(...skipping 16 matching lines...) Expand all Loading... |
27 #define TRACE(...) | 27 #define TRACE(...) |
28 #endif | 28 #endif |
29 | 29 |
30 // A helper utility to decode bytes, integers, fields, varints, etc, from | 30 // A helper utility to decode bytes, integers, fields, varints, etc, from |
31 // a buffer of bytes. | 31 // a buffer of bytes. |
32 class Decoder { | 32 class Decoder { |
33 public: | 33 public: |
34 Decoder(const byte* start, const byte* end) | 34 Decoder(const byte* start, const byte* end) |
35 : start_(start), | 35 : start_(start), |
36 pc_(start), | 36 pc_(start), |
37 limit_(end), | |
38 end_(end), | 37 end_(end), |
39 error_pc_(nullptr), | 38 error_pc_(nullptr), |
40 error_pt_(nullptr) {} | 39 error_pt_(nullptr) {} |
41 | 40 |
42 virtual ~Decoder() {} | 41 virtual ~Decoder() {} |
43 | 42 |
44 inline bool check(const byte* base, unsigned offset, unsigned length, | 43 inline bool check(const byte* base, unsigned offset, unsigned length, |
45 const char* msg) { | 44 const char* msg) { |
46 DCHECK_GE(base, start_); | 45 DCHECK_GE(base, start_); |
47 if ((base + offset + length) > limit_) { | 46 if ((base + offset + length) > end_) { |
48 error(base, base + offset, "%s", msg); | 47 error(base, base + offset, "%s", msg); |
49 return false; | 48 return false; |
50 } | 49 } |
51 return true; | 50 return true; |
52 } | 51 } |
53 | 52 |
54 // Reads a single 8-bit byte, reporting an error if out of bounds. | 53 // Reads a single 8-bit byte, reporting an error if out of bounds. |
55 inline uint8_t checked_read_u8(const byte* base, unsigned offset, | 54 inline uint8_t checked_read_u8(const byte* base, unsigned offset, |
56 const char* msg = "expected 1 byte") { | 55 const char* msg = "expected 1 byte") { |
57 return check(base, offset, 1, msg) ? base[offset] : 0; | 56 return check(base, offset, 1, msg) ? base[offset] : 0; |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 return consume_leb<int32_t, true>(name); | 182 return consume_leb<int32_t, true>(name); |
184 } | 183 } |
185 | 184 |
186 // Consume {size} bytes and send them to the bit bucket, advancing {pc_}. | 185 // Consume {size} bytes and send them to the bit bucket, advancing {pc_}. |
187 void consume_bytes(uint32_t size, const char* name = "skip") { | 186 void consume_bytes(uint32_t size, const char* name = "skip") { |
188 TRACE(" +%d %-20s: %d bytes\n", static_cast<int>(pc_ - start_), name, | 187 TRACE(" +%d %-20s: %d bytes\n", static_cast<int>(pc_ - start_), name, |
189 size); | 188 size); |
190 if (checkAvailable(size)) { | 189 if (checkAvailable(size)) { |
191 pc_ += size; | 190 pc_ += size; |
192 } else { | 191 } else { |
193 pc_ = limit_; | 192 pc_ = end_; |
194 } | 193 } |
195 } | 194 } |
196 | 195 |
197 // Check that at least {size} bytes exist between {pc_} and {limit_}. | 196 // Check that at least {size} bytes exist between {pc_} and {end_}. |
198 bool checkAvailable(int size) { | 197 bool checkAvailable(int size) { |
199 intptr_t pc_overflow_value = std::numeric_limits<intptr_t>::max() - size; | 198 intptr_t pc_overflow_value = std::numeric_limits<intptr_t>::max() - size; |
200 if (size < 0 || (intptr_t)pc_ > pc_overflow_value) { | 199 if (size < 0 || (intptr_t)pc_ > pc_overflow_value) { |
201 error(pc_, nullptr, "reading %d bytes would underflow/overflow", size); | 200 error(pc_, nullptr, "reading %d bytes would underflow/overflow", size); |
202 return false; | 201 return false; |
203 } else if (pc_ < start_ || limit_ < (pc_ + size)) { | 202 } else if (pc_ < start_ || end_ < (pc_ + size)) { |
204 error(pc_, nullptr, "expected %d bytes, fell off end", size); | 203 error(pc_, nullptr, "expected %d bytes, fell off end", size); |
205 return false; | 204 return false; |
206 } else { | 205 } else { |
207 return true; | 206 return true; |
208 } | 207 } |
209 } | 208 } |
210 | 209 |
211 void error(const char* msg) { error(pc_, nullptr, "%s", msg); } | 210 void error(const char* msg) { error(pc_, nullptr, "%s", msg); } |
212 | 211 |
213 void error(const byte* pc, const char* msg) { error(pc, nullptr, "%s", msg); } | 212 void error(const byte* pc, const char* msg) { error(pc, nullptr, "%s", msg); } |
(...skipping 20 matching lines...) Expand all Loading... |
234 } | 233 } |
235 } | 234 } |
236 | 235 |
237 // Behavior triggered on first error, overridden in subclasses. | 236 // Behavior triggered on first error, overridden in subclasses. |
238 virtual void onFirstError() {} | 237 virtual void onFirstError() {} |
239 | 238 |
240 // Debugging helper to print bytes up to the end. | 239 // Debugging helper to print bytes up to the end. |
241 template <typename T> | 240 template <typename T> |
242 T traceOffEnd() { | 241 T traceOffEnd() { |
243 T t = 0; | 242 T t = 0; |
244 for (const byte* ptr = pc_; ptr < limit_; ptr++) { | 243 for (const byte* ptr = pc_; ptr < end_; ptr++) { |
245 TRACE("%02x ", *ptr); | 244 TRACE("%02x ", *ptr); |
246 } | 245 } |
247 TRACE("<end>\n"); | 246 TRACE("<end>\n"); |
248 pc_ = limit_; | 247 pc_ = end_; |
249 return t; | 248 return t; |
250 } | 249 } |
251 | 250 |
252 // Converts the given value to a {Result}, copying the error if necessary. | 251 // Converts the given value to a {Result}, copying the error if necessary. |
253 template <typename T> | 252 template <typename T> |
254 Result<T> toResult(T val) { | 253 Result<T> toResult(T val) { |
255 Result<T> result; | 254 Result<T> result; |
256 if (failed()) { | 255 if (failed()) { |
257 TRACE("Result error: %s\n", error_msg_.get()); | 256 TRACE("Result error: %s\n", error_msg_.get()); |
258 result.error_code = kError; | 257 result.error_code = kError; |
259 result.start = start_; | 258 result.start = start_; |
260 result.error_pc = error_pc_; | 259 result.error_pc = error_pc_; |
261 result.error_pt = error_pt_; | 260 result.error_pt = error_pt_; |
262 // transfer ownership of the error to the result. | 261 // transfer ownership of the error to the result. |
263 result.error_msg.reset(error_msg_.release()); | 262 result.error_msg.reset(error_msg_.release()); |
264 } else { | 263 } else { |
265 result.error_code = kSuccess; | 264 result.error_code = kSuccess; |
266 } | 265 } |
267 result.val = std::move(val); | 266 result.val = std::move(val); |
268 return result; | 267 return result; |
269 } | 268 } |
270 | 269 |
271 // Resets the boundaries of this decoder. | 270 // Resets the boundaries of this decoder. |
272 void Reset(const byte* start, const byte* end) { | 271 void Reset(const byte* start, const byte* end) { |
273 start_ = start; | 272 start_ = start; |
274 pc_ = start; | 273 pc_ = start; |
275 limit_ = end; | |
276 end_ = end; | 274 end_ = end; |
277 error_pc_ = nullptr; | 275 error_pc_ = nullptr; |
278 error_pt_ = nullptr; | 276 error_pt_ = nullptr; |
279 error_msg_.reset(); | 277 error_msg_.reset(); |
280 } | 278 } |
281 | 279 |
282 bool ok() const { return error_msg_ == nullptr; } | 280 bool ok() const { return error_msg_ == nullptr; } |
283 bool failed() const { return !ok(); } | 281 bool failed() const { return !ok(); } |
284 bool more() const { return pc_ < limit_; } | 282 bool more() const { return pc_ < end_; } |
285 | 283 |
286 const byte* start() { return start_; } | 284 const byte* start() { return start_; } |
287 const byte* pc() { return pc_; } | 285 const byte* pc() { return pc_; } |
288 uint32_t pc_offset() { return static_cast<uint32_t>(pc_ - start_); } | 286 uint32_t pc_offset() { return static_cast<uint32_t>(pc_ - start_); } |
289 | 287 |
290 protected: | 288 protected: |
291 const byte* start_; | 289 const byte* start_; |
292 const byte* pc_; | 290 const byte* pc_; |
293 const byte* limit_; | |
294 const byte* end_; | 291 const byte* end_; |
295 const byte* error_pc_; | 292 const byte* error_pc_; |
296 const byte* error_pt_; | 293 const byte* error_pt_; |
297 std::unique_ptr<char[]> error_msg_; | 294 std::unique_ptr<char[]> error_msg_; |
298 | 295 |
299 private: | 296 private: |
300 template <typename IntType, bool is_signed> | 297 template <typename IntType, bool is_signed> |
301 IntType checked_read_leb(const byte* base, unsigned offset, unsigned* length, | 298 IntType checked_read_leb(const byte* base, unsigned offset, unsigned* length, |
302 const char* msg) { | 299 const char* msg) { |
303 if (!check(base, offset, 1, msg)) { | 300 if (!check(base, offset, 1, msg)) { |
304 *length = 0; | 301 *length = 0; |
305 return 0; | 302 return 0; |
306 } | 303 } |
307 | 304 |
308 const int kMaxLength = (sizeof(IntType) * 8 + 6) / 7; | 305 const int kMaxLength = (sizeof(IntType) * 8 + 6) / 7; |
309 const byte* ptr = base + offset; | 306 const byte* ptr = base + offset; |
310 const byte* end = ptr + kMaxLength; | 307 const byte* end = ptr + kMaxLength; |
311 if (end > limit_) end = limit_; | 308 if (end > end_) end = end_; |
312 int shift = 0; | 309 int shift = 0; |
313 byte b = 0; | 310 byte b = 0; |
314 IntType result = 0; | 311 IntType result = 0; |
315 while (ptr < end) { | 312 while (ptr < end) { |
316 b = *ptr++; | 313 b = *ptr++; |
317 result = result | (static_cast<IntType>(b & 0x7F) << shift); | 314 result = result | (static_cast<IntType>(b & 0x7F) << shift); |
318 if ((b & 0x80) == 0) break; | 315 if ((b & 0x80) == 0) break; |
319 shift += 7; | 316 shift += 7; |
320 } | 317 } |
321 DCHECK_LE(ptr - (base + offset), kMaxLength); | 318 DCHECK_LE(ptr - (base + offset), kMaxLength); |
(...skipping 29 matching lines...) Expand all Loading... |
351 } | 348 } |
352 | 349 |
353 template <typename IntType, bool is_signed> | 350 template <typename IntType, bool is_signed> |
354 IntType consume_leb(const char* name = nullptr) { | 351 IntType consume_leb(const char* name = nullptr) { |
355 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), | 352 TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_), |
356 name ? name : "varint"); | 353 name ? name : "varint"); |
357 if (checkAvailable(1)) { | 354 if (checkAvailable(1)) { |
358 const int kMaxLength = (sizeof(IntType) * 8 + 6) / 7; | 355 const int kMaxLength = (sizeof(IntType) * 8 + 6) / 7; |
359 const byte* pos = pc_; | 356 const byte* pos = pc_; |
360 const byte* end = pc_ + kMaxLength; | 357 const byte* end = pc_ + kMaxLength; |
361 if (end > limit_) end = limit_; | 358 if (end > end_) end = end_; |
362 | 359 |
363 IntType result = 0; | 360 IntType result = 0; |
364 int shift = 0; | 361 int shift = 0; |
365 byte b = 0; | 362 byte b = 0; |
366 while (pc_ < end) { | 363 while (pc_ < end) { |
367 b = *pc_++; | 364 b = *pc_++; |
368 TRACE("%02x ", b); | 365 TRACE("%02x ", b); |
369 result = result | (static_cast<IntType>(b & 0x7F) << shift); | 366 result = result | (static_cast<IntType>(b & 0x7F) << shift); |
370 shift += 7; | 367 shift += 7; |
371 if ((b & 0x80) == 0) break; | 368 if ((b & 0x80) == 0) break; |
(...skipping 19 matching lines...) Expand all Loading... |
391 return traceOffEnd<uint32_t>(); | 388 return traceOffEnd<uint32_t>(); |
392 } | 389 } |
393 }; | 390 }; |
394 | 391 |
395 #undef TRACE | 392 #undef TRACE |
396 } // namespace wasm | 393 } // namespace wasm |
397 } // namespace internal | 394 } // namespace internal |
398 } // namespace v8 | 395 } // namespace v8 |
399 | 396 |
400 #endif // V8_WASM_DECODER_H_ | 397 #endif // V8_WASM_DECODER_H_ |
OLD | NEW |