Commit b86ef5ce authored by rossberg's avatar rossberg Committed by Commit bot

[wasm] Fix and tighten memory validation

Makes us pass the spec's memory.wast test.

R=titzer@chromium.org
BUG=

Review-Url: https://codereview.chromium.org/2640453003
Cr-Commit-Position: refs/heads/master@{#42452}
parent 3c897883
...@@ -622,6 +622,13 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -622,6 +622,13 @@ class WasmFullDecoder : public WasmDecoder {
return bytes; return bytes;
} }
bool CheckHasMemory() {
if (!module_->has_memory) {
error(pc_ - 1, "memory instruction with no memory");
}
return module_->has_memory;
}
// Decodes the body of a function. // Decodes the body of a function.
void DecodeFunctionBody() { void DecodeFunctionBody() {
TRACE("wasm-decode %p...%p (module+%d, %d bytes) %s\n", TRACE("wasm-decode %p...%p (module+%d, %d bytes) %s\n",
...@@ -1112,6 +1119,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1112,6 +1119,7 @@ class WasmFullDecoder : public WasmDecoder {
len = DecodeStoreMem(kWasmF64, MachineType::Float64()); len = DecodeStoreMem(kWasmF64, MachineType::Float64());
break; break;
case kExprGrowMemory: { case kExprGrowMemory: {
if (!CheckHasMemory()) break;
MemoryIndexOperand operand(this, pc_); MemoryIndexOperand operand(this, pc_);
DCHECK_NOT_NULL(module_); DCHECK_NOT_NULL(module_);
if (module_->origin != kAsmJsOrigin) { if (module_->origin != kAsmJsOrigin) {
...@@ -1124,6 +1132,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1124,6 +1132,7 @@ class WasmFullDecoder : public WasmDecoder {
break; break;
} }
case kExprMemorySize: { case kExprMemorySize: {
if (!CheckHasMemory()) break;
MemoryIndexOperand operand(this, pc_); MemoryIndexOperand operand(this, pc_);
Push(kWasmI32, BUILD(CurrentMemoryPages)); Push(kWasmI32, BUILD(CurrentMemoryPages));
len = 1 + operand.length; len = 1 + operand.length;
...@@ -1304,6 +1313,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1304,6 +1313,7 @@ class WasmFullDecoder : public WasmDecoder {
void PopControl() { control_.pop_back(); } void PopControl() { control_.pop_back(); }
int DecodeLoadMem(ValueType type, MachineType mem_type) { int DecodeLoadMem(ValueType type, MachineType mem_type) {
if (!CheckHasMemory()) return 0;
MemoryAccessOperand operand(this, pc_, MemoryAccessOperand operand(this, pc_,
ElementSizeLog2Of(mem_type.representation())); ElementSizeLog2Of(mem_type.representation()));
...@@ -1315,6 +1325,7 @@ class WasmFullDecoder : public WasmDecoder { ...@@ -1315,6 +1325,7 @@ class WasmFullDecoder : public WasmDecoder {
} }
int DecodeStoreMem(ValueType type, MachineType mem_type) { int DecodeStoreMem(ValueType type, MachineType mem_type) {
if (!CheckHasMemory()) return 0;
MemoryAccessOperand operand(this, pc_, MemoryAccessOperand operand(this, pc_,
ElementSizeLog2Of(mem_type.representation())); ElementSizeLog2Of(mem_type.representation()));
Value val = Pop(1, type); Value val = Pop(1, type);
......
...@@ -308,7 +308,10 @@ void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -308,7 +308,10 @@ void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
MaybeLocal<Value> instance = MaybeLocal<Value> instance =
InstantiateModuleImpl(i_isolate, i_module_obj, args, &thrower); InstantiateModuleImpl(i_isolate, i_module_obj, args, &thrower);
if (instance.IsEmpty()) return; if (instance.IsEmpty()) {
DCHECK(thrower.error());
return;
}
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
return_value.Set(instance.ToLocalChecked()); return_value.Set(instance.ToLocalChecked());
......
...@@ -1293,7 +1293,7 @@ class WasmInstanceBuilder { ...@@ -1293,7 +1293,7 @@ class WasmInstanceBuilder {
Address mem_start = static_cast<Address>(memory_->backing_store()); Address mem_start = static_cast<Address>(memory_->backing_store());
uint32_t mem_size = uint32_t mem_size =
static_cast<uint32_t>(memory_->byte_length()->Number()); static_cast<uint32_t>(memory_->byte_length()->Number());
LoadDataSegments(mem_start, mem_size); if (!LoadDataSegments(mem_start, mem_size)) return nothing;
uint32_t old_mem_size = compiled_module_->mem_size(); uint32_t old_mem_size = compiled_module_->mem_size();
Address old_mem_start = Address old_mem_start =
...@@ -1305,7 +1305,7 @@ class WasmInstanceBuilder { ...@@ -1305,7 +1305,7 @@ class WasmInstanceBuilder {
old_mem_size, mem_size); old_mem_size, mem_size);
compiled_module_->set_memory(memory_); compiled_module_->set_memory(memory_);
} else { } else {
LoadDataSegments(nullptr, 0); if (!LoadDataSegments(nullptr, 0)) return nothing;
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
...@@ -1545,7 +1545,7 @@ class WasmInstanceBuilder { ...@@ -1545,7 +1545,7 @@ class WasmInstanceBuilder {
} }
// Load data segments into the memory. // Load data segments into the memory.
void LoadDataSegments(Address mem_addr, size_t mem_size) { bool LoadDataSegments(Address mem_addr, size_t mem_size) {
Handle<SeqOneByteString> module_bytes(compiled_module_->module_bytes(), Handle<SeqOneByteString> module_bytes(compiled_module_->module_bytes(),
isolate_); isolate_);
for (const WasmDataSegment& segment : module_->data_segments) { for (const WasmDataSegment& segment : module_->data_segments) {
...@@ -1553,18 +1553,19 @@ class WasmInstanceBuilder { ...@@ -1553,18 +1553,19 @@ class WasmInstanceBuilder {
// Segments of size == 0 are just nops. // Segments of size == 0 are just nops.
if (source_size == 0) continue; if (source_size == 0) continue;
uint32_t dest_offset = EvalUint32InitExpr(segment.dest_addr); uint32_t dest_offset = EvalUint32InitExpr(segment.dest_addr);
if (dest_offset >= mem_size || source_size >= mem_size || if (dest_offset + source_size > mem_size ||
dest_offset > (mem_size - source_size)) { dest_offset + source_size < dest_offset) {
thrower_->LinkError("data segment (start = %" PRIu32 ", size = %" PRIu32 thrower_->LinkError("data segment (start = %" PRIu32 ", size = %" PRIu32
") does not fit into memory (size = %" PRIuS ")", ") does not fit into memory (size = %" PRIuS ")",
dest_offset, source_size, mem_size); dest_offset, source_size, mem_size);
return; return false;
} }
byte* dest = mem_addr + dest_offset; byte* dest = mem_addr + dest_offset;
const byte* src = reinterpret_cast<const byte*>( const byte* src = reinterpret_cast<const byte*>(
module_bytes->GetCharsAddress() + segment.source_offset); module_bytes->GetCharsAddress() + segment.source_offset);
memcpy(dest, src, source_size); memcpy(dest, src, source_size);
} }
return true;
} }
void WriteGlobalValue(WasmGlobal& global, Handle<Object> value) { void WriteGlobalValue(WasmGlobal& global, Handle<Object> value) {
......
...@@ -1808,6 +1808,7 @@ TEST(Build_Wasm_UnreachableIf2) { ...@@ -1808,6 +1808,7 @@ TEST(Build_Wasm_UnreachableIf2) {
WASM_EXEC_TEST(Unreachable_Load) { WASM_EXEC_TEST(Unreachable_Load) {
WasmRunner<int32_t, int32_t> r(execution_mode); WasmRunner<int32_t, int32_t> r(execution_mode);
r.module().AddMemory(0L);
BUILD(r, WASM_BLOCK_I(WASM_BRV(0, WASM_GET_LOCAL(0)), BUILD(r, WASM_BLOCK_I(WASM_BRV(0, WASM_GET_LOCAL(0)),
WASM_LOAD_MEM(MachineType::Int8(), WASM_GET_LOCAL(0)))); WASM_LOAD_MEM(MachineType::Int8(), WASM_GET_LOCAL(0))));
CHECK_EQ(11, r.Call(11)); CHECK_EQ(11, r.Call(11));
......
...@@ -101,6 +101,7 @@ TEST(IllegalLoad) { ...@@ -101,6 +101,7 @@ TEST(IllegalLoad) {
TestSignatures sigs; TestSignatures sigs;
// Set the execution context, such that a runtime error can be thrown. // Set the execution context, such that a runtime error can be thrown.
r.SetModuleContext(); r.SetModuleContext();
r.module().AddMemory(0L);
BUILD(r, WASM_IF(WASM_ONE, WASM_SEQ(WASM_LOAD_MEM(MachineType::Int32(), BUILD(r, WASM_IF(WASM_ONE, WASM_SEQ(WASM_LOAD_MEM(MachineType::Int32(),
WASM_I32V_1(-3)), WASM_I32V_1(-3)),
......
...@@ -105,8 +105,10 @@ class TestingModule : public ModuleEnv { ...@@ -105,8 +105,10 @@ class TestingModule : public ModuleEnv {
void ChangeOriginToAsmjs() { module_.origin = kAsmJsOrigin; } void ChangeOriginToAsmjs() { module_.origin = kAsmJsOrigin; }
byte* AddMemory(uint32_t size) { byte* AddMemory(uint32_t size) {
CHECK(!module_.has_memory);
CHECK_NULL(instance->mem_start); CHECK_NULL(instance->mem_start);
CHECK_EQ(0, instance->mem_size); CHECK_EQ(0, instance->mem_size);
module_.has_memory = true;
instance->mem_start = reinterpret_cast<byte*>(malloc(size)); instance->mem_start = reinterpret_cast<byte*>(malloc(size));
CHECK(instance->mem_start); CHECK(instance->mem_start);
memset(instance->mem_start, 0, size); memset(instance->mem_start, 0, size);
......
...@@ -9,6 +9,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -9,6 +9,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function() { (function() {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addMemory(0, 0, false);
builder.addFunction("test", kSig_i_iii) builder.addFunction("test", kSig_i_iii)
.addBody([ .addBody([
kExprI32Const, 0x0b, kExprI32Const, 0x0b,
......
...@@ -184,6 +184,7 @@ testGrowMemoryReadWrite8(); ...@@ -184,6 +184,7 @@ testGrowMemoryReadWrite8();
function testGrowMemoryZeroInitialSize() { function testGrowMemoryZeroInitialSize() {
var builder = genGrowMemoryBuilder(); var builder = genGrowMemoryBuilder();
builder.addMemory(0, kV8MaxPages, false);
var module = builder.instantiate(); var module = builder.instantiate();
var offset; var offset;
function peek() { return module.exports.load(offset); } function peek() { return module.exports.load(offset); }
...@@ -217,6 +218,7 @@ testGrowMemoryZeroInitialSize(); ...@@ -217,6 +218,7 @@ testGrowMemoryZeroInitialSize();
function testGrowMemoryZeroInitialSize32() { function testGrowMemoryZeroInitialSize32() {
var builder = genGrowMemoryBuilder(); var builder = genGrowMemoryBuilder();
builder.addMemory(0, kV8MaxPages, false);
var module = builder.instantiate(); var module = builder.instantiate();
var offset; var offset;
function peek() { return module.exports.load(offset); } function peek() { return module.exports.load(offset); }
...@@ -242,6 +244,7 @@ testGrowMemoryZeroInitialSize32(); ...@@ -242,6 +244,7 @@ testGrowMemoryZeroInitialSize32();
function testGrowMemoryZeroInitialSize16() { function testGrowMemoryZeroInitialSize16() {
var builder = genGrowMemoryBuilder(); var builder = genGrowMemoryBuilder();
builder.addMemory(0, kV8MaxPages, false);
var module = builder.instantiate(); var module = builder.instantiate();
var offset; var offset;
function peek() { return module.exports.load16(offset); } function peek() { return module.exports.load16(offset); }
...@@ -267,6 +270,7 @@ testGrowMemoryZeroInitialSize16(); ...@@ -267,6 +270,7 @@ testGrowMemoryZeroInitialSize16();
function testGrowMemoryZeroInitialSize8() { function testGrowMemoryZeroInitialSize8() {
var builder = genGrowMemoryBuilder(); var builder = genGrowMemoryBuilder();
builder.addMemory(0, kV8MaxPages, false);
var module = builder.instantiate(); var module = builder.instantiate();
var offset; var offset;
function peek() { return module.exports.load8(offset); } function peek() { return module.exports.load8(offset); }
...@@ -292,6 +296,7 @@ testGrowMemoryZeroInitialSize8(); ...@@ -292,6 +296,7 @@ testGrowMemoryZeroInitialSize8();
function testGrowMemoryTrapMaxPagesZeroInitialMemory() { function testGrowMemoryTrapMaxPagesZeroInitialMemory() {
var builder = genGrowMemoryBuilder(); var builder = genGrowMemoryBuilder();
builder.addMemory(0, kV8MaxPages, false);
var module = builder.instantiate(); var module = builder.instantiate();
var maxPages = 16385; var maxPages = 16385;
function growMem(pages) { return module.exports.grow_memory(pages); } function growMem(pages) { return module.exports.grow_memory(pages); }
...@@ -313,6 +318,7 @@ testGrowMemoryTrapMaxPages(); ...@@ -313,6 +318,7 @@ testGrowMemoryTrapMaxPages();
function testGrowMemoryTrapsWithNonSmiInput() { function testGrowMemoryTrapsWithNonSmiInput() {
var builder = genGrowMemoryBuilder(); var builder = genGrowMemoryBuilder();
builder.addMemory(0, kV8MaxPages, false);
var module = builder.instantiate(); var module = builder.instantiate();
function growMem(pages) { return module.exports.grow_memory(pages); } function growMem(pages) { return module.exports.grow_memory(pages); }
// The parameter of grow_memory is unsigned. Therefore -1 stands for // The parameter of grow_memory is unsigned. Therefore -1 stands for
......
...@@ -10,6 +10,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -10,6 +10,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function testMemorySizeZero() { (function testMemorySizeZero() {
print("testMemorySizeZero()"); print("testMemorySizeZero()");
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addMemory(0, 0, false);
builder.addFunction("memory_size", kSig_i_v) builder.addFunction("memory_size", kSig_i_v)
.addBody([kExprMemorySize, kMemoryZero]) .addBody([kExprMemorySize, kMemoryZero])
.exportFunc(); .exportFunc();
......
...@@ -42,6 +42,8 @@ function STACK() { ...@@ -42,6 +42,8 @@ function STACK() {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addMemory(0, 1, false);
builder.addImport("mod", "func", kSig_v_v); builder.addImport("mod", "func", kSig_v_v);
builder.addFunction("main", kSig_v_v) builder.addFunction("main", kSig_v_v)
...@@ -70,8 +72,8 @@ var module = builder.instantiate({mod: {func: STACK}}); ...@@ -70,8 +72,8 @@ var module = builder.instantiate({mod: {func: STACK}});
// The line numbers below will change as this test gains / loses lines.. // The line numbers below will change as this test gains / loses lines..
" at STACK (stack.js:39:11)\n" + // -- " at STACK (stack.js:39:11)\n" + // --
" at main (<WASM>[1]+1)\n" + // -- " at main (<WASM>[1]+1)\n" + // --
" at testSimpleStack (stack.js:76:18)\n" + // -- " at testSimpleStack (stack.js:78:18)\n" + // --
" at stack.js:78:3"; // -- " at stack.js:80:3"; // --
module.exports.main(); module.exports.main();
assertEquals(expected_string, stripPath(stack)); assertEquals(expected_string, stripPath(stack));
...@@ -90,8 +92,8 @@ Error.prepareStackTrace = function(error, frames) { ...@@ -90,8 +92,8 @@ Error.prepareStackTrace = function(error, frames) {
// isWasm function line pos file // isWasm function line pos file
[ false, "STACK", 39, 0, "stack.js"], [ false, "STACK", 39, 0, "stack.js"],
[ true, "main", 1, 1, null], [ true, "main", 1, 1, null],
[ false, "testStackFrames", 87, 0, "stack.js"], [ false, "testStackFrames", 89, 0, "stack.js"],
[ false, null, 96, 0, "stack.js"] [ false, null, 98, 0, "stack.js"]
]); ]);
})(); })();
...@@ -104,8 +106,8 @@ Error.prepareStackTrace = function(error, frames) { ...@@ -104,8 +106,8 @@ Error.prepareStackTrace = function(error, frames) {
verifyStack(e.stack, [ verifyStack(e.stack, [
// isWasm function line pos file // isWasm function line pos file
[ true, "exec_unreachable", 2, 1, null], [ true, "exec_unreachable", 2, 1, null],
[ false, "testWasmUnreachable", 100, 0, "stack.js"], [ false, "testWasmUnreachable", 102, 0, "stack.js"],
[ false, null, 111, 0, "stack.js"] [ false, null, 113, 0, "stack.js"]
]); ]);
} }
})(); })();
...@@ -120,8 +122,8 @@ Error.prepareStackTrace = function(error, frames) { ...@@ -120,8 +122,8 @@ Error.prepareStackTrace = function(error, frames) {
// isWasm function line pos file // isWasm function line pos file
[ true, "", 3, 3, null], [ true, "", 3, 3, null],
[ true, "call_mem_out_of_bounds", 4, 1, null], [ true, "call_mem_out_of_bounds", 4, 1, null],
[ false, "testWasmMemOutOfBounds", 115, 0, "stack.js"], [ false, "testWasmMemOutOfBounds", 117, 0, "stack.js"],
[ false, null, 127, 0, "stack.js"] [ false, null, 129, 0, "stack.js"]
]); ]);
} }
})(); })();
......
...@@ -14,6 +14,8 @@ Error.prepareStackTrace = function(error, frames) { ...@@ -14,6 +14,8 @@ Error.prepareStackTrace = function(error, frames) {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addMemory(0, 1, false);
var sig_index = builder.addType(kSig_i_v) var sig_index = builder.addType(kSig_i_v)
// Build a function to resemble this code: // Build a function to resemble this code:
......
...@@ -14,6 +14,8 @@ Error.prepareStackTrace = function(error, frames) { ...@@ -14,6 +14,8 @@ Error.prepareStackTrace = function(error, frames) {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addMemory(0, 1, false);
var sig_index = builder.addType(kSig_i_v) var sig_index = builder.addType(kSig_i_v)
// Build a function to resemble this code: // Build a function to resemble this code:
......
...@@ -201,6 +201,60 @@ class FunctionBodyDecoderTest : public TestWithZone { ...@@ -201,6 +201,60 @@ class FunctionBodyDecoderTest : public TestWithZone {
} }
}; };
namespace {
// A helper for tests that require a module environment for functions,
// globals, or memories.
class TestModuleEnv : public ModuleEnv {
public:
explicit TestModuleEnv(ModuleOrigin origin = kWasmOrigin)
: ModuleEnv(&mod, nullptr) {
mod.origin = origin;
}
byte AddGlobal(ValueType type, bool mutability = true) {
mod.globals.push_back({type, mutability, WasmInitExpr(), 0, false, false});
CHECK(mod.globals.size() <= 127);
return static_cast<byte>(mod.globals.size() - 1);
}
byte AddSignature(FunctionSig* sig) {
mod.signatures.push_back(sig);
CHECK(mod.signatures.size() <= 127);
return static_cast<byte>(mod.signatures.size() - 1);
}
byte AddFunction(FunctionSig* sig) {
mod.functions.push_back({sig, // sig
0, // func_index
0, // sig_index
0, // name_offset
0, // name_length
0, // code_start_offset
0, // code_end_offset
false, // import
false}); // export
CHECK(mod.functions.size() <= 127);
return static_cast<byte>(mod.functions.size() - 1);
}
byte AddImport(FunctionSig* sig) {
byte result = AddFunction(sig);
mod.functions[result].imported = true;
return result;
}
void InitializeMemory() {
mod.has_memory = true;
mod.min_mem_pages = 1;
mod.max_mem_pages = 100;
}
void InitializeFunctionTable() {
mod.function_tables.push_back(
{0, 0, true, std::vector<int32_t>(), false, false, SignatureMap()});
}
private:
WasmModule mod;
};
} // namespace
TEST_F(FunctionBodyDecoderTest, Int32Const1) { TEST_F(FunctionBodyDecoderTest, Int32Const1) {
byte code[] = {kExprI32Const, 0}; byte code[] = {kExprI32Const, 0};
for (int i = -64; i <= 63; i++) { for (int i = -64; i <= 63; i++) {
...@@ -1023,6 +1077,9 @@ TEST_F(FunctionBodyDecoderTest, TypeConversions) { ...@@ -1023,6 +1077,9 @@ TEST_F(FunctionBodyDecoderTest, TypeConversions) {
} }
TEST_F(FunctionBodyDecoderTest, MacrosStmt) { TEST_F(FunctionBodyDecoderTest, MacrosStmt) {
TestModuleEnv module_env;
module = &module_env;
module_env.InitializeMemory();
EXPECT_VERIFIES(v_i, WASM_SET_LOCAL(0, WASM_I32V_3(87348))); EXPECT_VERIFIES(v_i, WASM_SET_LOCAL(0, WASM_I32V_3(87348)));
EXPECT_VERIFIES(v_i, WASM_STORE_MEM(MachineType::Int32(), WASM_I32V_1(24), EXPECT_VERIFIES(v_i, WASM_STORE_MEM(MachineType::Int32(), WASM_I32V_1(24),
WASM_I32V_1(40))); WASM_I32V_1(40)));
...@@ -1159,12 +1216,18 @@ TEST_F(FunctionBodyDecoderTest, AllSimpleExpressions) { ...@@ -1159,12 +1216,18 @@ TEST_F(FunctionBodyDecoderTest, AllSimpleExpressions) {
} }
TEST_F(FunctionBodyDecoderTest, MemorySize) { TEST_F(FunctionBodyDecoderTest, MemorySize) {
TestModuleEnv module_env;
module = &module_env;
module_env.InitializeMemory();
byte code[] = {kExprMemorySize, 0}; byte code[] = {kExprMemorySize, 0};
EXPECT_VERIFIES_C(i_i, code); EXPECT_VERIFIES_C(i_i, code);
EXPECT_FAILURE_C(f_ff, code); EXPECT_FAILURE_C(f_ff, code);
} }
TEST_F(FunctionBodyDecoderTest, LoadMemOffset) { TEST_F(FunctionBodyDecoderTest, LoadMemOffset) {
TestModuleEnv module_env;
module = &module_env;
module_env.InitializeMemory();
for (int offset = 0; offset < 128; offset += 7) { for (int offset = 0; offset < 128; offset += 7) {
byte code[] = {kExprI32Const, 0, kExprI32LoadMem, ZERO_ALIGNMENT, byte code[] = {kExprI32Const, 0, kExprI32LoadMem, ZERO_ALIGNMENT,
static_cast<byte>(offset)}; static_cast<byte>(offset)};
...@@ -1173,6 +1236,9 @@ TEST_F(FunctionBodyDecoderTest, LoadMemOffset) { ...@@ -1173,6 +1236,9 @@ TEST_F(FunctionBodyDecoderTest, LoadMemOffset) {
} }
TEST_F(FunctionBodyDecoderTest, LoadMemAlignment) { TEST_F(FunctionBodyDecoderTest, LoadMemAlignment) {
TestModuleEnv module_env;
module = &module_env;
module_env.InitializeMemory();
struct { struct {
WasmOpcode instruction; WasmOpcode instruction;
uint32_t maximum_aligment; uint32_t maximum_aligment;
...@@ -1207,6 +1273,9 @@ TEST_F(FunctionBodyDecoderTest, LoadMemAlignment) { ...@@ -1207,6 +1273,9 @@ TEST_F(FunctionBodyDecoderTest, LoadMemAlignment) {
} }
TEST_F(FunctionBodyDecoderTest, StoreMemOffset) { TEST_F(FunctionBodyDecoderTest, StoreMemOffset) {
TestModuleEnv module_env;
module = &module_env;
module_env.InitializeMemory();
for (int offset = 0; offset < 128; offset += 7) { for (int offset = 0; offset < 128; offset += 7) {
byte code[] = {WASM_STORE_MEM_OFFSET(MachineType::Int32(), offset, byte code[] = {WASM_STORE_MEM_OFFSET(MachineType::Int32(), offset,
WASM_ZERO, WASM_ZERO)}; WASM_ZERO, WASM_ZERO)};
...@@ -1215,6 +1284,9 @@ TEST_F(FunctionBodyDecoderTest, StoreMemOffset) { ...@@ -1215,6 +1284,9 @@ TEST_F(FunctionBodyDecoderTest, StoreMemOffset) {
} }
TEST_F(FunctionBodyDecoderTest, StoreMemOffset_void) { TEST_F(FunctionBodyDecoderTest, StoreMemOffset_void) {
TestModuleEnv module_env;
module = &module_env;
module_env.InitializeMemory();
EXPECT_FAILURE(i_i, WASM_STORE_MEM_OFFSET(MachineType::Int32(), 0, WASM_ZERO, EXPECT_FAILURE(i_i, WASM_STORE_MEM_OFFSET(MachineType::Int32(), 0, WASM_ZERO,
WASM_ZERO)); WASM_ZERO));
} }
...@@ -1230,6 +1302,9 @@ TEST_F(FunctionBodyDecoderTest, StoreMemOffset_void) { ...@@ -1230,6 +1302,9 @@ TEST_F(FunctionBodyDecoderTest, StoreMemOffset_void) {
#define VARINT4(x) BYTE0(x) | 0x80, BYTE1(x) | 0x80, BYTE2(x) | 0x80, BYTE3(x) #define VARINT4(x) BYTE0(x) | 0x80, BYTE1(x) | 0x80, BYTE2(x) | 0x80, BYTE3(x)
TEST_F(FunctionBodyDecoderTest, LoadMemOffset_varint) { TEST_F(FunctionBodyDecoderTest, LoadMemOffset_varint) {
TestModuleEnv module_env;
module = &module_env;
module_env.InitializeMemory();
EXPECT_VERIFIES(i_i, WASM_ZERO, kExprI32LoadMem, ZERO_ALIGNMENT, EXPECT_VERIFIES(i_i, WASM_ZERO, kExprI32LoadMem, ZERO_ALIGNMENT,
VARINT1(0x45)); VARINT1(0x45));
EXPECT_VERIFIES(i_i, WASM_ZERO, kExprI32LoadMem, ZERO_ALIGNMENT, EXPECT_VERIFIES(i_i, WASM_ZERO, kExprI32LoadMem, ZERO_ALIGNMENT,
...@@ -1241,6 +1316,9 @@ TEST_F(FunctionBodyDecoderTest, LoadMemOffset_varint) { ...@@ -1241,6 +1316,9 @@ TEST_F(FunctionBodyDecoderTest, LoadMemOffset_varint) {
} }
TEST_F(FunctionBodyDecoderTest, StoreMemOffset_varint) { TEST_F(FunctionBodyDecoderTest, StoreMemOffset_varint) {
TestModuleEnv module_env;
module = &module_env;
module_env.InitializeMemory();
EXPECT_VERIFIES(v_i, WASM_ZERO, WASM_ZERO, kExprI32StoreMem, ZERO_ALIGNMENT, EXPECT_VERIFIES(v_i, WASM_ZERO, WASM_ZERO, kExprI32StoreMem, ZERO_ALIGNMENT,
VARINT1(0x33)); VARINT1(0x33));
EXPECT_VERIFIES(v_i, WASM_ZERO, WASM_ZERO, kExprI32StoreMem, ZERO_ALIGNMENT, EXPECT_VERIFIES(v_i, WASM_ZERO, WASM_ZERO, kExprI32StoreMem, ZERO_ALIGNMENT,
...@@ -1252,6 +1330,9 @@ TEST_F(FunctionBodyDecoderTest, StoreMemOffset_varint) { ...@@ -1252,6 +1330,9 @@ TEST_F(FunctionBodyDecoderTest, StoreMemOffset_varint) {
} }
TEST_F(FunctionBodyDecoderTest, AllLoadMemCombinations) { TEST_F(FunctionBodyDecoderTest, AllLoadMemCombinations) {
TestModuleEnv module_env;
module = &module_env;
module_env.InitializeMemory();
for (size_t i = 0; i < arraysize(kValueTypes); i++) { for (size_t i = 0; i < arraysize(kValueTypes); i++) {
ValueType local_type = kValueTypes[i]; ValueType local_type = kValueTypes[i];
for (size_t j = 0; j < arraysize(machineTypes); j++) { for (size_t j = 0; j < arraysize(machineTypes); j++) {
...@@ -1268,6 +1349,9 @@ TEST_F(FunctionBodyDecoderTest, AllLoadMemCombinations) { ...@@ -1268,6 +1349,9 @@ TEST_F(FunctionBodyDecoderTest, AllLoadMemCombinations) {
} }
TEST_F(FunctionBodyDecoderTest, AllStoreMemCombinations) { TEST_F(FunctionBodyDecoderTest, AllStoreMemCombinations) {
TestModuleEnv module_env;
module = &module_env;
module_env.InitializeMemory();
for (size_t i = 0; i < arraysize(kValueTypes); i++) { for (size_t i = 0; i < arraysize(kValueTypes); i++) {
ValueType local_type = kValueTypes[i]; ValueType local_type = kValueTypes[i];
for (size_t j = 0; j < arraysize(machineTypes); j++) { for (size_t j = 0; j < arraysize(machineTypes); j++) {
...@@ -1283,54 +1367,6 @@ TEST_F(FunctionBodyDecoderTest, AllStoreMemCombinations) { ...@@ -1283,54 +1367,6 @@ TEST_F(FunctionBodyDecoderTest, AllStoreMemCombinations) {
} }
} }
namespace {
// A helper for tests that require a module environment for functions and
// globals.
class TestModuleEnv : public ModuleEnv {
public:
explicit TestModuleEnv(ModuleOrigin origin = kWasmOrigin)
: ModuleEnv(&mod, nullptr) {
mod.origin = origin;
}
byte AddGlobal(ValueType type, bool mutability = true) {
mod.globals.push_back({type, mutability, WasmInitExpr(), 0, false, false});
CHECK(mod.globals.size() <= 127);
return static_cast<byte>(mod.globals.size() - 1);
}
byte AddSignature(FunctionSig* sig) {
mod.signatures.push_back(sig);
CHECK(mod.signatures.size() <= 127);
return static_cast<byte>(mod.signatures.size() - 1);
}
byte AddFunction(FunctionSig* sig) {
mod.functions.push_back({sig, // sig
0, // func_index
0, // sig_index
0, // name_offset
0, // name_length
0, // code_start_offset
0, // code_end_offset
false, // import
false}); // export
CHECK(mod.functions.size() <= 127);
return static_cast<byte>(mod.functions.size() - 1);
}
byte AddImport(FunctionSig* sig) {
byte result = AddFunction(sig);
mod.functions[result].imported = true;
return result;
}
void InitializeFunctionTable() {
mod.function_tables.push_back(
{0, 0, true, std::vector<int32_t>(), false, false, SignatureMap()});
}
private:
WasmModule mod;
};
} // namespace
TEST_F(FunctionBodyDecoderTest, SimpleCalls) { TEST_F(FunctionBodyDecoderTest, SimpleCalls) {
FunctionSig* sig = sigs.i_i(); FunctionSig* sig = sigs.i_i();
TestModuleEnv module_env; TestModuleEnv module_env;
...@@ -1665,6 +1701,7 @@ TEST_F(FunctionBodyDecoderTest, AllSetGlobalCombinations) { ...@@ -1665,6 +1701,7 @@ TEST_F(FunctionBodyDecoderTest, AllSetGlobalCombinations) {
TEST_F(FunctionBodyDecoderTest, WasmGrowMemory) { TEST_F(FunctionBodyDecoderTest, WasmGrowMemory) {
TestModuleEnv module_env; TestModuleEnv module_env;
module = &module_env; module = &module_env;
module_env.InitializeMemory();
byte code[] = {WASM_GET_LOCAL(0), kExprGrowMemory, 0}; byte code[] = {WASM_GET_LOCAL(0), kExprGrowMemory, 0};
EXPECT_VERIFIES_C(i_i, code); EXPECT_VERIFIES_C(i_i, code);
...@@ -1674,6 +1711,7 @@ TEST_F(FunctionBodyDecoderTest, WasmGrowMemory) { ...@@ -1674,6 +1711,7 @@ TEST_F(FunctionBodyDecoderTest, WasmGrowMemory) {
TEST_F(FunctionBodyDecoderTest, AsmJsGrowMemory) { TEST_F(FunctionBodyDecoderTest, AsmJsGrowMemory) {
TestModuleEnv module_env(kAsmJsOrigin); TestModuleEnv module_env(kAsmJsOrigin);
module = &module_env; module = &module_env;
module_env.InitializeMemory();
byte code[] = {WASM_GET_LOCAL(0), kExprGrowMemory, 0}; byte code[] = {WASM_GET_LOCAL(0), kExprGrowMemory, 0};
EXPECT_FAILURE_C(i_i, code); EXPECT_FAILURE_C(i_i, code);
...@@ -1705,6 +1743,7 @@ TEST_F(FunctionBodyDecoderTest, AsmJsBinOpsCheckOrigin) { ...@@ -1705,6 +1743,7 @@ TEST_F(FunctionBodyDecoderTest, AsmJsBinOpsCheckOrigin) {
{ {
TestModuleEnv module_env(kAsmJsOrigin); TestModuleEnv module_env(kAsmJsOrigin);
module = &module_env; module = &module_env;
module_env.InitializeMemory();
for (size_t i = 0; i < arraysize(AsmJsBinOps); i++) { for (size_t i = 0; i < arraysize(AsmJsBinOps); i++) {
TestBinop(AsmJsBinOps[i].op, AsmJsBinOps[i].sig); TestBinop(AsmJsBinOps[i].op, AsmJsBinOps[i].sig);
} }
...@@ -1713,6 +1752,7 @@ TEST_F(FunctionBodyDecoderTest, AsmJsBinOpsCheckOrigin) { ...@@ -1713,6 +1752,7 @@ TEST_F(FunctionBodyDecoderTest, AsmJsBinOpsCheckOrigin) {
{ {
TestModuleEnv module_env; TestModuleEnv module_env;
module = &module_env; module = &module_env;
module_env.InitializeMemory();
for (size_t i = 0; i < arraysize(AsmJsBinOps); i++) { for (size_t i = 0; i < arraysize(AsmJsBinOps); i++) {
byte code[] = { byte code[] = {
WASM_BINOP(AsmJsBinOps[i].op, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))}; WASM_BINOP(AsmJsBinOps[i].op, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))};
...@@ -1751,6 +1791,7 @@ TEST_F(FunctionBodyDecoderTest, AsmJsUnOpsCheckOrigin) { ...@@ -1751,6 +1791,7 @@ TEST_F(FunctionBodyDecoderTest, AsmJsUnOpsCheckOrigin) {
{ {
TestModuleEnv module_env(kAsmJsOrigin); TestModuleEnv module_env(kAsmJsOrigin);
module = &module_env; module = &module_env;
module_env.InitializeMemory();
for (size_t i = 0; i < arraysize(AsmJsUnOps); i++) { for (size_t i = 0; i < arraysize(AsmJsUnOps); i++) {
TestUnop(AsmJsUnOps[i].op, AsmJsUnOps[i].sig); TestUnop(AsmJsUnOps[i].op, AsmJsUnOps[i].sig);
} }
...@@ -1759,6 +1800,7 @@ TEST_F(FunctionBodyDecoderTest, AsmJsUnOpsCheckOrigin) { ...@@ -1759,6 +1800,7 @@ TEST_F(FunctionBodyDecoderTest, AsmJsUnOpsCheckOrigin) {
{ {
TestModuleEnv module_env; TestModuleEnv module_env;
module = &module_env; module = &module_env;
module_env.InitializeMemory();
for (size_t i = 0; i < arraysize(AsmJsUnOps); i++) { for (size_t i = 0; i < arraysize(AsmJsUnOps); i++) {
byte code[] = {WASM_UNOP(AsmJsUnOps[i].op, WASM_GET_LOCAL(0))}; byte code[] = {WASM_UNOP(AsmJsUnOps[i].op, WASM_GET_LOCAL(0))};
EXPECT_FAILURE_SC(AsmJsUnOps[i].sig, code); EXPECT_FAILURE_SC(AsmJsUnOps[i].sig, code);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment