const mem1Page = new Memory({initial:1}); const mem1PageMax1 = new Memory({initial:1, maximum: 1}); const mem2Page = new Memory({initial:2}); const mem2PageMax2 = new Memory({initial:2, maximum: 2}); const mem2PageMax3 = new Memory({initial:2, maximum: 3}); const mem2PageMax4 = new Memory({initial:2, maximum: 4}); const mem3Page = new Memory({initial:3}); const mem3PageMax3 = new Memory({initial:3, maximum: 3}); const mem4Page = new Memory({initial:4}); const mem4PageMax4 = new Memory({initial:4, maximum: 4}); const tab1Elem = new Table({initial:1, element:"anyfunc"}); const tab2Elem = new Table({initial:2, element:"anyfunc"}); const tab3Elem = new Table({initial:3, element:"anyfunc"}); const tab4Elem = new Table({initial:4, element:"anyfunc"});
function assertSegmentFitError(f) {
assertErrorMessage(f, RuntimeError, /out of bounds/);
}
const m1 = new Module(wasmTextToBinary('(module (import "foo" "bar" (func)) (import "baz" "quux" (func)))'));
assertErrorMessage(() => new Instance(m1), TypeError, /second argument must be an object/);
assertErrorMessage(() => new Instance(m1, {foo:null}), TypeError, /import object field 'foo' is not an Object/);
assertErrorMessage(() => new Instance(m1, {foo:{bar:{}}}), LinkError, /import object field 'bar' is not a Function/);
assertErrorMessage(() => new Instance(m1, {foo:{bar:()=>{}}, baz:null}), TypeError, /import object field 'baz' is not an Object/);
assertErrorMessage(() => new Instance(m1, {foo:{bar:()=>{}}, baz:{}}), LinkError, /importobject field 'quux' is not a Function/);
assertEq(new Instance(m1, {foo:{bar:()=>{}}, baz:{quux:()=>{}}}) instanceof Instance, true);
const m2 = new Module(wasmTextToBinary('(module (import "x" "y" (memory 2 3)))'));
assertErrorMessage(() => new Instance(m2), TypeError, /second argument must be an object/);
assertErrorMessage(() => new Instance(m2, {x:null}), TypeError, /import object field 'x' is not an Object/);
assertErrorMessage(() => new Instance(m2, {x:{y:{}}}), LinkError, /import object field 'y'is not a Memory/);
assertErrorMessage(() => new Instance(m2, {x:{y:mem1Page}}), LinkError, /imported Memory with incompatible size/);
assertErrorMessage(() => new Instance(m2, {x:{y:mem1PageMax1}}), LinkError, /imported Memory with incompatible size/);
assertErrorMessage(() => new Instance(m2, {x:{y:mem4Page}}), LinkError, /imported Memory with incompatible size/);
assertErrorMessage(() => new Instance(m2, {x:{y:mem4PageMax4}}), LinkError, /imported Memory with incompatible size/);
assertErrorMessage(() => new Instance(m2, {x:{y:mem2Page}}), LinkError, /imported Memory with incompatible maximum size/);
assertEq(new Instance(m2, {x:{y:mem2PageMax2}}) instanceof Instance, true);
assertErrorMessage(() => new Instance(m2, {x:{y:mem3Page}}), LinkError, /imported Memory with incompatible maximum size/);
assertEq(new Instance(m2, {x:{y:mem3PageMax3}}) instanceof Instance, true);
assertEq(new Instance(m2, {x:{y:mem2PageMax3}}) instanceof Instance, true);
assertErrorMessage(() => new Instance(m2, {x:{y:mem2PageMax4}}), LinkError, /imported Memory with incompatible maximum size/);
const m3 = new Module(wasmTextToBinary('(module (import "foo" "bar" (memory 1 1)) (import "baz" "quux" (func)))'));
assertErrorMessage(() => new Instance(m3), TypeError, /second argument must be an object/);
assertErrorMessage(() => new Instance(m3, {foo:null}), TypeError, /import object field 'foo' is not an Object/);
assertErrorMessage(() => new Instance(m3, {foo:{bar:{}}}), LinkError, /import object field 'bar' is not a Memory/);
assertErrorMessage(() => new Instance(m3, {foo:{bar:mem1Page}, baz:null}), TypeError, /import object field 'baz' is not an Object/);
assertErrorMessage(() => new Instance(m3, {foo:{bar:mem1Page}, baz:{quux:mem1Page}}), LinkError, /import object field 'quux' is not a Function/);
assertErrorMessage(() => new Instance(m3, {foo:{bar:mem1Page}, baz:{quux:()=>{}}}), LinkError, /imported Memory with incompatible maximum size/);
assertEq(new Instance(m3, {foo:{bar:mem1PageMax1}, baz:{quux:()=>{}}}) instanceof Instance, true);
const m4 = new Module(wasmTextToBinary('(module (import "baz" "quux" (func)) (import "foo" "bar" (memory 1 1)))'));
assertErrorMessage(() => new Instance(m4), TypeError, /second argument must be an object/);
assertErrorMessage(() => new Instance(m4, {baz:null}), TypeError, /import object field 'baz' is not an Object/);
assertErrorMessage(() => new Instance(m4, {baz:{quux:{}}}), LinkError, /import object field 'quux' is not a Function/);
assertErrorMessage(() => new Instance(m4, {baz:{quux:()=>{}}, foo:null}), TypeError, /import object field 'foo' is not an Object/);
assertErrorMessage(() => new Instance(m4, {baz:{quux:()=>{}}, foo:{bar:()=>{}}}), LinkError, /import object field 'bar' is not a Memory/);
assertErrorMessage(() => new Instance(m4, {baz:{quux:()=>{}}, foo:{bar:mem1Page}}), LinkError, /imported Memory with incompatible maximum size/);
assertEq(new Instance(m3, {baz:{quux:()=>{}}, foo:{bar:mem1PageMax1}}) instanceof Instance, true);
const m5 = new Module(wasmTextToBinary('(module (import "a" "b" (memory 2)))'));
assertErrorMessage(() => new Instance(m5, {a:{b:mem1Page}}), LinkError, /imported Memory with incompatible size/);
assertEq(new Instance(m5, {a:{b:mem2Page}}) instanceof Instance, true);
assertEq(new Instance(m5, {a:{b:mem3Page}}) instanceof Instance, true);
assertEq(new Instance(m5, {a:{b:mem4Page}}) instanceof Instance, true);
const m6 = new Module(wasmTextToBinary('(module (import "a" "b" (table 2 funcref)))'));
assertErrorMessage(() => new Instance(m6, {a:{b:tab1Elem}}), LinkError, /imported Table with incompatible size/);
assertEq(new Instance(m6, {a:{b:tab2Elem}}) instanceof Instance, true);
assertEq(new Instance(m6, {a:{b:tab3Elem}}) instanceof Instance, true);
assertEq(new Instance(m6, {a:{b:tab4Elem}}) instanceof Instance, true);
const m7 = new Module(wasmTextToBinary('(module (import "a" "b" (table 2 3 funcref)))'));
assertErrorMessage(() => new Instance(m7, {a:{b:tab1Elem}}), LinkError, /imported Table with incompatible size/);
assertErrorMessage(() => new Instance(m7, {a:{b:tab2Elem}}), LinkError, /imported Table with incompatible maximum size/);
assertErrorMessage(() => new Instance(m7, {a:{b:tab3Elem}}), LinkError, /imported Table with incompatible maximum size/);
assertErrorMessage(() => new Instance(m7, {a:{b:tab4Elem}}), LinkError, /imported Table with incompatible size/);
wasmFailValidateText('(module (memory 2 1))', /maximum length 1 is less than initial length 2/);
wasmFailValidateText('(module (import "a" "b" (memory 2 1)))', /maximum length 1 is less than initial length 2/);
wasmFailValidateText('(module (table 2 1 funcref))', /maximum length 1 is less than initial length 2/);
wasmFailValidateText('(module (import "a" "b" (table 2 1 funcref)))', /maximum length 1 is less than initial length 2/);
// Import wasm-wasm type mismatch
var e = wasmEvalText('(module (func $i2v (param i32)) (export "i2v" (func $i2v)) (func $f2v (param f32)) (export "f2v" (func $f2v)))').exports; var i2vm = new Module(wasmTextToBinary('(module (import "a" "b" (func (param i32))))')); var f2vm = new Module(wasmTextToBinary('(module (import "a" "b" (func (param f32))))'));
assertEq(new Instance(i2vm, {a:{b:e.i2v}}) instanceof Instance, true);
assertErrorMessage(() => new Instance(i2vm, {a:{b:e.f2v}}), LinkError, /imported function'a.b' signature mismatch/);
assertErrorMessage(() => new Instance(f2vm, {a:{b:e.i2v}}), LinkError, /imported function'a.b' signature mismatch/);
assertEq(new Instance(f2vm, {a:{b:e.f2v}}) instanceof Instance, true); var l2vm = new Module(wasmTextToBinary('(module (import "x" "y" (memory 1)) (import "c" "d" (func (param i64))))'));
assertErrorMessage(() => new Instance(l2vm, {x:{y:mem1Page}, c:{d:e.i2v}}), LinkError, /imported function'c.d' signature mismatch/);
// Import order:
var arr = []; var importObj = {
get foo() { arr.push("foo") },
get baz() { arr.push("bad") },
};
assertErrorMessage(() => new Instance(m1, importObj), TypeError, /import object field 'foo' is not an Object/);
assertEq(arr.join(), "foo");
var arr = []; var importObj = {
get foo() {
arr.push("foo"); return { get bar() { arr.push("bar"); returnnull } }
},
get baz() { arr.push("bad") },
};
assertErrorMessage(() => new Instance(m1, importObj), LinkError, /import object field 'bar' is not a Function/);
assertEq(arr.join(), "foo,bar");
var arr = []; var importObj = {
get foo() {
arr.push("foo"); return { get bar() { arr.push("bar"); return () => arr.push("bad") } }
},
get baz() {
arr.push("baz"); return { get quux() { arr.push("quux"); return () => arr.push("bad") } }
}
};
assertEq(new Instance(m1, importObj) instanceof Instance, true);
assertEq(arr.join(), "foo,bar,baz,quux");
var code = wasmTextToBinary('(module)'); var e = new Instance(new Module(code)).exports;
assertEq(Object.keys(e).length, 0);
var code = wasmTextToBinary('(module (func) (export "foo" (func 0)))'); var e = new Instance(new Module(code)).exports;
assertEq(Object.keys(e).join(), "foo");
assertEq(e.foo(), undefined);
var code = wasmTextToBinary('(module (func) (export "foo" (func 0)) (export "bar" (func 0)))'); var e = new Instance(new Module(code)).exports;
assertEq(Object.keys(e).join(), "foo,bar");
assertEq(e.foo(), undefined);
assertEq(e.bar(), undefined);
assertEq(e.foo, e.bar);
var code = wasmTextToBinary('(module (memory 1 1) (export "memory" (memory 0)))'); var e = new Instance(new Module(code)).exports;
assertEq(Object.keys(e).join(), "memory");
var code = wasmTextToBinary('(module (memory 1 1) (export "foo" (memory 0)) (export "bar" (memory 0)))'); var e = new Instance(new Module(code)).exports;
assertEq(Object.keys(e).join(), "foo,bar");
assertEq(e.foo, e.bar);
assertEq(e.foo instanceof Memory, true);
assertEq(e.foo.buffer.byteLength, 64*1024);
var code = wasmTextToBinary('(module (memory 1 1) (func) (export "foo" (func 0)) (export "bar" (memory 0)))'); var e = new Instance(new Module(code)).exports;
assertEq(Object.keys(e).join(), "foo,bar");
assertEq(e.foo(), undefined);
assertEq(e.bar instanceof Memory, true);
assertEq(e.bar instanceof Memory, true);
assertEq(e.bar.buffer.byteLength, 64*1024);
var code = wasmTextToBinary('(module (memory 1 1) (func) (export "bar" (memory 0)) (export "foo" (func 0)))'); var e = new Instance(new Module(code)).exports;
assertEq(Object.keys(e).join(), "bar,foo");
assertEq(e.foo(), undefined);
assertEq(e.bar.buffer.byteLength, 64*1024);
var code = wasmTextToBinary('(module (memory 1 1) (export "" (memory 0)))'); var e = new Instance(new Module(code)).exports;
assertEq(Object.keys(e).length, 1);
assertEq(String(Object.keys(e)), "");
assertEq(e[""] instanceof Memory, true);
var code = wasmTextToBinary('(module (table 0 funcref) (export "tbl" (table 0)))'); var e = new Instance(new Module(code)).exports;
assertEq(Object.keys(e).join(), "tbl");
assertEq(e.tbl instanceof Table, true);
assertEq(e.tbl.length, 0);
var code = wasmTextToBinary('(module (table 2 funcref) (export "t1" (table 0)) (export "t2" (table 0)))'); var e = new Instance(new Module(code)).exports;
assertEq(Object.keys(e).join(), "t1,t2");
assertEq(e.t1 instanceof Table, true);
assertEq(e.t2 instanceof Table, true);
assertEq(e.t1, e.t2);
assertEq(e.t1.length, 2);
var code = wasmTextToBinary('(module (import "a" "b" (memory 1 1)) (export "foo" (memory 0)) (export "bar" (memory 0)))'); var mem = new Memory({initial:1, maximum:1}); var e = new Instance(new Module(code), {a:{b:mem}}).exports;
assertEq(mem, e.foo);
assertEq(mem, e.bar);
var code = wasmTextToBinary('(module (import "a" "b" (table 1 1 funcref)) (export "foo" (table 0)) (export "bar" (table 0)))'); var tbl = new Table({initial:1, maximum:1, element:"anyfunc"}); var e = new Instance(new Module(code), {a:{b:tbl}}).exports;
assertEq(tbl, e.foo);
assertEq(tbl, e.bar);
var code = wasmTextToBinary('(module (import "a" "b" (table 2 2 funcref)) (func $foo) (elem (i32.const 0) $foo) (export "foo" (func $foo)))'); var tbl = new Table({initial:2, maximum:2, element:"anyfunc"}); var e1 = new Instance(new Module(code), {a:{b:tbl}}).exports;
assertEq(e1.foo, tbl.get(0));
tbl.set(1, e1.foo);
assertEq(e1.foo, tbl.get(1)); var e2 = new Instance(new Module(code), {a:{b:tbl}}).exports;
assertEq(e2.foo, tbl.get(0));
assertEq(e1.foo, tbl.get(1));
assertEq(tbl.get(0) === e1.foo, false);
assertEq(e1.foo === e2.foo, false);
// i64 is fully allowed for imported wasm functions
var code1 = wasmTextToBinary('(module (func $exp (param i64) (result i64) (i64.add (local.get 0) (i64.const 10))) (export "exp" (func $exp)))'); var e1 = new Instance(new Module(code1)).exports; var code2 = wasmTextToBinary('(module (import "a" "b" (func $i (param i64) (result i64))) (func $f (result i32) (i32.wrap_i64 (call $i (i64.const 42)))) (export "f" (func $f)))'); var e2 = new Instance(new Module(code2), {a:{b:e1.exp}}).exports;
assertEq(e2.f(), 52);
// Non-existent export errors
wasmFailValidateText('(module (export "a" (func 0)))', /exported function index out of bounds/);
wasmFailValidateText('(module (export "a" (global 0)))', /exported global index out of bounds/);
wasmFailValidateText('(module (export "a" (memory 0)))', /exported memory index out of bounds/);
wasmFailValidateText('(module (export "a" (table 0)))', /exported table index out of bounds/);
// Default memory/table rules if (!wasmMultiMemoryEnabled()) {
wasmFailValidateText('(module (import "a" "b" (memory 1 1)) (memory 1 1))', /already have default memory/);
wasmFailValidateText('(module (import "a" "b" (memory 1 1)) (import "x" "y" (memory 2 2)))', /already have default memory/);
}
// Data segments on imports
var m = new Module(wasmTextToBinary(`
(module
(import"a""b" (memory 1 1))
(data (i32.const 0) "\\0a\\0b")
(data (i32.const 100) "\\0c\\0d")
(func $get (param $p i32) (result i32)
(i32.load8_u (local.get $p)))
(export "get" (func $get)))
`)); var mem = new Memory({initial:1, maximum:1}); var {get} = new Instance(m, {a:{b:mem}}).exports;
assertEq(get(0), 0xa);
assertEq(get(1), 0xb);
assertEq(get(2), 0x0);
assertEq(get(100), 0xc);
assertEq(get(101), 0xd);
assertEq(get(102), 0x0); var i8 = new Uint8Array(mem.buffer);
assertEq(i8[0], 0xa);
assertEq(i8[1], 0xb);
assertEq(i8[2], 0x0);
assertEq(i8[100], 0xc);
assertEq(i8[101], 0xd);
assertEq(i8[102], 0x0);
// Data segments with imported offsets
var m = new Module(wasmTextToBinary(`
(module
(import"glob""a" (global i32))
(memory 1)
(data (global.get 0) "\\0a\\0b"))
`));
assertEq(new Instance(m, {glob:{a:0}}) instanceof Instance, true);
assertEq(new Instance(m, {glob:{a:(64*1024 - 2)}}) instanceof Instance, true);
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"))
`));
assertSegmentFitError(() => new Instance(m));
var m = new Module(wasmTextToBinary(`
(module
(memory 0)
(data (i32.const 0x10001) ""))
`));
assertSegmentFitError(() => new Instance(m));
// Errors during segment initialization do not have observable effects // and are checked against the actual memory/table length, not the declared // initial length.
// Active segments are applied in order (this is observable if they overlap). // // Without bulk memory, all range checking for tables and memory happens before // any writes happen, and any OOB will force no writing to happen at all. // // With bulk memory, active segments are applied first for tables and then for // memories. Bounds checking happens for each byte or table element written. // The first OOB aborts the initialization process, leaving written data in // place. Notably, any OOB in table initialization will prevent any memory // initialization from happening at all.
var npages = 2; var mem = new Memory({initial:npages}); var mem8 = new Uint8Array(mem.buffer); var tbl = new Table({initial:2, element:"anyfunc"});
assertSegmentFitError(() => new Instance(m, {a:{mem, tbl, memOff:1, tblOff:2}})); // The first active element segment is applied, but the second active // element segment is completely OOB.
assertEq(typeof tbl.get(0), "function");
assertEq(tbl.get(1), null);
assertEq(mem8[0], 0);
assertEq(mem8[1], 0);
tbl.set(0, null);
tbl.set(1, null);
assertSegmentFitError(() => new Instance(m, {a:{mem, tbl, memOff:npages*64*1024, tblOff:1}})); // The first and second active element segments are applied fully. The // first active data segment applies, but the second one is completely OOB.
assertEq(typeof tbl.get(0), "function");
assertEq(typeof tbl.get(1), "function");
assertEq(mem8[0], 1);
tbl.set(0, null);
tbl.set(1, null);
mem8[0] = 0;
// Both element and data segments apply successfully without OOB
var i = new Instance(m, {a:{mem, tbl, memOff:npages*64*1024-1, tblOff:1}});
assertEq(mem8[0], 1);
assertEq(mem8[npages*64*1024-1], 2);
assertEq(tbl.get(0), i.exports.f);
assertEq(tbl.get(1), i.exports.g);
// Element segment doesn't apply and prevents subsequent elem segment and // data segment from being applied.
var m = new Module(wasmTextToBinary(
`(module
(import"""mem" (memory 1))
(import"""tbl" (table 3 funcref))
(elem (i32.const 1) $f $g $h) ;; fails after $f and $g
(elem (i32.const 0) $f) ;; is not applied
(data (i32.const 0) "\\01") ;; is not applied
(func $f)
(func $g)
(func $h))`)); var mem = new Memory({initial:1}); var tbl = new Table({initial:3, element:"anyfunc"});
assertSegmentFitError(() => new Instance(m, {"":{mem, tbl}}));
assertEq(tbl.get(0), null);
assertEq(tbl.get(1), null);
assertEq(tbl.get(2), null); var v = new Uint8Array(mem.buffer);
assertEq(v[0], 0);
// Data segment doesn't apply and prevents subsequent data segment from // being applied.
var m = new Module(wasmTextToBinary(
`(module
(import"""mem" (memory 1))
(data (i32.const 65534) "\\01\\02\\03") ;; fails after 1 and 2
(data (i32.const 0) "\\04") ;; is not applied
)`)); var mem = new Memory({initial:1});
assertSegmentFitError(() => new Instance(m, {"":{mem}})); var v = new Uint8Array(mem.buffer);
assertEq(v[65534], 0);
assertEq(v[65535], 0);
assertEq(v[0], 0);
// Elem segments on imported tables
var m = new Module(wasmTextToBinary(`
(module
(import"a""b" (table 10 funcref))
(elem (i32.const 0) $one $two)
(elem (i32.const 3) $three $four)
(func $one (result i32) (i32.const 1))
(func $two (result i32) (i32.const 2))
(func $three (result i32) (i32.const 3))
(func $four (result i32) (i32.const 4)))
`)); var tbl = new Table({initial:10, element:"anyfunc"}); new Instance(m, {a:{b:tbl}});
assertEq(tbl.get(0)(), 1);
assertEq(tbl.get(1)(), 2);
assertEq(tbl.get(2), null);
assertEq(tbl.get(3)(), 3);
assertEq(tbl.get(4)(), 4); for (var i = 5; i < 10; i++)
assertEq(tbl.get(i), null);
var m = new Module(wasmTextToBinary(`
(module
(func $their1 (import"""func") (result i32))
(func $their2 (import"""func"))
(table (import"""table") 4 funcref)
(func $my (result i32) i32.const 13)
(elem (i32.const 1) $my)
(elem (i32.const 2) $their1)
(elem (i32.const 3) $their2)
)
`)); var tbl = new Table({initial:4, element:"anyfunc"}); var f = () => 42; new Instance(m, { "": { table: tbl, func: f} });
assertEq(tbl.get(0), null);
assertEq(tbl.get(1)(), 13);
assertEq(tbl.get(2)(), 42);
assertEq(tbl.get(3)(), undefined);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.