Index: src/wasm/decoder.h |
diff --git a/src/wasm/decoder.h b/src/wasm/decoder.h |
index 2dfdd02aed912387d75b4c31cef0656a26ca5263..ef7f85f166b09595c8ee6a2b5ff83646c10ed4e4 100644 |
--- a/src/wasm/decoder.h |
+++ b/src/wasm/decoder.h |
@@ -77,53 +77,44 @@ class Decoder { |
return check(base, offset, 8, msg) ? read_u64(base + offset) : 0; |
} |
+ // Reads a variable-length unsigned integer (little endian). |
uint32_t checked_read_u32v(const byte* base, int offset, int* length, |
- const char* msg = "expected LEB128") { |
- if (!check(base, offset, 1, msg)) { |
- *length = 0; |
- return 0; |
- } |
- |
- const ptrdiff_t kMaxDiff = 5; // maximum 5 bytes. |
- const byte* ptr = base + offset; |
- const byte* end = ptr + kMaxDiff; |
- if (end > limit_) end = limit_; |
- int shift = 0; |
- byte b = 0; |
- uint32_t result = 0; |
- while (ptr < end) { |
- b = *ptr++; |
- result = result | ((b & 0x7F) << shift); |
- if ((b & 0x80) == 0) break; |
- shift += 7; |
- } |
- DCHECK_LE(ptr - (base + offset), kMaxDiff); |
- *length = static_cast<int>(ptr - (base + offset)); |
- if (ptr == end) { |
- if (*length == kMaxDiff && (b & 0xF0) != 0) { |
- error(base, ptr, "extra bits in LEB128"); |
- return 0; |
- } |
- if ((b & 0x80) != 0) { |
- error(base, ptr, msg); |
- return 0; |
- } |
- } |
- return result; |
+ const char* msg = "expected LEB32") { |
+ return checked_read_leb<uint32_t>(base, offset, length, msg); |
} |
// Reads a variable-length signed integer (little endian). |
int32_t checked_read_i32v(const byte* base, int offset, int* length, |
- const char* msg = "expected SLEB128") { |
+ const char* msg = "expected SLEB32") { |
uint32_t result = checked_read_u32v(base, offset, length, msg); |
if (*length == 5) return bit_cast<int32_t>(result); |
if (*length > 0) { |
int shift = 32 - 7 * *length; |
+ // Perform sign extension. |
return bit_cast<int32_t>(result << shift) >> shift; |
} |
return 0; |
} |
+ // Reads a variable-length unsigned integer (little endian). |
+ uint64_t checked_read_u64v(const byte* base, int offset, int* length, |
+ const char* msg = "expected LEB64") { |
+ return checked_read_leb<uint64_t>(base, offset, length, msg); |
+ } |
+ |
+ // Reads a variable-length signed integer (little endian). |
+ int64_t checked_read_i64v(const byte* base, int offset, int* length, |
+ const char* msg = "expected SLEB64") { |
+ uint64_t result = checked_read_u64v(base, offset, length, msg); |
+ if (*length == 10) return bit_cast<int64_t>(result); |
+ if (*length > 0) { |
+ int shift = 64 - 7 * *length; |
+ // Perform sign extension. |
+ return bit_cast<int64_t>(result << shift) >> shift; |
+ } |
+ return 0; |
+ } |
+ |
// Reads a single 16-bit unsigned integer (little endian). |
inline uint16_t read_u16(const byte* ptr) { |
DCHECK(ptr >= start_ && (ptr + 2) <= end_); |
@@ -333,6 +324,47 @@ class Decoder { |
const byte* error_pc_; |
const byte* error_pt_; |
base::SmartArrayPointer<char> error_msg_; |
+ |
+ private: |
+ template <typename IntType> |
+ IntType checked_read_leb(const byte* base, int offset, int* length, |
+ const char* msg) { |
+ if (!check(base, offset, 1, msg)) { |
+ *length = 0; |
+ return 0; |
+ } |
+ |
+ const int kMaxLength = (sizeof(IntType) * 8 + 6) / 7; |
+ const byte* ptr = base + offset; |
+ const byte* end = ptr + kMaxLength; |
+ if (end > limit_) end = limit_; |
+ int shift = 0; |
+ byte b = 0; |
+ IntType result = 0; |
+ while (ptr < end) { |
+ b = *ptr++; |
+ result = result | (static_cast<IntType>(b & 0x7F) << shift); |
+ if ((b & 0x80) == 0) break; |
+ shift += 7; |
+ } |
+ DCHECK_LE(ptr - (base + offset), kMaxLength); |
+ *length = static_cast<int>(ptr - (base + offset)); |
+ if (ptr == end) { |
+ // Check there are no bits set beyond the bitwidth of {IntType}. |
+ const int kExtraBits = (1 + kMaxLength * 7) - (sizeof(IntType) * 8); |
+ const byte kExtraBitsMask = |
+ static_cast<byte>((0xFF << (8 - kExtraBits)) & 0xFF); |
+ if (*length == kMaxLength && (b & kExtraBitsMask) != 0) { |
+ error(base, ptr, "extra bits in varint"); |
+ return 0; |
+ } |
+ if ((b & 0x80) != 0) { |
+ error(base, ptr, msg); |
+ return 0; |
+ } |
+ } |
+ return result; |
+ } |
}; |
#undef TRACE |