mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1598149 - Report bulk-memory failures to instantiate segments as runtime errors. r=lth
Bulk memory reduces active segments to sequences of *.init that are executed before the start function is called. This implies that an error here is to be reported as a RuntimeError, as an error in the start function would. The latest spec tests for bulk-memory check this, so we're required to update as well. Differential Revision: https://phabricator.services.mozilla.com/D54598 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
68bba5ed9e
commit
ad3b40a6b8
@ -1,8 +1,4 @@
|
||||
const Module = WebAssembly.Module;
|
||||
const Instance = WebAssembly.Instance;
|
||||
const Memory = WebAssembly.Memory;
|
||||
const Table = WebAssembly.Table;
|
||||
const LinkError = WebAssembly.LinkError;
|
||||
const { Module, Instance, Memory, Table, LinkError, RuntimeError } = WebAssembly;
|
||||
|
||||
const mem1Page = new Memory({initial:1});
|
||||
const mem1PageMax1 = new Memory({initial:1, maximum: 1});
|
||||
@ -19,6 +15,14 @@ const tab2Elem = new Table({initial:2, element:"funcref"});
|
||||
const tab3Elem = new Table({initial:3, element:"funcref"});
|
||||
const tab4Elem = new Table({initial:4, element:"funcref"});
|
||||
|
||||
function assertSegmentFitError(f) {
|
||||
if (wasmBulkMemSupported()) {
|
||||
assertErrorMessage(f, RuntimeError, /out of bounds/);
|
||||
} else {
|
||||
assertErrorMessage(f, LinkError, /segment does not fit/);
|
||||
}
|
||||
}
|
||||
|
||||
// Memory size consistency and internal limits.
|
||||
assertErrorMessage(() => new Memory({initial:2, maximum:1}), RangeError, /bad Memory maximum size/);
|
||||
|
||||
@ -491,15 +495,15 @@ var m = new Module(wasmTextToBinary(`
|
||||
`));
|
||||
assertEq(new Instance(m, {glob:{a:0}}) instanceof Instance, true);
|
||||
assertEq(new Instance(m, {glob:{a:(64*1024 - 2)}}) instanceof Instance, true);
|
||||
assertErrorMessage(() => new Instance(m, {glob:{a:(64*1024 - 1)}}), LinkError, /data segment does not fit/);
|
||||
assertErrorMessage(() => new Instance(m, {glob:{a:64*1024}}), LinkError, /data segment does not fit/);
|
||||
assertSegmentFitError(() => new Instance(m, {glob:{a:(64*1024 - 1)}}));
|
||||
assertSegmentFitError(() => new Instance(m, {glob:{a:64*1024}}));
|
||||
|
||||
var m = new Module(wasmTextToBinary(`
|
||||
(module
|
||||
(memory 1)
|
||||
(data (i32.const 0x10001) "\\0a\\0b"))
|
||||
`));
|
||||
assertErrorMessage(() => new Instance(m), LinkError, /data segment does not fit/);
|
||||
assertSegmentFitError(() => new Instance(m));
|
||||
|
||||
var m = new Module(wasmTextToBinary(`
|
||||
(module
|
||||
@ -544,9 +548,7 @@ var mem = new Memory({initial:npages});
|
||||
var mem8 = new Uint8Array(mem.buffer);
|
||||
var tbl = new Table({initial:2, element:"funcref"});
|
||||
|
||||
assertErrorMessage(() => new Instance(m, {a:{mem, tbl, memOff:1, tblOff:2}}),
|
||||
LinkError,
|
||||
/elem segment does not fit/);
|
||||
assertSegmentFitError(() => new Instance(m, {a:{mem, tbl, memOff:1, tblOff:2}}));
|
||||
if (wasmBulkMemSupported()) {
|
||||
// The first active element segment is applied, but the second active
|
||||
// element segment is completely OOB.
|
||||
@ -562,9 +564,7 @@ assertEq(mem8[1], 0);
|
||||
tbl.set(0, null);
|
||||
tbl.set(1, null);
|
||||
|
||||
assertErrorMessage(() => new Instance(m, {a:{mem, tbl, memOff:npages*64*1024, tblOff:1}}),
|
||||
LinkError,
|
||||
/data segment does not fit/);
|
||||
assertSegmentFitError(() => new Instance(m, {a:{mem, tbl, memOff:npages*64*1024, tblOff:1}}));
|
||||
if (wasmBulkMemSupported()) {
|
||||
// The first and second active element segments are applied fully. The
|
||||
// first active data segment applies, but the second one is completely OOB.
|
||||
@ -605,9 +605,7 @@ if (wasmBulkMemSupported()) {
|
||||
(func $h))`));
|
||||
let mem = new Memory({initial:1});
|
||||
let tbl = new Table({initial:3, element:"funcref"});
|
||||
assertErrorMessage(() => new Instance(m, {"":{mem, tbl}}),
|
||||
LinkError,
|
||||
/elem segment does not fit/);
|
||||
assertSegmentFitError(() => new Instance(m, {"":{mem, tbl}}));
|
||||
assertEq(tbl.get(0), null);
|
||||
assertEq(tbl.get(1), null);
|
||||
assertEq(tbl.get(2), null);
|
||||
@ -626,9 +624,7 @@ if (wasmBulkMemSupported()) {
|
||||
(data (i32.const 0) "\\04") ;; is not applied
|
||||
)`));
|
||||
let mem = new Memory({initial:1});
|
||||
assertErrorMessage(() => new Instance(m, {"":{mem}}),
|
||||
LinkError,
|
||||
/data segment does not fit/);
|
||||
assertSegmentFitError(() => new Instance(m, {"":{mem}}));
|
||||
let v = new Uint8Array(mem.buffer);
|
||||
assertEq(v[65534], 0);
|
||||
assertEq(v[65535], 0);
|
||||
|
@ -7,6 +7,14 @@ const RuntimeError = WebAssembly.RuntimeError;
|
||||
|
||||
const badFuncRefError = /can only pass WebAssembly exported functions to funcref/;
|
||||
|
||||
function assertSegmentFitError(f) {
|
||||
if (wasmBulkMemSupported()) {
|
||||
assertErrorMessage(f, RuntimeError, /out of bounds/);
|
||||
} else {
|
||||
assertErrorMessage(f, LinkError, /segment does not fit/);
|
||||
}
|
||||
}
|
||||
|
||||
var callee = i => `(func $f${i} (result i32) (i32.const ${i}))`;
|
||||
|
||||
wasmFailValidateText(`(module (elem (i32.const 0) $f0) ${callee(0)})`, /elem segment requires a table/);
|
||||
@ -14,12 +22,12 @@ wasmFailValidateText(`(module (table 10 funcref) (elem (i32.const 0) 0))`, /tabl
|
||||
wasmFailValidateText(`(module (table 10 funcref) (func) (elem (i32.const 0) 0 1))`, /table element out of range/);
|
||||
wasmFailValidateText(`(module (table 10 funcref) (func) (elem (f32.const 0) 0) ${callee(0)})`, /type mismatch/);
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`(module (table 10 funcref) (elem (i32.const 10) $f0) ${callee(0)})`), LinkError, /elem segment does not fit/);
|
||||
assertErrorMessage(() => wasmEvalText(`(module (table 10 funcref) (elem (i32.const 8) $f0 $f0 $f0) ${callee(0)})`), LinkError, /elem segment does not fit/);
|
||||
assertEq(wasmEvalText(`(module (table 0 funcref) (func) (elem (i32.const 0x10001)))`) instanceof Instance, true);
|
||||
assertSegmentFitError(() => wasmEvalText(`(module (table 10 funcref) (elem (i32.const 10) $f0) ${callee(0)})`));
|
||||
assertSegmentFitError(() => wasmEvalText(`(module (table 10 funcref) (elem (i32.const 8) $f0 $f0 $f0) ${callee(0)})`));
|
||||
assertSegmentFitError(() => wasmEvalText(`(module (table 0 funcref) (func) (elem (i32.const 0x10001)))`));
|
||||
|
||||
assertErrorMessage(() => wasmEvalText(`(module (table 10 funcref) (import "globals" "a" (global i32)) (elem (global.get 0) $f0) ${callee(0)})`, {globals:{a:10}}), LinkError, /elem segment does not fit/);
|
||||
assertErrorMessage(() => wasmEvalText(`(module (table 10 funcref) (import "globals" "a" (global i32)) (elem (global.get 0) $f0 $f0 $f0) ${callee(0)})`, {globals:{a:8}}), LinkError, /elem segment does not fit/);
|
||||
assertSegmentFitError(() => wasmEvalText(`(module (table 10 funcref) (import "globals" "a" (global i32)) (elem (global.get 0) $f0) ${callee(0)})`, {globals:{a:10}}));
|
||||
assertSegmentFitError(() => wasmEvalText(`(module (table 10 funcref) (import "globals" "a" (global i32)) (elem (global.get 0) $f0 $f0 $f0) ${callee(0)})`, {globals:{a:8}}));
|
||||
|
||||
assertEq(new Module(wasmTextToBinary(`(module (table 10 funcref) (elem (i32.const 1) $f0 $f0) (elem (i32.const 0) $f0) ${callee(0)})`)) instanceof Module, true);
|
||||
assertEq(new Module(wasmTextToBinary(`(module (table 10 funcref) (elem (i32.const 1) $f0 $f0) (elem (i32.const 2) $f0) ${callee(0)})`)) instanceof Module, true);
|
||||
@ -61,7 +69,7 @@ var m = new Module(wasmTextToBinary(`
|
||||
`));
|
||||
var tbl = new Table({initial:50, element:"funcref"});
|
||||
assertEq(new Instance(m, {globals:{a:20, table:tbl}}) instanceof Instance, true);
|
||||
assertErrorMessage(() => new Instance(m, {globals:{a:50, table:tbl}}), LinkError, /elem segment does not fit/);
|
||||
assertSegmentFitError(() => new Instance(m, {globals:{a:50, table:tbl}}));
|
||||
|
||||
var caller = `(type $v2i (func (result i32))) (func $call (param $i i32) (result i32) (call_indirect $v2i (local.get $i))) (export "call" $call)`
|
||||
var callee = i => `(func $f${i} (type $v2i) (i32.const ${i}))`;
|
||||
|
@ -531,7 +531,8 @@ bool Module::initSegments(JSContext* cx, HandleWasmInstanceObject instanceObj,
|
||||
|
||||
if (eagerBoundsCheck) {
|
||||
// Perform all error checks up front so that this function does not perform
|
||||
// partial initialization if an error is reported.
|
||||
// partial initialization if an error is reported. In addition, we need to
|
||||
// to report OOBs as a link error when bulk-memory is disabled.
|
||||
|
||||
for (const ElemSegment* seg : elemSegments_) {
|
||||
if (!seg->active()) {
|
||||
@ -586,7 +587,7 @@ bool Module::initSegments(JSContext* cx, HandleWasmInstanceObject instanceObj,
|
||||
uint32_t tableLength = tables[seg->tableIndex]->length();
|
||||
if (offset > tableLength || tableLength - offset < count) {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_WASM_BAD_FIT, "elem", "table");
|
||||
JSMSG_WASM_OUT_OF_BOUNDS);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -621,7 +622,7 @@ bool Module::initSegments(JSContext* cx, HandleWasmInstanceObject instanceObj,
|
||||
if (!eagerBoundsCheck) {
|
||||
if (offset > memoryLength || memoryLength - offset < count) {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_WASM_BAD_FIT, "data", "memory");
|
||||
JSMSG_WASM_OUT_OF_BOUNDS);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user