passive-segs-partial-mem.js (6478B)
1 if (getBuildConfiguration("debug") && 2 (getBuildConfiguration("arm-simulator") || getBuildConfiguration("arm64-simulator") || 3 getBuildConfiguration("mips64-simulator"))) 4 { 5 // Will timeout, so just quit early. 6 quit(0); 7 } 8 9 // Sundry test cases for the "partial write" bounds checking semantics. 10 11 const PAGESIZE = 65536; 12 13 // memory.fill: out of bounds, should not perform writes 14 // 15 // Arithmetic overflow of memory offset + len should not affect the behavior, we 16 // should still fill up to the limit. 17 18 function mem_fill(min, max, shared, backup, write=backup*2) { 19 if (shared == "shared" && !sharedMemoryEnabled()) 20 return; 21 let ins = wasmEvalText( 22 `(module 23 (memory (export "mem") ${min} ${max} ${shared}) 24 (func (export "run") (param $offs i32) (param $val i32) (param $len i32) 25 (memory.fill (local.get $offs) (local.get $val) (local.get $len))))`); 26 // A fill past the end should throw *and* not have filled all the way up to 27 // the end 28 let offs = min*PAGESIZE - backup; 29 let val = 37; 30 assertErrorMessage(() => ins.exports.run(offs, val, write), 31 WebAssembly.RuntimeError, 32 /index out of bounds/); 33 let v = new Uint8Array(ins.exports.mem.buffer); 34 for (let i=0; i < backup; i++) 35 assertEq(v[offs+i], 0); 36 for (let i=0; i < offs; i++) 37 assertEq(v[i], 0); 38 } 39 40 mem_fill(1, 1, "", 256); 41 mem_fill(1, 1, "", 257); 42 mem_fill(1, 1, "", 257, 0xFFFFFFFF); // offs + len overflows 32-bit 43 44 mem_fill(2, 4, "shared", 256); 45 mem_fill(2, 4, "shared", 257); 46 mem_fill(2, 4, "shared", 257, 0xFFFFFFFF); // offs + len overflows 32-bit 47 48 // memory.init: out of bounds of the memory or the segment, and should not perform 49 // the operation at all. 50 // 51 // Arithmetic overflow of memoffset + len or of bufferoffset + len should not 52 // affect the behavior. 53 54 // Note, the length of the data segment is 16. 55 const mem_init_len = 16; 56 57 function mem_init(min, max, shared, backup, write) { 58 if (shared == "shared" && !sharedMemoryEnabled()) 59 return; 60 let ins = wasmEvalText( 61 `(module 62 (memory (export "mem") ${min} ${max} ${shared}) 63 (data "\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42") 64 (func (export "run") (param $offs i32) (param $len i32) 65 (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))`); 66 // A fill writing past the end of the memory should throw *and* not have filled 67 // all the way up to the end. 68 // 69 // A fill reading past the end of the segment should throw *and* not have filled 70 // memory with as much data as was available. 71 let offs = min*PAGESIZE - backup; 72 assertErrorMessage(() => ins.exports.run(offs, write), 73 WebAssembly.RuntimeError, 74 /index out of bounds/); 75 let v = new Uint8Array(ins.exports.mem.buffer); 76 for (let i=0; i < min; i++) 77 assertEq(v[offs + i], 0); 78 } 79 80 // We exceed the bounds of the memory but not of the data segment 81 mem_init(1, 1, "", Math.floor(mem_init_len/2), mem_init_len); 82 mem_init(1, 1, "", Math.floor(mem_init_len/2)+1, mem_init_len); 83 mem_init(2, 4, "shared", Math.floor(mem_init_len/2), mem_init_len); 84 mem_init(2, 4, "shared", Math.floor(mem_init_len/2)+1, mem_init_len); 85 86 // We exceed the bounds of the data segment but not the memory 87 mem_init(1, 1, "", mem_init_len*4, mem_init_len*2-2); 88 mem_init(1, 1, "", mem_init_len*4-1, mem_init_len*2-1); 89 mem_init(2, 4, "shared", mem_init_len*4, mem_init_len*2-2); 90 mem_init(2, 4, "shared", mem_init_len*4-1, mem_init_len*2-1); 91 92 // We arithmetically overflow the memory limit but not the segment limit 93 mem_init(1, "", "", Math.floor(mem_init_len/2), 0xFFFFFF00); 94 95 // We arithmetically overflow the segment limit but not the memory limit 96 mem_init(1, "", "", PAGESIZE, 0xFFFFFFFC); 97 98 // memory.copy: out of bounds of the memory for the source or target, and should 99 // not perform at all. Major cases: 100 // 101 // - non-overlapping regions 102 // - overlapping regions with src >= dest 103 // - overlapping regions with src == dest 104 // - overlapping regions with src < dest 105 // - arithmetic overflow on src addresses 106 // - arithmetic overflow on target addresses 107 // 108 // for each of those, 109 // 110 // - src address oob 111 // - target address oob 112 // - both oob 113 114 function mem_copy(min, max, shared, srcOffs, targetOffs, len) { 115 if (shared == "shared" && !sharedMemoryEnabled()) 116 return; 117 let ins = wasmEvalText( 118 `(module 119 (memory (export "mem") ${min} ${max} ${shared}) 120 (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) 121 (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))`); 122 123 let v = new Uint8Array(ins.exports.mem.buffer); 124 125 let copyDown = srcOffs < targetOffs; 126 let targetAvail = v.length - targetOffs; 127 let srcAvail = v.length - srcOffs; 128 let srcLim = srcOffs + Math.min(len, targetAvail, srcAvail); 129 130 for (let i=srcOffs, j=0; i < srcLim; i++, j++) 131 v[i] = j; 132 assertErrorMessage(() => ins.exports.run(targetOffs, srcOffs, len), 133 WebAssembly.RuntimeError, 134 /index out of bounds/); 135 136 for (var i=0, s=0; i < v.length; i++ ) { 137 if (i >= srcOffs && i < srcLim) { 138 assertEq(v[i], (s++) & 0xFF); 139 continue; 140 } 141 assertEq(v[i], 0); 142 } 143 } 144 145 // OOB target address, nonoverlapping 146 mem_copy(1, 1, "", 0, PAGESIZE-20, 40); 147 mem_copy(1, 1, "", 0, PAGESIZE-21, 39); 148 mem_copy(2, 4, "shared", 0, 2*PAGESIZE-20, 40); 149 mem_copy(2, 4, "shared", 0, 2*PAGESIZE-21, 39); 150 151 // OOB source address, nonoverlapping 152 mem_copy(1, 1, "", PAGESIZE-20, 0, 40); 153 mem_copy(1, 1, "", PAGESIZE-21, 0, 39); 154 mem_copy(2, 4, "shared", 2*PAGESIZE-20, 0, 40); 155 mem_copy(2, 4, "shared", 2*PAGESIZE-21, 0, 39); 156 157 // OOB target address, overlapping, src < target 158 mem_copy(1, 1, "", PAGESIZE-50, PAGESIZE-20, 40); 159 160 // OOB source address, overlapping, target < src 161 mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-50, 40); 162 163 // OOB both, overlapping, including target == src 164 mem_copy(1, 1, "", PAGESIZE-30, PAGESIZE-20, 40); 165 mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-30, 40); 166 mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-20, 40); 167 168 // Arithmetic overflow on source address. 169 mem_copy(1, "", "", PAGESIZE-20, 0, 0xFFFFF000); 170 171 // Arithmetic overflow on target adddress is an overlapping case. 172 mem_copy(1, 1, "", PAGESIZE-0x1000, PAGESIZE-20, 0xFFFFFF00);