// Perform a test which, // // * if errKind is defined, is expected to fail with an exception // characterised by errKind and errText. // // * if errKind is undefined, is expected to succeed, in which case errKind // and errText are ignored. // // The function body will be [insn1, insn2] and is constructed according to // four booleans: // // * isMem controls whether the module is constructed with memory or // table initializers. // // * haveStorage determines whether there is actually a memory or table to // work with. // // * haveInitA controls whether active initializers are added. // // * haveInitP controls whether passive initializers are added.
// The tested semantics for memory.drop, in the case where there's no memory, // are as follows. table.drop is analogous. // // no memory, no data segments: // drop with any args -> fail OOB // [because there's nothing to drop] // // no memory, data segments, at least one of which is active: // -> always fails, regardless of insns // [because active segments implicitly reference memory 0] // // no memory, data segments, all of which are passive: // drop, segment index is OOB -> fail OOB // [because it refers to non existent segment] // // drop, segment index is IB -> OK
// drop with no memory and no data segments
mem_test("data.drop 0", "",
WebAssembly.CompileError, /(data.drop segment index out of range)|(unknown data segment 0)/, /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/false);
// drop with no memory but with both passive and active segments, ix in range // and refers to a passive segment
mem_test("data.drop 3", "",
WebAssembly.CompileError,
/active data segment requires a memory section/, /*haveStorage=*/false, /*haveInitA=*/true, /*haveInitP=*/true);
// drop with no memory but with passive segments only, ix out of range
mem_test("data.drop 2", "",
WebAssembly.CompileError, /(data.drop segment index out of range)|(unknown data segment 2)/, /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/true);
// drop with no memory but with passive segments only, ix in range
mem_test_nofail("data.drop 1", "", /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/true);
// init with no memory and no data segs
mem_test("(memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))", "",
WebAssembly.CompileError, /memory index/, /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/false);
// drop with data seg ix out of range
mem_test("data.drop 4", "",
WebAssembly.CompileError, /(data.drop segment index out of range)|(unknown data segment 4)/);
// init with data seg ix out of range
mem_test("(memory.init 4 (i32.const 1234) (i32.const 1) (i32.const 1))", "",
WebAssembly.CompileError, /(memory.init segment index out of range)|(unknown data segment 4)/);
// drop with data seg ix indicating an active segment
mem_test("data.drop 2", "");
// init with data seg ix indicating an active segment
mem_test("(memory.init 2 (i32.const 1234) (i32.const 1) (i32.const 1))", "",
WebAssembly.RuntimeError, /index out of bounds/);
// init, using a data seg ix more than once is OK
mem_test_nofail( "(memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))", "(memory.init 1 (i32.const 4321) (i32.const 1) (i32.const 1))");
// drop, then drop
mem_test("data.drop 1", "data.drop 1");
// drop, then init
mem_test("data.drop 1", "(memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))",
WebAssembly.RuntimeError, /index out of bounds/);
// init: seg ix is valid passive, but length to copy > len of seg
mem_test("", "(memory.init 1 (i32.const 1234) (i32.const 0) (i32.const 5))",
WebAssembly.RuntimeError, /index out of bounds/);
// init: seg ix is valid passive, but implies copying beyond end of seg
mem_test("", "(memory.init 1 (i32.const 1234) (i32.const 2) (i32.const 3))",
WebAssembly.RuntimeError, /index out of bounds/);
// init: seg ix is valid passive, but implies copying beyond end of dst
mem_test("", "(memory.init 1 (i32.const 0xFFFE) (i32.const 1) (i32.const 3))",
WebAssembly.RuntimeError, /index out of bounds/);
// init: seg ix is valid passive, zero len, but src offset out of bounds at the // edge
mem_test("", "(memory.init 1 (i32.const 1234) (i32.const 4) (i32.const 0))");
// init: seg ix is valid passive, zero len, but src offset out of bounds one // past the edge
mem_test("", "(memory.init 1 (i32.const 1234) (i32.const 5) (i32.const 0))",
WebAssembly.RuntimeError, /index out of bounds/);
// init: seg ix is valid passive, zero len, but dst offset out of bounds at the // edge
mem_test("", "(memory.init 1 (i32.const 0x10000) (i32.const 2) (i32.const 0))");
// init: seg ix is valid passive, zero len, but dst offset out of bounds one // past the edge
mem_test("", "(memory.init 1 (i32.const 0x10001) (i32.const 2) (i32.const 0))",
WebAssembly.RuntimeError, /index out of bounds/);
// drop: too many args
mem_test("data.drop 1 (i32.const 42)", "",
WebAssembly.CompileError,
/(unused values not explicitly dropped by end of block)|(values remaining on stack at end of block)/);
// init: too many args
mem_test("(memory.init 1 (i32.const 1) (i32.const 1) (i32.const 1) (i32.const 1))", "",
WebAssembly.CompileError, /(unused values)|(values remaining on stack at end of block)/);
// init: too few args
mem_test("(memory.init 1 (i32.const 1) (i32.const 1))", "",
WebAssembly.CompileError,
/(popping value from empty stack)|(expected i32 but nothing on stack)/);
for (let ty1 of tys) { for (let ty2 of tys) { for (let ty3 of tys) { if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32') continue; // this is the only valid case
let i1 = `(memory.init 1 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1))`;
mem_test(i1, "", WebAssembly.CompileError, /type mismatch/);
}}}
}
// drop with no tables and no elem segments
tab_test("elem.drop 0", "",
WebAssembly.CompileError,
/(element segment index out of range for elem.drop)|(segment index out of bounds)/, /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/false);
// drop with no tables but with both passive and active segments, ix in range // and refers to a passive segment
tab_test("elem.drop 3", "",
WebAssembly.CompileError,
/active elem segment requires a table/, /*haveStorage=*/false, /*haveInitA=*/true, /*haveInitP=*/true);
// drop with no tables but with passive segments only, ix out of range
tab_test("elem.drop 2", "",
WebAssembly.CompileError,
/(element segment index out of range for elem.drop)|(segment index out of bounds)/, /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/true);
// drop with no tables but with passive segments only, ix in range
tab_test_nofail("elem.drop 1", "", /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/true);
// init with no table
tab_test("(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))", "",
WebAssembly.CompileError, /(table index out of range)|(table index out of bounds)/, /*haveStorage=*/false, /*haveInitA=*/false, /*haveInitP=*/false);
// drop with elem seg ix out of range
tab_test("elem.drop 4", "",
WebAssembly.CompileError, /(element segment index out of range for elem.drop)|(segment index out of bounds)/);
// init with elem seg ix out of range
tab_test("(table.init 4 (i32.const 12) (i32.const 1) (i32.const 1))", "",
WebAssembly.CompileError, /(table.init segment index out of range)|(segment index out of bounds)/);
// drop with elem seg ix indicating an active segment
tab_test("elem.drop 2", "");
// init with elem seg ix indicating an active segment
tab_test("(table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))", "",
WebAssembly.RuntimeError, /index out of bounds/);
// init, using an elem seg ix more than once is OK
tab_test_nofail( "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))", "(table.init 1 (i32.const 21) (i32.const 1) (i32.const 1))");
// drop, then drop
tab_test("elem.drop 1", "elem.drop 1");
// drop, then init
tab_test("elem.drop 1", "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))",
WebAssembly.RuntimeError, /index out of bounds/);
// init: seg ix is valid passive, but length to copy > len of seg
tab_test("", "(table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))",
WebAssembly.RuntimeError, /index out of bounds/);
// init: seg ix is valid passive, but implies copying beyond end of seg
tab_test("", "(table.init 1 (i32.const 12) (i32.const 2) (i32.const 3))",
WebAssembly.RuntimeError, /index out of bounds/);
// init: seg ix is valid passive, but implies copying beyond end of dst
tab_test("", "(table.init 1 (i32.const 28) (i32.const 1) (i32.const 3))",
WebAssembly.RuntimeError, /index out of bounds/);
// init: seg ix is valid passive, zero len, but src offset out of bounds at the // edge
tab_test("", "(table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))");
// init: seg ix is valid passive, zero len, but src offset out of bounds one // past the edge
tab_test("", "(table.init 1 (i32.const 12) (i32.const 5) (i32.const 0))",
WebAssembly.RuntimeError, /index out of bounds/);
// init: seg ix is valid passive, zero len, but dst offset out of bounds
tab_test("", "(table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))");
// init: seg ix is valid passive, zero len, but dst offset out of bounds one // past the edge
tab_test("", "(table.init 1 (i32.const 31) (i32.const 2) (i32.const 0))",
WebAssembly.RuntimeError, /index out of bounds/);
// drop: too many args
tab_test("elem.drop 1 (i32.const 42)", "",
WebAssembly.CompileError,
/(unused values not explicitly dropped by end of block)|(values remaining on stack at end of block)/);
// init: too many args
tab_test("(table.init 1 (i32.const 1) (i32.const 1) (i32.const 1) (i32.const 1))", "",
WebAssembly.CompileError, /(unused values)|(values remaining on stack at end of block)/);
// init: too few args
tab_test("(table.init 1 (i32.const 1) (i32.const 1))", "",
WebAssembly.CompileError,
/(popping value from empty stack)|(expected i32 but nothing on stack)/);
const ops = ['table.init 1', 'table.copy']; for (let ty1 of tys) { for (let ty2 of tys) { for (let ty3 of tys) { for (let op of ops) { if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32') continue; // this is the only valid case
let i1 = `(${op} (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1))`;
tab_test(i1, "", WebAssembly.CompileError, /type mismatch/);
}}}}
}
// There are no immediates here, only 3 dynamic args. So we're limited to // runtime boundary checks.
// passive-segs-smoketest.js tests the normal, non-exception cases of // table.copy. Here we just test the boundary-failure cases. The // table's valid indices are 0 .. 29 inclusive.
// copy: dst range invalid
tab_test("(table.copy (i32.const 28) (i32.const 1) (i32.const 3))", "",
WebAssembly.RuntimeError, /index out of bounds/);
// copy: dst wraparound end of 32 bit offset space
tab_test("(table.copy (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2))", "",
WebAssembly.RuntimeError, /index out of bounds/);
// copy: src range invalid
tab_test("(table.copy (i32.const 15) (i32.const 25) (i32.const 6))", "",
WebAssembly.RuntimeError, /index out of bounds/);
// copy: src wraparound end of 32 bit offset space
tab_test("(table.copy (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2))", "",
WebAssembly.RuntimeError, /index out of bounds/);
// copy: zero length with both offsets in-bounds is OK
tab_test_nofail( "(table.copy (i32.const 15) (i32.const 25) (i32.const 0))", "");
// copy: zero length with dst offset out of bounds at the edge
tab_test("(table.copy (i32.const 30) (i32.const 15) (i32.const 0))", "");
// copy: zero length with dst offset out of bounds one past the edge
tab_test("(table.copy (i32.const 31) (i32.const 15) (i32.const 0))", "", WebAssembly.RuntimeError, /index out of bounds/);
// copy: zero length with src offset out of bounds at the edge
tab_test("(table.copy (i32.const 15) (i32.const 30) (i32.const 0))", "");
// copy: zero length with src offset out of bounds one past the edge
tab_test("(table.copy (i32.const 15) (i32.const 31) (i32.const 0))", "", WebAssembly.RuntimeError, /index out of bounds/);
Messung V0.5
¤ Dauer der Verarbeitung: 0.29 Sekunden
(vorverarbeitet)
¤
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.