diff options
Diffstat (limited to 'js/src/jit-test/tests/wasm/passive-segs-partial-mem.js')
-rw-r--r-- | js/src/jit-test/tests/wasm/passive-segs-partial-mem.js | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/passive-segs-partial-mem.js b/js/src/jit-test/tests/wasm/passive-segs-partial-mem.js new file mode 100644 index 0000000000..5e9351ef8a --- /dev/null +++ b/js/src/jit-test/tests/wasm/passive-segs-partial-mem.js @@ -0,0 +1,174 @@ +let conf = getBuildConfiguration(); +if (conf.debug && + (conf["arm-simulator"] || conf["arm64-simulator"] || + conf["mips32-simulator"] || conf["mips64-simulator"])) +{ + // Will timeout, so just quit early. + quit(0); +} + +// Sundry test cases for the "partial write" bounds checking semantics. + +const PAGESIZE = 65536; + +// memory.fill: out of bounds, should not perform writes +// +// Arithmetic overflow of memory offset + len should not affect the behavior, we +// should still fill up to the limit. + +function mem_fill(min, max, shared, backup, write=backup*2) { + if (shared == "shared" && !sharedMemoryEnabled()) + return; + let ins = wasmEvalText( + `(module + (memory (export "mem") ${min} ${max} ${shared}) + (func (export "run") (param $offs i32) (param $val i32) (param $len i32) + (memory.fill (local.get $offs) (local.get $val) (local.get $len))))`); + // A fill past the end should throw *and* not have filled all the way up to + // the end + let offs = min*PAGESIZE - backup; + let val = 37; + assertErrorMessage(() => ins.exports.run(offs, val, write), + WebAssembly.RuntimeError, + /index out of bounds/); + let v = new Uint8Array(ins.exports.mem.buffer); + for (let i=0; i < backup; i++) + assertEq(v[offs+i], 0); + for (let i=0; i < offs; i++) + assertEq(v[i], 0); +} + +mem_fill(1, 1, "", 256); +mem_fill(1, 1, "", 257); +mem_fill(1, 1, "", 257, 0xFFFFFFFF); // offs + len overflows 32-bit + +mem_fill(2, 4, "shared", 256); +mem_fill(2, 4, "shared", 257); +mem_fill(2, 4, "shared", 257, 0xFFFFFFFF); // offs + len overflows 32-bit + +// memory.init: out of bounds of the memory or the segment, and should not perform +// the operation at all. +// +// Arithmetic overflow of memoffset + len or of bufferoffset + len should not +// affect the behavior. + +// Note, the length of the data segment is 16. +const mem_init_len = 16; + +function mem_init(min, max, shared, backup, write) { + if (shared == "shared" && !sharedMemoryEnabled()) + return; + let ins = wasmEvalText( + `(module + (memory (export "mem") ${min} ${max} ${shared}) + (data "\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42") + (func (export "run") (param $offs i32) (param $len i32) + (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))`); + // A fill writing past the end of the memory should throw *and* not have filled + // all the way up to the end. + // + // A fill reading past the end of the segment should throw *and* not have filled + // memory with as much data as was available. + let offs = min*PAGESIZE - backup; + assertErrorMessage(() => ins.exports.run(offs, write), + WebAssembly.RuntimeError, + /index out of bounds/); + let v = new Uint8Array(ins.exports.mem.buffer); + for (let i=0; i < min; i++) + assertEq(v[offs + i], 0); +} + +// We exceed the bounds of the memory but not of the data segment +mem_init(1, 1, "", Math.floor(mem_init_len/2), mem_init_len); +mem_init(1, 1, "", Math.floor(mem_init_len/2)+1, mem_init_len); +mem_init(2, 4, "shared", Math.floor(mem_init_len/2), mem_init_len); +mem_init(2, 4, "shared", Math.floor(mem_init_len/2)+1, mem_init_len); + +// We exceed the bounds of the data segment but not the memory +mem_init(1, 1, "", mem_init_len*4, mem_init_len*2-2); +mem_init(1, 1, "", mem_init_len*4-1, mem_init_len*2-1); +mem_init(2, 4, "shared", mem_init_len*4, mem_init_len*2-2); +mem_init(2, 4, "shared", mem_init_len*4-1, mem_init_len*2-1); + +// We arithmetically overflow the memory limit but not the segment limit +mem_init(1, "", "", Math.floor(mem_init_len/2), 0xFFFFFF00); + +// We arithmetically overflow the segment limit but not the memory limit +mem_init(1, "", "", PAGESIZE, 0xFFFFFFFC); + +// memory.copy: out of bounds of the memory for the source or target, and should +// not perform at all. Major cases: +// +// - non-overlapping regions +// - overlapping regions with src >= dest +// - overlapping regions with src == dest +// - overlapping regions with src < dest +// - arithmetic overflow on src addresses +// - arithmetic overflow on target addresses +// +// for each of those, +// +// - src address oob +// - target address oob +// - both oob + +function mem_copy(min, max, shared, srcOffs, targetOffs, len) { + if (shared == "shared" && !sharedMemoryEnabled()) + return; + let ins = wasmEvalText( + `(module + (memory (export "mem") ${min} ${max} ${shared}) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))`); + + let v = new Uint8Array(ins.exports.mem.buffer); + + let copyDown = srcOffs < targetOffs; + let targetAvail = v.length - targetOffs; + let srcAvail = v.length - srcOffs; + let srcLim = srcOffs + Math.min(len, targetAvail, srcAvail); + + for (let i=srcOffs, j=0; i < srcLim; i++, j++) + v[i] = j; + assertErrorMessage(() => ins.exports.run(targetOffs, srcOffs, len), + WebAssembly.RuntimeError, + /index out of bounds/); + + for (var i=0, s=0; i < v.length; i++ ) { + if (i >= srcOffs && i < srcLim) { + assertEq(v[i], (s++) & 0xFF); + continue; + } + assertEq(v[i], 0); + } +} + +// OOB target address, nonoverlapping +mem_copy(1, 1, "", 0, PAGESIZE-20, 40); +mem_copy(1, 1, "", 0, PAGESIZE-21, 39); +mem_copy(2, 4, "shared", 0, 2*PAGESIZE-20, 40); +mem_copy(2, 4, "shared", 0, 2*PAGESIZE-21, 39); + +// OOB source address, nonoverlapping +mem_copy(1, 1, "", PAGESIZE-20, 0, 40); +mem_copy(1, 1, "", PAGESIZE-21, 0, 39); +mem_copy(2, 4, "shared", 2*PAGESIZE-20, 0, 40); +mem_copy(2, 4, "shared", 2*PAGESIZE-21, 0, 39); + +// OOB target address, overlapping, src < target +mem_copy(1, 1, "", PAGESIZE-50, PAGESIZE-20, 40); + +// OOB source address, overlapping, target < src +mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-50, 40); + +// OOB both, overlapping, including target == src +mem_copy(1, 1, "", PAGESIZE-30, PAGESIZE-20, 40); +mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-30, 40); +mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-20, 40); + +// Arithmetic overflow on source address. +mem_copy(1, "", "", PAGESIZE-20, 0, 0xFFFFF000); + +// Arithmetic overflow on target adddress is an overlapping case. +mem_copy(1, 1, "", PAGESIZE-0x1000, PAGESIZE-20, 0xFFFFFF00); + |