summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/wasm/passive-segs-partial-mem.js
diff options
context:
space:
mode:
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.js174
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);
+