[wasm] Fix misaligned accesses and endianness issues in decoders.
R=ahaas@chromium.org,bradnelson@chromium.org BUG= Review URL: https://codereview.chromium.org/1644023002 Cr-Commit-Position: refs/heads/master@{#33595}
This commit is contained in:
parent
6399fce56b
commit
716bc803a3
@ -112,28 +112,28 @@ class WasmDecoder : public Decoder {
|
||||
function_env_ = function_env;
|
||||
}
|
||||
|
||||
// Load an operand at [pc + 1].
|
||||
template <typename V>
|
||||
V Operand(const byte* pc) {
|
||||
if ((limit_ - pc) < static_cast<int>(1 + sizeof(V))) {
|
||||
const char* msg = "Expected operand following opcode";
|
||||
switch (sizeof(V)) {
|
||||
case 1:
|
||||
msg = "Expected 1-byte operand following opcode";
|
||||
break;
|
||||
case 2:
|
||||
msg = "Expected 2-byte operand following opcode";
|
||||
break;
|
||||
case 4:
|
||||
msg = "Expected 4-byte operand following opcode";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
byte ByteOperand(const byte* pc, const char* msg = "missing 1-byte operand") {
|
||||
if ((pc + sizeof(byte)) >= limit_) {
|
||||
error(pc, msg);
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
return *reinterpret_cast<const V*>(pc + 1);
|
||||
return pc[1];
|
||||
}
|
||||
|
||||
uint32_t Uint32Operand(const byte* pc) {
|
||||
if ((pc + sizeof(uint32_t)) >= limit_) {
|
||||
error(pc, "missing 4-byte operand");
|
||||
return 0;
|
||||
}
|
||||
return read_u32(pc + 1);
|
||||
}
|
||||
|
||||
uint64_t Uint64Operand(const byte* pc) {
|
||||
if ((pc + sizeof(uint64_t)) >= limit_) {
|
||||
error(pc, "missing 8-byte operand");
|
||||
return 0;
|
||||
}
|
||||
return read_u64(pc + 1);
|
||||
}
|
||||
|
||||
LocalType LocalOperand(const byte* pc, uint32_t* index, int* length) {
|
||||
@ -185,7 +185,7 @@ class WasmDecoder : public Decoder {
|
||||
}
|
||||
|
||||
void MemoryAccessOperand(const byte* pc, int* length, uint32_t* offset) {
|
||||
byte bitfield = Operand<uint8_t>(pc);
|
||||
byte bitfield = ByteOperand(pc, "missing memory access operand");
|
||||
if (MemoryAccess::OffsetField::decode(bitfield)) {
|
||||
*offset = UnsignedLEB128Operand(pc + 1, length);
|
||||
(*length)++; // to account for the memory access byte
|
||||
@ -431,7 +431,7 @@ class LR_WasmDecoder : public WasmDecoder {
|
||||
Leaf(kAstStmt);
|
||||
break;
|
||||
case kExprBlock: {
|
||||
int length = Operand<uint8_t>(pc_);
|
||||
int length = ByteOperand(pc_);
|
||||
if (length < 1) {
|
||||
Leaf(kAstStmt);
|
||||
} else {
|
||||
@ -445,7 +445,7 @@ class LR_WasmDecoder : public WasmDecoder {
|
||||
break;
|
||||
}
|
||||
case kExprLoop: {
|
||||
int length = Operand<uint8_t>(pc_);
|
||||
int length = ByteOperand(pc_);
|
||||
if (length < 1) {
|
||||
Leaf(kAstStmt);
|
||||
} else {
|
||||
@ -474,7 +474,7 @@ class LR_WasmDecoder : public WasmDecoder {
|
||||
Shift(kAstStmt, 3); // Result type is typeof(x) in {c ? x : y}.
|
||||
break;
|
||||
case kExprBr: {
|
||||
uint32_t depth = Operand<uint8_t>(pc_);
|
||||
uint32_t depth = ByteOperand(pc_);
|
||||
Shift(kAstEnd, 1);
|
||||
if (depth >= blocks_.size()) {
|
||||
error("improperly nested branch");
|
||||
@ -483,7 +483,7 @@ class LR_WasmDecoder : public WasmDecoder {
|
||||
break;
|
||||
}
|
||||
case kExprBrIf: {
|
||||
uint32_t depth = Operand<uint8_t>(pc_);
|
||||
uint32_t depth = ByteOperand(pc_);
|
||||
Shift(kAstStmt, 2);
|
||||
if (depth >= blocks_.size()) {
|
||||
error("improperly nested conditional branch");
|
||||
@ -496,8 +496,8 @@ class LR_WasmDecoder : public WasmDecoder {
|
||||
error("expected #tableswitch <cases> <table>, fell off end");
|
||||
break;
|
||||
}
|
||||
uint16_t case_count = *reinterpret_cast<const uint16_t*>(pc_ + 1);
|
||||
uint16_t table_count = *reinterpret_cast<const uint16_t*>(pc_ + 3);
|
||||
uint16_t case_count = read_u16(pc_ + 1);
|
||||
uint16_t table_count = read_u16(pc_ + 3);
|
||||
len = 5 + table_count * 2;
|
||||
|
||||
if (table_count == 0) {
|
||||
@ -514,8 +514,7 @@ class LR_WasmDecoder : public WasmDecoder {
|
||||
|
||||
// Verify table.
|
||||
for (int i = 0; i < table_count; i++) {
|
||||
uint16_t target =
|
||||
*reinterpret_cast<const uint16_t*>(pc_ + 5 + i * 2);
|
||||
uint16_t target = read_u16(pc_ + 5 + i * 2);
|
||||
if (target >= 0x8000) {
|
||||
size_t depth = target - 0x8000;
|
||||
if (depth > blocks_.size()) {
|
||||
@ -547,31 +546,31 @@ class LR_WasmDecoder : public WasmDecoder {
|
||||
break;
|
||||
}
|
||||
case kExprI8Const: {
|
||||
int32_t value = Operand<int8_t>(pc_);
|
||||
int32_t value = bit_cast<int8_t>(ByteOperand(pc_));
|
||||
Leaf(kAstI32, BUILD(Int32Constant, value));
|
||||
len = 2;
|
||||
break;
|
||||
}
|
||||
case kExprI32Const: {
|
||||
int32_t value = Operand<int32_t>(pc_);
|
||||
uint32_t value = Uint32Operand(pc_);
|
||||
Leaf(kAstI32, BUILD(Int32Constant, value));
|
||||
len = 5;
|
||||
break;
|
||||
}
|
||||
case kExprI64Const: {
|
||||
int64_t value = Operand<int64_t>(pc_);
|
||||
uint64_t value = Uint64Operand(pc_);
|
||||
Leaf(kAstI64, BUILD(Int64Constant, value));
|
||||
len = 9;
|
||||
break;
|
||||
}
|
||||
case kExprF32Const: {
|
||||
float value = Operand<float>(pc_);
|
||||
float value = bit_cast<float>(Uint32Operand(pc_));
|
||||
Leaf(kAstF32, BUILD(Float32Constant, value));
|
||||
len = 5;
|
||||
break;
|
||||
}
|
||||
case kExprF64Const: {
|
||||
double value = Operand<double>(pc_);
|
||||
double value = bit_cast<double>(Uint64Operand(pc_));
|
||||
Leaf(kAstF64, BUILD(Float64Constant, value));
|
||||
len = 9;
|
||||
break;
|
||||
@ -877,7 +876,7 @@ class LR_WasmDecoder : public WasmDecoder {
|
||||
break;
|
||||
}
|
||||
case kExprBr: {
|
||||
uint32_t depth = Operand<uint8_t>(p->pc());
|
||||
uint32_t depth = ByteOperand(p->pc());
|
||||
if (depth >= blocks_.size()) {
|
||||
error("improperly nested branch");
|
||||
break;
|
||||
@ -890,7 +889,7 @@ class LR_WasmDecoder : public WasmDecoder {
|
||||
if (p->index == 1) {
|
||||
TypeCheckLast(p, kAstI32);
|
||||
} else if (p->done()) {
|
||||
uint32_t depth = Operand<uint8_t>(p->pc());
|
||||
uint32_t depth = ByteOperand(p->pc());
|
||||
if (depth >= blocks_.size()) {
|
||||
error("improperly nested branch");
|
||||
break;
|
||||
@ -911,8 +910,7 @@ class LR_WasmDecoder : public WasmDecoder {
|
||||
// Switch key finished.
|
||||
TypeCheckLast(p, kAstI32);
|
||||
|
||||
uint16_t table_count =
|
||||
*reinterpret_cast<const uint16_t*>(p->pc() + 3);
|
||||
uint16_t table_count = read_u16(p->pc() + 3);
|
||||
|
||||
// Build the switch only if it has more than just a default target.
|
||||
bool build_switch = table_count > 1;
|
||||
@ -920,7 +918,7 @@ class LR_WasmDecoder : public WasmDecoder {
|
||||
if (build_switch) sw = BUILD(Switch, table_count, p->last()->node);
|
||||
|
||||
// Allocate environments for each case.
|
||||
uint16_t case_count = *reinterpret_cast<const uint16_t*>(p->pc() + 1);
|
||||
uint16_t case_count = read_u16(p->pc() + 1);
|
||||
SsaEnv** case_envs = zone_->NewArray<SsaEnv*>(case_count);
|
||||
for (int i = 0; i < case_count; i++) case_envs[i] = UnreachableEnv();
|
||||
|
||||
@ -931,10 +929,8 @@ class LR_WasmDecoder : public WasmDecoder {
|
||||
ssa_env_ = copy;
|
||||
|
||||
// Build the environments for each case based on the table.
|
||||
const uint16_t* table =
|
||||
reinterpret_cast<const uint16_t*>(p->pc() + 5);
|
||||
for (int i = 0; i < table_count; i++) {
|
||||
uint16_t target = table[i];
|
||||
uint16_t target = read_u16(p->pc() + 5 + i * 2);
|
||||
SsaEnv* env = copy;
|
||||
if (build_switch) {
|
||||
env = Split(env);
|
||||
|
@ -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);
|
||||
}
|
||||
return 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 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_;
|
||||
|
@ -62,7 +62,7 @@ class ModuleDecoder : public Decoder {
|
||||
while (pc_ < limit_) {
|
||||
TRACE("DecodeSection\n");
|
||||
WasmSectionDeclCode section =
|
||||
static_cast<WasmSectionDeclCode>(u8("section"));
|
||||
static_cast<WasmSectionDeclCode>(consume_u8("section"));
|
||||
// Each section should appear at most once.
|
||||
if (section < kMaxModuleSectionCode) {
|
||||
CheckForPreviousSection(sections, section, false);
|
||||
@ -75,20 +75,20 @@ class ModuleDecoder : public Decoder {
|
||||
limit_ = pc_;
|
||||
break;
|
||||
case kDeclMemory:
|
||||
module->min_mem_size_log2 = u8("min memory");
|
||||
module->max_mem_size_log2 = u8("max memory");
|
||||
module->mem_export = u8("export memory") != 0;
|
||||
module->min_mem_size_log2 = consume_u8("min memory");
|
||||
module->max_mem_size_log2 = consume_u8("max memory");
|
||||
module->mem_export = consume_u8("export memory") != 0;
|
||||
break;
|
||||
case kDeclSignatures: {
|
||||
int length;
|
||||
uint32_t signatures_count = u32v(&length, "signatures count");
|
||||
uint32_t signatures_count = consume_u32v(&length, "signatures count");
|
||||
module->signatures->reserve(SafeReserve(signatures_count));
|
||||
// Decode signatures.
|
||||
for (uint32_t i = 0; i < signatures_count; i++) {
|
||||
if (failed()) break;
|
||||
TRACE("DecodeSignature[%d] module+%d\n", i,
|
||||
static_cast<int>(pc_ - start_));
|
||||
FunctionSig* s = sig(); // read function sig.
|
||||
FunctionSig* s = consume_sig(); // read function sig.
|
||||
module->signatures->push_back(s);
|
||||
}
|
||||
break;
|
||||
@ -97,7 +97,7 @@ class ModuleDecoder : public Decoder {
|
||||
// Functions require a signature table first.
|
||||
CheckForPreviousSection(sections, kDeclSignatures, true);
|
||||
int length;
|
||||
uint32_t functions_count = u32v(&length, "functions count");
|
||||
uint32_t functions_count = consume_u32v(&length, "functions count");
|
||||
module->functions->reserve(SafeReserve(functions_count));
|
||||
// Set up module environment for verification.
|
||||
ModuleEnv menv;
|
||||
@ -130,7 +130,7 @@ class ModuleDecoder : public Decoder {
|
||||
}
|
||||
case kDeclGlobals: {
|
||||
int length;
|
||||
uint32_t globals_count = u32v(&length, "globals count");
|
||||
uint32_t globals_count = consume_u32v(&length, "globals count");
|
||||
module->globals->reserve(SafeReserve(globals_count));
|
||||
// Decode globals.
|
||||
for (uint32_t i = 0; i < globals_count; i++) {
|
||||
@ -145,7 +145,8 @@ class ModuleDecoder : public Decoder {
|
||||
}
|
||||
case kDeclDataSegments: {
|
||||
int length;
|
||||
uint32_t data_segments_count = u32v(&length, "data segments count");
|
||||
uint32_t data_segments_count =
|
||||
consume_u32v(&length, "data segments count");
|
||||
module->data_segments->reserve(SafeReserve(data_segments_count));
|
||||
// Decode data segments.
|
||||
for (uint32_t i = 0; i < data_segments_count; i++) {
|
||||
@ -162,14 +163,15 @@ class ModuleDecoder : public Decoder {
|
||||
// An indirect function table requires functions first.
|
||||
CheckForPreviousSection(sections, kDeclFunctions, true);
|
||||
int length;
|
||||
uint32_t function_table_count = u32v(&length, "function table count");
|
||||
uint32_t function_table_count =
|
||||
consume_u32v(&length, "function table count");
|
||||
module->function_table->reserve(SafeReserve(function_table_count));
|
||||
// Decode function table.
|
||||
for (uint32_t i = 0; i < function_table_count; i++) {
|
||||
if (failed()) break;
|
||||
TRACE("DecodeFunctionTable[%d] module+%d\n", i,
|
||||
static_cast<int>(pc_ - start_));
|
||||
uint16_t index = u16();
|
||||
uint16_t index = consume_u16();
|
||||
if (index >= module->functions->size()) {
|
||||
error(pc_ - 2, "invalid function index");
|
||||
break;
|
||||
@ -184,7 +186,7 @@ class ModuleDecoder : public Decoder {
|
||||
// information. This section does not affect the semantics of the code
|
||||
// and can be ignored by the runtime. https://github.com/JSStats/wll
|
||||
int length = 0;
|
||||
uint32_t section_size = u32v(&length, "section size");
|
||||
uint32_t section_size = consume_u32v(&length, "section size");
|
||||
if (pc_ + section_size > limit_ || pc_ + section_size < pc_) {
|
||||
error(pc_ - length, "invalid section size");
|
||||
break;
|
||||
@ -246,14 +248,14 @@ class ModuleDecoder : public Decoder {
|
||||
FunctionResult DecodeSingleFunction(ModuleEnv* module_env,
|
||||
WasmFunction* function) {
|
||||
pc_ = start_;
|
||||
function->sig = sig(); // read signature
|
||||
function->sig = consume_sig(); // read signature
|
||||
function->name_offset = 0; // ---- name
|
||||
function->code_start_offset = off(pc_ + 8); // ---- code start
|
||||
function->code_end_offset = off(limit_); // ---- code end
|
||||
function->local_int32_count = u16(); // read u16
|
||||
function->local_int64_count = u16(); // read u16
|
||||
function->local_float32_count = u16(); // read u16
|
||||
function->local_float64_count = u16(); // read u16
|
||||
function->local_int32_count = consume_u16(); // read u16
|
||||
function->local_int64_count = consume_u16(); // read u16
|
||||
function->local_float32_count = consume_u16(); // read u16
|
||||
function->local_float64_count = consume_u16(); // read u16
|
||||
function->exported = false; // ---- exported
|
||||
function->external = false; // ---- external
|
||||
|
||||
@ -268,7 +270,7 @@ class ModuleDecoder : public Decoder {
|
||||
// Decodes a single function signature at {start}.
|
||||
FunctionSig* DecodeFunctionSignature(const byte* start) {
|
||||
pc_ = start;
|
||||
FunctionSig* result = sig();
|
||||
FunctionSig* result = consume_sig();
|
||||
return ok() ? result : nullptr;
|
||||
}
|
||||
|
||||
@ -281,19 +283,19 @@ class ModuleDecoder : public Decoder {
|
||||
|
||||
// Decodes a single global entry inside a module starting at {pc_}.
|
||||
void DecodeGlobalInModule(WasmGlobal* global) {
|
||||
global->name_offset = string("global name");
|
||||
global->name_offset = consume_string("global name");
|
||||
global->type = mem_type();
|
||||
global->offset = 0;
|
||||
global->exported = u8("exported") != 0;
|
||||
global->exported = consume_u8("exported") != 0;
|
||||
}
|
||||
|
||||
// Decodes a single function entry inside a module starting at {pc_}.
|
||||
void DecodeFunctionInModule(WasmModule* module, WasmFunction* function,
|
||||
bool verify_body = true) {
|
||||
byte decl_bits = u8("function decl");
|
||||
byte decl_bits = consume_u8("function decl");
|
||||
|
||||
const byte* sigpos = pc_;
|
||||
function->sig_index = u16("signature index");
|
||||
function->sig_index = consume_u16("signature index");
|
||||
|
||||
if (function->sig_index >= module->signatures->size()) {
|
||||
return error(sigpos, "invalid signature index");
|
||||
@ -310,7 +312,7 @@ class ModuleDecoder : public Decoder {
|
||||
(decl_bits & kDeclFunctionImport) == 0 ? " body" : "");
|
||||
|
||||
if (decl_bits & kDeclFunctionName) {
|
||||
function->name_offset = string("function name");
|
||||
function->name_offset = consume_string("function name");
|
||||
}
|
||||
|
||||
function->exported = decl_bits & kDeclFunctionExport;
|
||||
@ -322,13 +324,13 @@ class ModuleDecoder : public Decoder {
|
||||
}
|
||||
|
||||
if (decl_bits & kDeclFunctionLocals) {
|
||||
function->local_int32_count = u16("int32 count");
|
||||
function->local_int64_count = u16("int64 count");
|
||||
function->local_float32_count = u16("float32 count");
|
||||
function->local_float64_count = u16("float64 count");
|
||||
function->local_int32_count = consume_u16("int32 count");
|
||||
function->local_int64_count = consume_u16("int64 count");
|
||||
function->local_float32_count = consume_u16("float32 count");
|
||||
function->local_float64_count = consume_u16("float64 count");
|
||||
}
|
||||
|
||||
uint16_t size = u16("body size");
|
||||
uint16_t size = consume_u16("body size");
|
||||
if (ok()) {
|
||||
if ((pc_ + size) > limit_) {
|
||||
return error(pc_, limit_,
|
||||
@ -350,10 +352,10 @@ class ModuleDecoder : public Decoder {
|
||||
|
||||
// Decodes a single data segment entry inside a module starting at {pc_}.
|
||||
void DecodeDataSegmentInModule(WasmModule* module, WasmDataSegment* segment) {
|
||||
segment->dest_addr = u32("destination");
|
||||
segment->source_offset = offset("source offset");
|
||||
segment->source_size = u32("source size");
|
||||
segment->init = u8("init");
|
||||
segment->dest_addr = consume_u32("destination");
|
||||
segment->source_offset = consume_offset("source offset");
|
||||
segment->source_size = consume_u32("source size");
|
||||
segment->init = consume_u8("init");
|
||||
|
||||
// Validate the data is in the module.
|
||||
uint32_t module_limit = static_cast<uint32_t>(limit_ - start_);
|
||||
@ -416,8 +418,8 @@ class ModuleDecoder : public Decoder {
|
||||
|
||||
// Reads a single 32-bit unsigned integer interpreted as an offset, checking
|
||||
// the offset is within bounds and advances.
|
||||
uint32_t offset(const char* name = nullptr) {
|
||||
uint32_t offset = u32(name ? name : "offset");
|
||||
uint32_t consume_offset(const char* name = nullptr) {
|
||||
uint32_t offset = consume_u32(name ? name : "offset");
|
||||
if (offset > static_cast<uint32_t>(limit_ - start_)) {
|
||||
error(pc_ - sizeof(uint32_t), "offset out of bounds of module");
|
||||
}
|
||||
@ -426,13 +428,14 @@ class ModuleDecoder : public Decoder {
|
||||
|
||||
// Reads a single 32-bit unsigned integer interpreted as an offset into the
|
||||
// data and validating the string there and advances.
|
||||
uint32_t string(const char* name = nullptr) {
|
||||
return offset(name ? name : "string"); // TODO(titzer): validate string
|
||||
uint32_t consume_string(const char* name = nullptr) {
|
||||
// TODO(titzer): validate string
|
||||
return consume_offset(name ? name : "string");
|
||||
}
|
||||
|
||||
// Reads a single 8-bit integer, interpreting it as a local type.
|
||||
LocalType local_type() {
|
||||
byte val = u8("local type");
|
||||
LocalType consume_local_type() {
|
||||
byte val = consume_u8("local type");
|
||||
LocalTypeCode t = static_cast<LocalTypeCode>(val);
|
||||
switch (t) {
|
||||
case kLocalVoid:
|
||||
@ -453,7 +456,7 @@ class ModuleDecoder : public Decoder {
|
||||
|
||||
// Reads a single 8-bit integer, interpreting it as a memory type.
|
||||
MachineType mem_type() {
|
||||
byte val = u8("memory type");
|
||||
byte val = consume_u8("memory type");
|
||||
MemTypeCode t = static_cast<MemTypeCode>(val);
|
||||
switch (t) {
|
||||
case kMemI8:
|
||||
@ -483,14 +486,14 @@ class ModuleDecoder : public Decoder {
|
||||
}
|
||||
|
||||
// Parses an inline function signature.
|
||||
FunctionSig* sig() {
|
||||
byte count = u8("param count");
|
||||
LocalType ret = local_type();
|
||||
FunctionSig* consume_sig() {
|
||||
byte count = consume_u8("param count");
|
||||
LocalType ret = consume_local_type();
|
||||
FunctionSig::Builder builder(module_zone, ret == kAstStmt ? 0 : 1, count);
|
||||
if (ret != kAstStmt) builder.AddReturn(ret);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
LocalType param = local_type();
|
||||
LocalType param = consume_local_type();
|
||||
if (param == kAstStmt) error(pc_ - 1, "invalid void parameter type");
|
||||
builder.AddParam(param);
|
||||
}
|
||||
|
@ -2378,9 +2378,6 @@ TEST(Run_WasmCallEmpty) {
|
||||
}
|
||||
|
||||
|
||||
// TODO(tizer): Fix on arm and reenable.
|
||||
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64
|
||||
|
||||
TEST(Run_WasmCallF32StackParameter) {
|
||||
// Build the target function.
|
||||
LocalType param_types[20];
|
||||
@ -2432,8 +2429,6 @@ TEST(Run_WasmCallF64StackParameter) {
|
||||
CHECK_EQ(256.5, result);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
TEST(Run_WasmCallVoid) {
|
||||
const byte kMemOffset = 8;
|
||||
|
@ -251,9 +251,6 @@ TEST_F(WasmDecoderTest, Int64Const) {
|
||||
}
|
||||
|
||||
|
||||
// TODO(tizer): Fix on arm and reenable.
|
||||
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64
|
||||
|
||||
TEST_F(WasmDecoderTest, Float32Const) {
|
||||
byte code[] = {kExprF32Const, 0, 0, 0, 0};
|
||||
float* ptr = reinterpret_cast<float*>(code + 1);
|
||||
@ -273,8 +270,6 @@ TEST_F(WasmDecoderTest, Float64Const) {
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
TEST_F(WasmDecoderTest, Int32Const_off_end) {
|
||||
byte code[] = {kExprI32Const, 0xaa, 0xbb, 0xcc, 0x44};
|
||||
@ -532,16 +527,11 @@ TEST_F(WasmDecoderTest, ExprBlock1b) {
|
||||
}
|
||||
|
||||
|
||||
// TODO(tizer): Fix on arm and reenable.
|
||||
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64
|
||||
|
||||
TEST_F(WasmDecoderTest, ExprBlock1c) {
|
||||
static const byte code[] = {kExprBlock, 1, kExprF32Const, 0, 0, 0, 0};
|
||||
EXPECT_VERIFIES(&env_f_ff, code);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
TEST_F(WasmDecoderTest, IfEmpty) {
|
||||
static const byte code[] = {kExprIf, kExprGetLocal, 0, kExprNop};
|
||||
@ -704,9 +694,6 @@ TEST_F(WasmDecoderTest, ReturnVoid2) {
|
||||
}
|
||||
|
||||
|
||||
// TODO(tizer): Fix on arm and reenable.
|
||||
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64
|
||||
|
||||
TEST_F(WasmDecoderTest, ReturnVoid3) {
|
||||
EXPECT_VERIFIES_INLINE(&env_v_v, kExprI8Const, 0);
|
||||
EXPECT_VERIFIES_INLINE(&env_v_v, kExprI32Const, 0, 0, 0, 0);
|
||||
@ -717,8 +704,6 @@ TEST_F(WasmDecoderTest, ReturnVoid3) {
|
||||
EXPECT_VERIFIES_INLINE(&env_v_i, kExprGetLocal, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
TEST_F(WasmDecoderTest, Unreachable1) {
|
||||
EXPECT_VERIFIES_INLINE(&env_v_v, kExprUnreachable);
|
||||
@ -881,9 +866,6 @@ TEST_F(WasmDecoderTest, MacrosStmt) {
|
||||
}
|
||||
|
||||
|
||||
// TODO(tizer): Fix on arm and reenable.
|
||||
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64
|
||||
|
||||
TEST_F(WasmDecoderTest, MacrosBreak) {
|
||||
EXPECT_VERIFIES_INLINE(&env_v_v, WASM_LOOP(1, WASM_BREAK(0)));
|
||||
|
||||
@ -895,8 +877,6 @@ TEST_F(WasmDecoderTest, MacrosBreak) {
|
||||
WASM_LOOP(1, WASM_BREAKV(0, WASM_F64(0.0))));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
TEST_F(WasmDecoderTest, MacrosContinue) {
|
||||
EXPECT_VERIFIES_INLINE(&env_v_v, WASM_LOOP(1, WASM_CONTINUE(0)));
|
||||
@ -1263,9 +1243,6 @@ TEST_F(WasmDecoderTest, CallsWithTooFewArguments) {
|
||||
}
|
||||
|
||||
|
||||
// TODO(tizer): Fix on arm and reenable.
|
||||
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64
|
||||
|
||||
TEST_F(WasmDecoderTest, CallsWithSpilloverArgs) {
|
||||
static LocalType a_i_ff[] = {kAstI32, kAstF32, kAstF32};
|
||||
FunctionSig sig_i_ff(1, 2, a_i_ff);
|
||||
@ -1329,8 +1306,6 @@ TEST_F(WasmDecoderTest, CallsWithMismatchedSigs3) {
|
||||
EXPECT_FAILURE_INLINE(env, WASM_CALL_FUNCTION(1, WASM_F32(17.6)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
TEST_F(WasmDecoderTest, SimpleIndirectCalls) {
|
||||
FunctionEnv* env = &env_i_i;
|
||||
@ -1573,9 +1548,6 @@ TEST_F(WasmDecoderTest, BreakNesting3) {
|
||||
}
|
||||
|
||||
|
||||
// TODO(tizer): Fix on arm and reenable.
|
||||
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64
|
||||
|
||||
TEST_F(WasmDecoderTest, BreaksWithMultipleTypes) {
|
||||
EXPECT_FAILURE_INLINE(
|
||||
&env_i_i,
|
||||
@ -1593,8 +1565,6 @@ TEST_F(WasmDecoderTest, BreaksWithMultipleTypes) {
|
||||
WASM_BRV_IF(0, WASM_ZERO, WASM_I8(11))));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
TEST_F(WasmDecoderTest, BreakNesting_6_levels) {
|
||||
for (int mask = 0; mask < 64; mask++) {
|
||||
@ -1628,9 +1598,6 @@ TEST_F(WasmDecoderTest, BreakNesting_6_levels) {
|
||||
}
|
||||
|
||||
|
||||
// TODO(tizer): Fix on arm and reenable.
|
||||
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64
|
||||
|
||||
TEST_F(WasmDecoderTest, ExprBreak_TypeCheck) {
|
||||
FunctionEnv* envs[] = {&env_i_i, &env_l_l, &env_f_ff, &env_d_dd};
|
||||
for (size_t i = 0; i < arraysize(envs); i++) {
|
||||
@ -1653,8 +1620,6 @@ TEST_F(WasmDecoderTest, ExprBreak_TypeCheck) {
|
||||
WASM_F64(1.2)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
TEST_F(WasmDecoderTest, ExprBreak_TypeCheckAll) {
|
||||
byte code1[] = {WASM_BLOCK(2,
|
||||
@ -1835,9 +1800,6 @@ TEST_F(WasmDecoderTest, TableSwitch2) {
|
||||
}
|
||||
|
||||
|
||||
// TODO(tizer): Fix on arm and reenable.
|
||||
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64
|
||||
|
||||
TEST_F(WasmDecoderTest, TableSwitch1b) {
|
||||
EXPECT_VERIFIES_INLINE(&env_i_i, WASM_TABLESWITCH_OP(1, 1, WASM_CASE(0)),
|
||||
WASM_TABLESWITCH_BODY(WASM_GET_LOCAL(0), WASM_ZERO));
|
||||
@ -1849,8 +1811,6 @@ TEST_F(WasmDecoderTest, TableSwitch1b) {
|
||||
WASM_TABLESWITCH_BODY(WASM_ZERO, WASM_F64(0.0)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST_F(WasmDecoderTest, TableSwitch_br1) {
|
||||
for (int depth = 0; depth < 2; depth++) {
|
||||
byte code[] = {WASM_BLOCK(1, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(depth)),
|
||||
@ -1882,17 +1842,12 @@ TEST_F(WasmDecoderTest, TableSwitch_invalid_case_ref) {
|
||||
}
|
||||
|
||||
|
||||
// TODO(tizer): Fix on arm and reenable.
|
||||
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64
|
||||
|
||||
TEST_F(WasmDecoderTest, TableSwitch1_br) {
|
||||
EXPECT_VERIFIES_INLINE(
|
||||
&env_i_i, WASM_TABLESWITCH_OP(1, 1, WASM_CASE(0)),
|
||||
WASM_TABLESWITCH_BODY(WASM_GET_LOCAL(0), WASM_BRV(0, WASM_ZERO)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
TEST_F(WasmDecoderTest, TableSwitch2_br) {
|
||||
EXPECT_VERIFIES_INLINE(
|
||||
@ -1916,9 +1871,6 @@ TEST_F(WasmDecoderTest, TableSwitch2x2) {
|
||||
}
|
||||
|
||||
|
||||
// TODO(tizer): Fix on arm and reenable.
|
||||
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64
|
||||
|
||||
TEST_F(WasmDecoderTest, ExprBreakNesting1) {
|
||||
EXPECT_VERIFIES_INLINE(&env_v_v, WASM_BLOCK(1, WASM_BRV(0, WASM_ZERO)));
|
||||
EXPECT_VERIFIES_INLINE(&env_v_v, WASM_BLOCK(1, WASM_BR(0)));
|
||||
@ -1936,8 +1888,6 @@ TEST_F(WasmDecoderTest, ExprBreakNesting1) {
|
||||
EXPECT_VERIFIES_INLINE(&env_v_v, WASM_LOOP(1, WASM_BR(1)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
TEST_F(WasmDecoderTest, Select) {
|
||||
EXPECT_VERIFIES_INLINE(
|
||||
@ -1946,9 +1896,6 @@ TEST_F(WasmDecoderTest, Select) {
|
||||
}
|
||||
|
||||
|
||||
// TODO(tizer): Fix on arm and reenable.
|
||||
#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64
|
||||
|
||||
TEST_F(WasmDecoderTest, Select_TypeCheck) {
|
||||
EXPECT_FAILURE_INLINE(&env_i_i, WASM_SELECT(WASM_F32(9.9), WASM_GET_LOCAL(0),
|
||||
WASM_GET_LOCAL(0)));
|
||||
@ -1960,8 +1907,6 @@ TEST_F(WasmDecoderTest, Select_TypeCheck) {
|
||||
&env_i_i, WASM_SELECT(WASM_F32(9.9), WASM_GET_LOCAL(0), WASM_I64(0)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class WasmOpcodeLengthTest : public TestWithZone {
|
||||
public:
|
||||
|
Loading…
Reference in New Issue
Block a user