Commit e3c7324a authored by ahaas's avatar ahaas Committed by Commit bot

[wasm] Check data segments for zero-sized memory.

According to the spec data segments are allowed even if the memory size
is zero. However, if one of the data segments has a length greater than
0, then module instantiation should fail.

I also changed the exception type in LoadDataSegments to TypeError,
because that's the exception type for all exceptions which can happen
during instantiation.

R=titzer@chromium.org, rossberg@chromium.org
TEST=cctest/test-run-wasm-module/EmptyMemoryEmptyDataSegment, cctest/test-run-wasm-module/EmptyMemoryNonEmptyDataSegment

Review-Url: https://codereview.chromium.org/2483053005
Cr-Commit-Position: refs/heads/master@{#40922}
parent 567904f1
...@@ -1078,6 +1078,8 @@ class WasmInstanceBuilder { ...@@ -1078,6 +1078,8 @@ class WasmInstanceBuilder {
RelocateMemoryReferencesInCode(code_table, old_mem_start, mem_start, RelocateMemoryReferencesInCode(code_table, old_mem_start, mem_start,
old_mem_size, mem_size); old_mem_size, mem_size);
compiled_module_->set_memory(memory_); compiled_module_->set_memory(memory_);
} else {
LoadDataSegments(nullptr, 0);
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
...@@ -1273,7 +1275,7 @@ class WasmInstanceBuilder { ...@@ -1273,7 +1275,7 @@ class WasmInstanceBuilder {
return result; return result;
} }
uint32_t EvalUint32InitExpr(WasmInitExpr& expr) { uint32_t EvalUint32InitExpr(const WasmInitExpr& expr) {
switch (expr.kind) { switch (expr.kind) {
case WasmInitExpr::kI32Const: case WasmInitExpr::kI32Const:
return expr.val.i32_const; return expr.val.i32_const;
...@@ -1290,15 +1292,18 @@ class WasmInstanceBuilder { ...@@ -1290,15 +1292,18 @@ class WasmInstanceBuilder {
// Load data segments into the memory. // Load data segments into the memory.
void LoadDataSegments(Address mem_addr, size_t mem_size) { void LoadDataSegments(Address mem_addr, size_t mem_size) {
Handle<SeqOneByteString> module_bytes = compiled_module_->module_bytes(); Handle<SeqOneByteString> module_bytes = compiled_module_->module_bytes();
for (auto segment : module_->data_segments) { for (const WasmDataSegment& segment : module_->data_segments) {
uint32_t dest_offset = EvalUint32InitExpr(segment.dest_addr);
uint32_t source_size = segment.source_size; uint32_t source_size = segment.source_size;
// Segments of size == 0 are just nops.
if (source_size == 0) continue;
uint32_t dest_offset = EvalUint32InitExpr(segment.dest_addr);
if (dest_offset >= mem_size || source_size >= mem_size || if (dest_offset >= mem_size || source_size >= mem_size ||
dest_offset > (mem_size - source_size)) { dest_offset > (mem_size - source_size)) {
thrower_->RangeError( thrower_->TypeError("data segment (start = %" PRIu32 ", size = %" PRIu32
"data segment (start = %u, size = %u) does not fit into memory " ") does not fit into memory "
"(size = %zu)", "(size = %" PRIu64 ")",
dest_offset, source_size, mem_size); dest_offset, source_size,
static_cast<uint64_t>(mem_size));
return; return;
} }
byte* dest = mem_addr + dest_offset; byte* dest = mem_addr + dest_offset;
......
...@@ -811,3 +811,106 @@ TEST(InitDataAtTheUpperLimit) { ...@@ -811,3 +811,106 @@ TEST(InitDataAtTheUpperLimit) {
} }
Cleanup(); Cleanup();
} }
TEST(EmptyMemoryNonEmptyDataSegment) {
{
Isolate* isolate = CcTest::InitIsolateOnce();
HandleScope scope(isolate);
testing::SetupIsolateForWasmModule(isolate);
ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit");
const byte data[] = {
WASM_MODULE_HEADER, // --
kMemorySectionCode, // --
U32V_1(4), // section size
ENTRY_COUNT(1), // --
kResizableMaximumFlag, // --
0, // initial size
0, // maximum size
kDataSectionCode, // --
U32V_1(7), // section size
ENTRY_COUNT(1), // --
0, // linear memory index
WASM_I32V_1(8), // destination offset
kExprEnd,
U32V_1(1), // source size
'c' // data bytes
};
testing::CompileInstantiateWasmModuleForTesting(isolate, &thrower, data,
data + arraysize(data),
ModuleOrigin::kWasmOrigin);
// It should not be possible to instantiate this module.
CHECK(thrower.error());
}
Cleanup();
}
TEST(EmptyMemoryEmptyDataSegment) {
{
Isolate* isolate = CcTest::InitIsolateOnce();
HandleScope scope(isolate);
testing::SetupIsolateForWasmModule(isolate);
ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit");
const byte data[] = {
WASM_MODULE_HEADER, // --
kMemorySectionCode, // --
U32V_1(4), // section size
ENTRY_COUNT(1), // --
kResizableMaximumFlag, // --
0, // initial size
0, // maximum size
kDataSectionCode, // --
U32V_1(6), // section size
ENTRY_COUNT(1), // --
0, // linear memory index
WASM_I32V_1(24), // destination offset
kExprEnd,
U32V_1(0), // source size
};
testing::CompileInstantiateWasmModuleForTesting(isolate, &thrower, data,
data + arraysize(data),
ModuleOrigin::kWasmOrigin);
// It should be possible to instantiate this module.
CHECK(!thrower.error());
}
Cleanup();
}
TEST(MemoryWithOOBEmptyDataSegment) {
{
Isolate* isolate = CcTest::InitIsolateOnce();
HandleScope scope(isolate);
testing::SetupIsolateForWasmModule(isolate);
ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit");
const byte data[] = {
WASM_MODULE_HEADER, // --
kMemorySectionCode, // --
U32V_1(4), // section size
ENTRY_COUNT(1), // --
kResizableMaximumFlag, // --
1, // initial size
1, // maximum size
kDataSectionCode, // --
U32V_1(9), // section size
ENTRY_COUNT(1), // --
0, // linear memory index
WASM_I32V_4(0x2468ace), // destination offset
kExprEnd,
U32V_1(0), // source size
};
testing::CompileInstantiateWasmModuleForTesting(isolate, &thrower, data,
data + arraysize(data),
ModuleOrigin::kWasmOrigin);
// It should be possible to instantiate this module.
CHECK(!thrower.error());
}
Cleanup();
}
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