From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- js/src/jit-test/tests/wasm/large-memory.js | 328 +++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 js/src/jit-test/tests/wasm/large-memory.js (limited to 'js/src/jit-test/tests/wasm/large-memory.js') diff --git a/js/src/jit-test/tests/wasm/large-memory.js b/js/src/jit-test/tests/wasm/large-memory.js new file mode 100644 index 0000000000..20c9c3b371 --- /dev/null +++ b/js/src/jit-test/tests/wasm/large-memory.js @@ -0,0 +1,328 @@ +// |jit-test| skip-if: !largeArrayBufferSupported(); allow-oom + +var pagesz = PageSizeInBytes; +var pages_limit = MaxPagesIn32BitMemory; + +// 40000 is well above 2GB but not anything that might run into boundary +// conditions near 4GB. +var pages_vanilla = 40000; + +for ( let [pages,maxpages] of [[pages_vanilla, pages_vanilla+100], + [pages_limit - 3, pages_limit], + [pages_limit, pages_limit]] ) { + assertEq(pages == maxpages || maxpages - pages >= 3, true) + let ins = wasmEvalText(` +(module + (memory (export "mem") ${pages} ${maxpages}) + + (data (i32.const ${(pages-5)*pagesz}) "yabbadabbado") + (data $flintstone "yabbadabbado") + + (func (export "get_constaddr") (result i32) + (i32.load (i32.const ${pages*pagesz-4}))) + + (func (export "get_varaddr") (param $p i32) (result i32) + (i32.load (local.get $p))) + + (func (export "set_constaddr") (param $v i32) + (i32.store (i32.const ${pages*pagesz-8}) (local.get $v))) + + (func (export "set_varaddr") (param $p i32) (param $v i32) + (i32.store (local.get $p) (local.get $v))) + + (func (export "get_constaddr_large_offset") (result i32) + (i32.load offset=${(pages-100)*pagesz-4} (i32.const ${pagesz*100}))) + + (func (export "get_varaddr_large_offset") (param $p i32) (result i32) + (i32.load offset=${(pages-100)*pagesz-4} (local.get $p))) + + (func (export "get_constaddr_small_offset") (result i32) + (i32.load offset=${pagesz-4} (i32.const ${(pages-1)*pagesz}))) + + (func (export "get_varaddr_small_offset") (param $p i32) (result i32) + (i32.load offset=${pagesz-4} (local.get $p))) + + (func (export "set_constaddr_large_offset") (param $v i32) + (i32.store offset=${(pages-100)*pagesz-16} (i32.const ${pagesz*100}) (local.get $v))) + + (func (export "set_varaddr_large_offset") (param $p i32) (param $v i32) + (i32.store offset=${(pages-100)*pagesz-20} (local.get $p) (local.get $v))) + + (func (export "set_constaddr_small_offset") (param $v i32) + (i32.store offset=${pagesz-24} (i32.const ${(pages-1)*pagesz}) (local.get $v))) + + (func (export "set_varaddr_small_offset") (param $p i32) (param $v i32) + (i32.store offset=${pagesz-28} (local.get $p) (local.get $v))) + + (func (export "copy") (param $dest i32) (param $src i32) + (memory.copy (local.get $dest) (local.get $src) (i32.const 12))) + + (func (export "init") (param $dest i32) + (memory.init $flintstone (local.get $dest) (i32.const 0) (i32.const 12))) + + (func (export "fill") (param $dest i32) (param $val i32) (param $len i32) + (memory.fill (local.get 0) (local.get 1) (local.get 2))) + + (func (export "grow1") (result i32) + (memory.grow (i32.const 1))) +)`); + + let buf = new Int32Array(ins.exports.mem.buffer); + + let checkFlintstoneAt = function (addr) { + assertEq(buf[addr/4], 0x62626179) // "yabb", little-endian + assertEq(buf[addr/4+1], 0x62616461) // "adab", ditto + assertEq(buf[addr/4+2], 0x6f646162) // "bado" + } + + buf[pages*pagesz/4-1] = 0xdeadbeef; + assertEq(ins.exports.get_constaddr(), 0xdeadbeef|0); + assertEq(ins.exports.get_varaddr(pages*pagesz-4), 0xdeadbeef|0); + + assertEq(ins.exports.get_constaddr_large_offset(), 0xdeadbeef|0); + assertEq(ins.exports.get_varaddr_large_offset(pagesz*100), 0xdeadbeef|0); + + assertEq(ins.exports.get_constaddr_small_offset(), 0xdeadbeef|0); + assertEq(ins.exports.get_varaddr_small_offset((pages-1)*pagesz), 0xdeadbeef|0); + + ins.exports.set_constaddr(0xcafebab0); + assertEq(buf[pages*pagesz/4-2], 0xcafebab0|0); + + ins.exports.set_varaddr(pages*pagesz-12, 0xcafebab1); + assertEq(buf[pages*pagesz/4-3], 0xcafebab1|0); + + ins.exports.set_constaddr_large_offset(0xcafebab2); + assertEq(buf[pages*pagesz/4-4], 0xcafebab2|0); + + ins.exports.set_varaddr_large_offset(pagesz*100, 0xcafebab3); + assertEq(buf[pages*pagesz/4-5], 0xcafebab3|0); + + ins.exports.set_constaddr_small_offset(0xcafebab4); + assertEq(buf[pages*pagesz/4-6], 0xcafebab4|0); + + ins.exports.set_varaddr_small_offset((pages-1)*pagesz, 0xcafebab5); + assertEq(buf[pages*pagesz/4-7], 0xcafebab5|0); + + if (pages*pagesz < 0x1_0000_0000) { + assertErrorMessage(() => ins.exports.get_varaddr(pages*pagesz), + WebAssembly.RuntimeError, + /index out of bounds/); + } + + assertErrorMessage(() => ins.exports.get_varaddr_large_offset(pagesz*100+4), + WebAssembly.RuntimeError, + /index out of bounds/); + + assertErrorMessage(() => ins.exports.get_varaddr_small_offset((pages-1)*pagesz+4), + WebAssembly.RuntimeError, + /index out of bounds/); + + ins.exports.set_varaddr(pages*pagesz-4, 0); // Should work + if (pages*pagesz < 0x1_0000_0000) { + assertErrorMessage(() => ins.exports.set_varaddr(pages*pagesz, 0), + WebAssembly.RuntimeError, + /index out of bounds/); + } + + ins.exports.set_varaddr_large_offset(pagesz*100+16, 0); // Should work + assertErrorMessage(() => ins.exports.set_varaddr_large_offset(pagesz*100+20, 0), + WebAssembly.RuntimeError, + /index out of bounds/); + + ins.exports.set_varaddr_small_offset((pages-1)*pagesz+24); // Should work + assertErrorMessage(() => ins.exports.set_varaddr_small_offset((pages-1)*pagesz+28, 0), + WebAssembly.RuntimeError, + /index out of bounds/); + + // Active init + checkFlintstoneAt((pages-5)*pagesz); + + // memory.init + ins.exports.init((pages-6)*pagesz); + checkFlintstoneAt((pages-6)*pagesz); + + ins.exports.init(pages*pagesz-12); // Should work + // Dest goes OOB + assertErrorMessage(() => ins.exports.init(pages*pagesz-6), + WebAssembly.RuntimeError, + /index out of bounds/); + + // memory.copy + + // Dest and src are in bounds + ins.exports.copy((pages-10)*pagesz, (pages-5)*pagesz); + checkFlintstoneAt((pages-10)*pagesz); + + // Dest goes OOB + assertErrorMessage(() => ins.exports.copy((pages)*pagesz-6, (pages-5)*pagesz, 12), + WebAssembly.RuntimeError, + /index out of bounds/); + + ins.exports.copy((pages)*pagesz-12, (pages-1)*pagesz); // Should work + // Src goes OOB + assertErrorMessage(() => ins.exports.copy((pages)*pagesz-12, (pages)*pagesz-6), + WebAssembly.RuntimeError, + /index out of bounds/); + + + // memory.fill + let lastpg = (pages-1)*pagesz; + ins.exports.fill(lastpg, 0x37, pagesz); + for ( let i=0; i < pagesz/4; i++ ) + assertEq(buf[lastpg/4+i], 0x37373737); + + assertErrorMessage(() => ins.exports.fill(lastpg, 0x42, pagesz+1), + WebAssembly.RuntimeError, + /index out of bounds/); + + done: + if (pages < maxpages) { + let res = 0; + + res = ins.exports.grow1(); + if (res == -1) break done; + assertEq(res, pages); + + res = ins.exports.grow1(); + if (res == -1) break done; + assertEq(res, pages+1); + + res = ins.exports.grow1(); + if (res == -1) break done; + assertEq(res, pages+2); + + assertEq(ins.exports.get_varaddr((pages+2)*pagesz), 0); + + let i = 0; + while (ins.exports.grow1() != -1) { + i++; + } + // We can't assert equality because we might OOM before we get to the + // max, but we can assert we did not go beyond that. + assertEq(i <= maxpages-pages-3, true); + } +} + +// Very large offsets should be allowed (but may of course be OOB). Observe +// that offset=0xffffffff is accepted by the validator even though this access +// could never succeed. +{ + let ins = wasmEvalText(` +(module + (memory (export "mem") 1) + (func (export "get1") (param $p i32) (result i32) + (i32.load offset=0x80000000 (local.get $p))) + (func (export "get2") (param $p i32) (result i32) + (i32.load offset=0xfffffffc (local.get $p))) + (func (export "get3") (param $p i32) (result i32) + (i32.load offset=0xffffffff (local.get $p)))) +`); + assertErrorMessage(() => ins.exports.get1(0), + WebAssembly.RuntimeError, + /index out of bounds/); + assertErrorMessage(() => ins.exports.get2(0), + WebAssembly.RuntimeError, + /index out of bounds/); + assertErrorMessage(() => ins.exports.get3(0), + WebAssembly.RuntimeError, + /index out of bounds/); +} + +{ + let ins = wasmEvalText(` +(module + (memory (export "mem") 32768) + (func (export "get1") (param $p i32) (result i32) + (i32.load8_s offset=0x7fffffff (local.get $p)))) +`); + assertEq(ins.exports.get1(0), 0); + assertErrorMessage(() => ins.exports.get1(1), + WebAssembly.RuntimeError, + /index out of bounds/); + assertErrorMessage(() => ins.exports.get1(-1), + WebAssembly.RuntimeError, + /index out of bounds/); +} + +{ + let ins = wasmEvalText(` +(module + (memory (export "mem") 32769) + (func (export "get1") (param $p i32) (result i32) + (i32.load8_s offset=0x80000000 (local.get $p)))) +`); + assertEq(ins.exports.get1(0), 0); + assertEq(ins.exports.get1(65535), 0); + assertErrorMessage(() => ins.exports.get1(65536), + WebAssembly.RuntimeError, + /index out of bounds/); +} + +{ + let ins = wasmEvalText(` +(module + (memory (export "mem") ${pages_limit}) + (func (export "get1") (param $p i32) (result i32) + (i32.load8_s offset=${pages_limit*pagesz-1} (local.get $p)))) +`); + assertEq(ins.exports.get1(0), 0); + assertErrorMessage(() => ins.exports.get1(1), + WebAssembly.RuntimeError, + /index out of bounds/); + assertErrorMessage(() => ins.exports.get1(-1), + WebAssembly.RuntimeError, + /index out of bounds/); +} + +// Fail to grow at the declared max +// Import and export + +{ + let ins = wasmEvalText(` +(module + (memory (export "mem") ${pages_limit} ${pages_limit}) + + (func (export "set_it") (param $addr i32) (param $val i32) + (i32.store (local.get $addr) (local.get $val))) + + (func (export "grow1") (result i32) + (memory.grow (i32.const 1))) +)`); + + assertEq(ins.exports.grow1(), -1); // Because initial == max + + let ins2 = wasmEvalText(` +(module + (import "" "mem" (memory 1)) + + (func (export "get_it") (param $addr i32) (result i32) + (i32.load (local.get $addr))) +)`, + {"":ins.exports}) + + ins.exports.set_it((pages_limit*pagesz)-4, 0xbaadf00d); + assertEq(ins2.exports.get_it((pages_limit*pagesz)-4), 0xbaadf00d|0) +} + +// Fail to grow at the max heap size even if there is headroom +// in the declared max +if (pages_limit < 65536) { + let ins = wasmEvalText(` +(module + (memory (export "mem") ${pages_limit} ${pages_limit+2}) + + (func (export "grow1") (result i32) + (memory.grow (i32.const 1))) +)`); + + assertEq(ins.exports.grow1(), -1); // Because current is at the max heap size +} + +// Fail to instantiate when the minimum is larger than the max heap size +if (pages_limit < 65536) { + assertErrorMessage(() => wasmEvalText(` +(module (memory (export "mem") ${pages_limit+1} ${pages_limit+1})) +`), + WebAssembly.RuntimeError, + /too many memory pages/); +} -- cgit v1.2.3