memory-partial-oob-store.js (4934B)
1 // Cloned from memory.js but kept separate because it may have to be disabled on 2 // some devices until bugs are fixed. 3 4 // Bug 1666747 - partially OOB unaligned stores are not handled correctly on ARM 5 // and ARM64. The simulators don't implement the correct semantics anyhow, so 6 // when the bug is fixed in the code generator they must remain excluded here. 7 var excluded = getBuildConfiguration("arm64") || 8 getBuildConfiguration("arm64-simulator") || 9 getBuildConfiguration("arm") || 10 getBuildConfiguration("arm-simulator") || 11 getBuildConfiguration("riscv64"); 12 var thirtytwobit = getBuildConfiguration("pointer-byte-size") == 4; 13 14 const RuntimeError = WebAssembly.RuntimeError; 15 16 function storeModuleSrc(type, ext, offset, align) { 17 var load_ext = ext === '' ? '' : ext + '_s'; 18 return `(module 19 (memory (export "mem") 1) 20 (data (i32.const 0) "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f") 21 (data (i32.const 16) "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff") 22 (func $store (param i32) (param ${type}) 23 (${type}.store${ext} 24 offset=${offset} 25 ${align != 0 ? 'align=' + align : ''} 26 (local.get 0) 27 (local.get 1) 28 ) 29 ) (export "store" (func 0)) 30 (func $load (param i32) (result ${type}) 31 (${type}.load${load_ext} 32 offset=${offset} 33 ${align != 0 ? 'align=' + align : ''} 34 (local.get 0) 35 ) 36 ) (export "load" (func 1)))`; 37 } 38 39 function storeModule(type, ext, offset, align, exportBox = null) { 40 let exports = wasmEvalText(storeModuleSrc(type, ext, offset, align)).exports; 41 if (exportBox !== null) 42 exportBox.exports = exports; 43 return exports; 44 } 45 46 function testStoreOOB(type, ext, base, offset, align, value) { 47 let exportBox = {}; 48 if (type === 'i64') { 49 assertErrorMessage(() => wasmAssert( 50 storeModuleSrc(type, ext, offset, align), 51 [{type, func: '$store', args: [`i32.const ${base}`, `i64.const ${value}`]}], 52 {}, 53 exportBox 54 ), RuntimeError, /index out of bounds/); 55 } else { 56 assertErrorMessage(() => storeModule(type, ext, offset, align, exportBox).store(base, value), 57 RuntimeError, 58 /index out of bounds/); 59 } 60 61 // Check that there were no partial writes at the end of the memory. 62 let buf = new Int8Array(exportBox.exports.mem.buffer); 63 let len = buf.length; 64 for ( let addr = base + offset ; addr < len; addr++ ) 65 assertEq(buf[addr], 0); 66 } 67 68 // Test bounds checks and edge cases. 69 70 for (let align of [0,1,2,4]) { 71 72 for (let offset of [0, 1, 2, 3, 4, 8, 16, 41, 0xfff0, 0xfff8]) { 73 // Accesses of 1 byte. 74 let lastValidIndex = 0x10000 - 1 - offset; 75 if (align < 2 && !excluded) { 76 testStoreOOB('i32', '8', lastValidIndex + 1, offset, align, -42); 77 } 78 79 // Accesses of 2 bytes. 80 lastValidIndex = 0x10000 - 2 - offset; 81 if (align < 4 && !excluded) { 82 testStoreOOB('i32', '16', lastValidIndex + 1, offset, align, -32768); 83 } 84 85 // Accesses of 4 bytes. 86 lastValidIndex = 0x10000 - 4 - offset; 87 if (!excluded) { 88 testStoreOOB('i32', '', lastValidIndex + 1, offset, align, 1337); 89 testStoreOOB('f32', '', lastValidIndex + 1, offset, align, Math.fround(13.37)); 90 } 91 92 // Accesses of 8 bytes. 93 lastValidIndex = 0x10000 - 8 - offset; 94 if (!excluded) { 95 testStoreOOB('f64', '', lastValidIndex + 1, offset, align, 1.23456789); 96 } 97 } 98 99 for (let offset of [0, 1, 2, 3, 4, 8, 16, 41, 0xfff0, 0xfff8]) { 100 // Accesses of 1 byte. 101 let lastValidIndex = 0x10000 - 1 - offset; 102 if (align < 2 && !excluded) { 103 testStoreOOB('i64', '8', lastValidIndex + 1, offset, align, -42); 104 } 105 106 // Accesses of 2 bytes. 107 lastValidIndex = 0x10000 - 2 - offset; 108 if (align < 4 && !excluded) { 109 testStoreOOB('i64', '16', lastValidIndex + 1, offset, align, -32768); 110 } 111 112 // Accesses of 4 bytes. 113 lastValidIndex = 0x10000 - 4 - offset; 114 if (!excluded) { 115 testStoreOOB('i64', '32', lastValidIndex + 1, offset, align, 0xf1231337 | 0); 116 } 117 118 // Accesses of 8 bytes. 119 lastValidIndex = 0x10000 - 8 - offset; 120 if (!excluded) { 121 testStoreOOB('i64', '', lastValidIndex + 1, offset, align, '0x1234567887654321'); 122 } 123 } 124 } 125 126 // On 32-bit platforms, a declared-aligned i64 store is implemented as two 127 // presumed-aligned 32-bit stores. This tests that we don't store the low 128 // word before the high word if the low word is in-bounds but the high word 129 // is not. 130 if (thirtytwobit) { 131 testStoreOOB('i64', '', 0x10000 - 4, 0, 0, '0x0123456789abcdef'); 132 }