Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(57)

Unified Diff: src/wasm/decoder.h

Issue 1644023002: [wasm] Fix misaligned accesses and endianness issues in decoders. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/wasm/ast-decoder.cc ('k') | src/wasm/module-decoder.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/wasm/decoder.h
diff --git a/src/wasm/decoder.h b/src/wasm/decoder.h
index 698919d6a024eea189aa6efbf0a660cd14d716b6..433e80a186a7f616d5cee2376a0af0e269a7b3b6 100644
--- a/src/wasm/decoder.h
+++ b/src/wasm/decoder.h
@@ -24,6 +24,12 @@ namespace wasm {
#define TRACE(...)
#endif
+#if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM)
+#define UNALIGNED_ACCESS_OK 1
+#else
+#define UNALIGNED_ACCESS_OK 0
+#endif
+
// A helper utility to decode bytes, integers, fields, varints, etc, from
// a buffer of bytes.
class Decoder {
@@ -32,107 +38,126 @@ class Decoder {
: start_(start),
pc_(start),
limit_(end),
+ end_(end),
error_pc_(nullptr),
error_pt_(nullptr) {}
virtual ~Decoder() {}
+ // Reads a single 16-bit unsigned integer (little endian).
+ inline uint16_t read_u16(const byte* ptr) {
+ DCHECK(ptr >= start_ && (ptr + 2) <= end_);
+#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
+ return *reinterpret_cast<const uint16_t*>(ptr);
+#else
+ uint16_t b0 = ptr[0];
+ uint16_t b1 = ptr[1];
+ return (b1 << 8) | b0;
+#endif
+ }
+
+ // Reads a single 32-bit unsigned integer (little endian).
+ inline uint32_t read_u32(const byte* ptr) {
+ DCHECK(ptr >= start_ && (ptr + 4) <= end_);
+#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
+ return *reinterpret_cast<const uint32_t*>(ptr);
+#else
+ uint32_t b0 = ptr[0];
+ uint32_t b1 = ptr[1];
+ uint32_t b2 = ptr[2];
+ uint32_t b3 = ptr[3];
+ return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
+#endif
+ }
+
+ // Reads a single 64-bit unsigned integer (little endian).
+ inline uint64_t read_u64(const byte* ptr) {
+ DCHECK(ptr >= start_ && (ptr + 8) <= end_);
+#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
+ return *reinterpret_cast<const uint64_t*>(ptr);
+#else
+ uint32_t b0 = ptr[0];
+ uint32_t b1 = ptr[1];
+ uint32_t b2 = ptr[2];
+ uint32_t b3 = ptr[3];
+ uint32_t low = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
+ uint32_t b4 = ptr[4];
+ uint32_t b5 = ptr[5];
+ uint32_t b6 = ptr[6];
+ uint32_t b7 = ptr[7];
+ uint64_t high = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4;
+ return (high << 32) | low;
+#endif
+ }
+
// Reads a 8-bit unsigned integer (byte) and advances {pc_}.
- uint8_t u8(const char* name = nullptr) {
+ uint8_t consume_u8(const char* name = nullptr) {
TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
name ? name : "uint8_t");
if (checkAvailable(1)) {
byte val = *(pc_++);
TRACE("%02x = %d\n", val, val);
return val;
- } else {
- error("expected 1 byte, but fell off end");
- return traceOffEnd<uint8_t>();
}
+ return traceOffEnd<uint8_t>();
}
// Reads a 16-bit unsigned integer (little endian) and advances {pc_}.
- uint16_t u16(const char* name = nullptr) {
+ uint16_t consume_u16(const char* name = nullptr) {
TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
name ? name : "uint16_t");
if (checkAvailable(2)) {
-#ifdef V8_TARGET_LITTLE_ENDIAN
- byte b0 = pc_[0];
- byte b1 = pc_[1];
-#else
- byte b1 = pc_[0];
- byte b0 = pc_[1];
-#endif
- uint16_t val = static_cast<uint16_t>(b1 << 8) | b0;
+ uint16_t val = read_u16(pc_);
TRACE("%02x %02x = %d\n", pc_[0], pc_[1], val);
pc_ += 2;
return val;
- } else {
- error("expected 2 bytes, but fell off end");
- return traceOffEnd<uint16_t>();
}
+ return traceOffEnd<uint16_t>();
}
// Reads a single 32-bit unsigned integer (little endian) and advances {pc_}.
- uint32_t u32(const char* name = nullptr) {
+ uint32_t consume_u32(const char* name = nullptr) {
TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
name ? name : "uint32_t");
if (checkAvailable(4)) {
-#ifdef V8_TARGET_LITTLE_ENDIAN
- byte b0 = pc_[0];
- byte b1 = pc_[1];
- byte b2 = pc_[2];
- byte b3 = pc_[3];
-#else
- byte b3 = pc_[0];
- byte b2 = pc_[1];
- byte b1 = pc_[2];
- byte b0 = pc_[3];
-#endif
- uint32_t val = static_cast<uint32_t>(b3 << 24) |
- static_cast<uint32_t>(b2 << 16) |
- static_cast<uint32_t>(b1 << 8) | b0;
+ uint32_t val = read_u32(pc_);
TRACE("%02x %02x %02x %02x = %u\n", pc_[0], pc_[1], pc_[2], pc_[3], val);
pc_ += 4;
return val;
- } else {
- error("expected 4 bytes, but fell off end");
- return traceOffEnd<uint32_t>();
}
+ return traceOffEnd<uint32_t>();
}
// Reads a LEB128 variable-length 32-bit integer and advances {pc_}.
- uint32_t u32v(int* length, const char* name = nullptr) {
+ uint32_t consume_u32v(int* length, const char* name = nullptr) {
TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
name ? name : "varint");
- if (!checkAvailable(1)) {
- error("expected at least 1 byte, but fell off end");
- return traceOffEnd<uint32_t>();
- }
+ if (checkAvailable(1)) {
+ const byte* pos = pc_;
+ const byte* end = pc_ + 5;
+ if (end > limit_) end = limit_;
- const byte* pos = pc_;
- const byte* end = pc_ + 5;
- if (end > limit_) end = limit_;
-
- uint32_t result = 0;
- int shift = 0;
- byte b = 0;
- while (pc_ < end) {
- b = *pc_++;
- TRACE("%02x ", b);
- result = result | ((b & 0x7F) << shift);
- if ((b & 0x80) == 0) break;
- shift += 7;
- }
+ uint32_t result = 0;
+ int shift = 0;
+ byte b = 0;
+ while (pc_ < end) {
+ b = *pc_++;
+ TRACE("%02x ", b);
+ result = result | ((b & 0x7F) << shift);
+ if ((b & 0x80) == 0) break;
+ shift += 7;
+ }
- *length = static_cast<int>(pc_ - pos);
- if (pc_ == end && (b & 0x80)) {
- error(pc_ - 1, "varint too large");
- } else {
- TRACE("= %u\n", result);
+ *length = static_cast<int>(pc_ - pos);
+ if (pc_ == end && (b & 0x80)) {
+ error(pc_ - 1, "varint too large");
+ } else {
+ TRACE("= %u\n", result);
+ }
+ return result;
}
- return result;
+ return traceOffEnd<uint32_t>();
}
// Check that at least {size} bytes exist between {pc_} and {limit_}.
@@ -208,6 +233,7 @@ class Decoder {
start_ = start;
pc_ = start;
limit_ = end;
+ end_ = end;
error_pc_ = nullptr;
error_pt_ = nullptr;
error_msg_.Reset(nullptr);
@@ -220,6 +246,7 @@ class Decoder {
const byte* start_;
const byte* pc_;
const byte* limit_;
+ const byte* end_;
const byte* error_pc_;
const byte* error_pt_;
base::SmartArrayPointer<char> error_msg_;
« no previous file with comments | « src/wasm/ast-decoder.cc ('k') | src/wasm/module-decoder.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698