large-memory.js (11506B)
1 // |jit-test| skip-if: !largeArrayBufferSupported(); allow-oom 2 3 var pagesz = PageSizeInBytes; 4 var pages_limit = MaxPagesIn32BitMemory; 5 6 // 40000 is well above 2GB but not anything that might run into boundary 7 // conditions near 4GB. 8 var pages_vanilla = 40000; 9 10 for ( let [pages,maxpages] of [[pages_vanilla, pages_vanilla+100], 11 [pages_limit - 3, pages_limit], 12 [pages_limit, pages_limit]] ) { 13 assertEq(pages == maxpages || maxpages - pages >= 3, true) 14 let ins = wasmEvalText(` 15 (module 16 (memory (export "mem") ${pages} ${maxpages}) 17 18 (data (i32.const ${(pages-5)*pagesz}) "yabbadabbado") 19 (data $flintstone "yabbadabbado") 20 21 (func (export "get_constaddr") (result i32) 22 (i32.load (i32.const ${pages*pagesz-4}))) 23 24 (func (export "get_varaddr") (param $p i32) (result i32) 25 (i32.load (local.get $p))) 26 27 (func (export "set_constaddr") (param $v i32) 28 (i32.store (i32.const ${pages*pagesz-8}) (local.get $v))) 29 30 (func (export "set_varaddr") (param $p i32) (param $v i32) 31 (i32.store (local.get $p) (local.get $v))) 32 33 (func (export "get_constaddr_large_offset") (result i32) 34 (i32.load offset=${(pages-100)*pagesz-4} (i32.const ${pagesz*100}))) 35 36 (func (export "get_varaddr_large_offset") (param $p i32) (result i32) 37 (i32.load offset=${(pages-100)*pagesz-4} (local.get $p))) 38 39 (func (export "get_constaddr_small_offset") (result i32) 40 (i32.load offset=${pagesz-4} (i32.const ${(pages-1)*pagesz}))) 41 42 (func (export "get_varaddr_small_offset") (param $p i32) (result i32) 43 (i32.load offset=${pagesz-4} (local.get $p))) 44 45 (func (export "set_constaddr_large_offset") (param $v i32) 46 (i32.store offset=${(pages-100)*pagesz-16} (i32.const ${pagesz*100}) (local.get $v))) 47 48 (func (export "set_varaddr_large_offset") (param $p i32) (param $v i32) 49 (i32.store offset=${(pages-100)*pagesz-20} (local.get $p) (local.get $v))) 50 51 (func (export "set_constaddr_small_offset") (param $v i32) 52 (i32.store offset=${pagesz-24} (i32.const ${(pages-1)*pagesz}) (local.get $v))) 53 54 (func (export "set_varaddr_small_offset") (param $p i32) (param $v i32) 55 (i32.store offset=${pagesz-28} (local.get $p) (local.get $v))) 56 57 (func (export "copy") (param $dest i32) (param $src i32) 58 (memory.copy (local.get $dest) (local.get $src) (i32.const 12))) 59 60 (func (export "init") (param $dest i32) 61 (memory.init $flintstone (local.get $dest) (i32.const 0) (i32.const 12))) 62 63 (func (export "fill") (param $dest i32) (param $val i32) (param $len i32) 64 (memory.fill (local.get 0) (local.get 1) (local.get 2))) 65 66 (func (export "grow1") (result i32) 67 (memory.grow (i32.const 1))) 68 )`); 69 70 let buf = new Int32Array(ins.exports.mem.buffer); 71 72 let checkFlintstoneAt = function (addr) { 73 assertEq(buf[addr/4], 0x62626179) // "yabb", little-endian 74 assertEq(buf[addr/4+1], 0x62616461) // "adab", ditto 75 assertEq(buf[addr/4+2], 0x6f646162) // "bado" 76 } 77 78 buf[pages*pagesz/4-1] = 0xdeadbeef; 79 assertEq(ins.exports.get_constaddr(), 0xdeadbeef|0); 80 assertEq(ins.exports.get_varaddr(pages*pagesz-4), 0xdeadbeef|0); 81 82 assertEq(ins.exports.get_constaddr_large_offset(), 0xdeadbeef|0); 83 assertEq(ins.exports.get_varaddr_large_offset(pagesz*100), 0xdeadbeef|0); 84 85 assertEq(ins.exports.get_constaddr_small_offset(), 0xdeadbeef|0); 86 assertEq(ins.exports.get_varaddr_small_offset((pages-1)*pagesz), 0xdeadbeef|0); 87 88 ins.exports.set_constaddr(0xcafebab0); 89 assertEq(buf[pages*pagesz/4-2], 0xcafebab0|0); 90 91 ins.exports.set_varaddr(pages*pagesz-12, 0xcafebab1); 92 assertEq(buf[pages*pagesz/4-3], 0xcafebab1|0); 93 94 ins.exports.set_constaddr_large_offset(0xcafebab2); 95 assertEq(buf[pages*pagesz/4-4], 0xcafebab2|0); 96 97 ins.exports.set_varaddr_large_offset(pagesz*100, 0xcafebab3); 98 assertEq(buf[pages*pagesz/4-5], 0xcafebab3|0); 99 100 ins.exports.set_constaddr_small_offset(0xcafebab4); 101 assertEq(buf[pages*pagesz/4-6], 0xcafebab4|0); 102 103 ins.exports.set_varaddr_small_offset((pages-1)*pagesz, 0xcafebab5); 104 assertEq(buf[pages*pagesz/4-7], 0xcafebab5|0); 105 106 if (pages*pagesz < 0x1_0000_0000) { 107 assertErrorMessage(() => ins.exports.get_varaddr(pages*pagesz), 108 WebAssembly.RuntimeError, 109 /index out of bounds/); 110 } 111 112 assertErrorMessage(() => ins.exports.get_varaddr_large_offset(pagesz*100+4), 113 WebAssembly.RuntimeError, 114 /index out of bounds/); 115 116 assertErrorMessage(() => ins.exports.get_varaddr_small_offset((pages-1)*pagesz+4), 117 WebAssembly.RuntimeError, 118 /index out of bounds/); 119 120 ins.exports.set_varaddr(pages*pagesz-4, 0); // Should work 121 if (pages*pagesz < 0x1_0000_0000) { 122 assertErrorMessage(() => ins.exports.set_varaddr(pages*pagesz, 0), 123 WebAssembly.RuntimeError, 124 /index out of bounds/); 125 } 126 127 ins.exports.set_varaddr_large_offset(pagesz*100+16, 0); // Should work 128 assertErrorMessage(() => ins.exports.set_varaddr_large_offset(pagesz*100+20, 0), 129 WebAssembly.RuntimeError, 130 /index out of bounds/); 131 132 ins.exports.set_varaddr_small_offset((pages-1)*pagesz+24); // Should work 133 assertErrorMessage(() => ins.exports.set_varaddr_small_offset((pages-1)*pagesz+28, 0), 134 WebAssembly.RuntimeError, 135 /index out of bounds/); 136 137 // Active init 138 checkFlintstoneAt((pages-5)*pagesz); 139 140 // memory.init 141 ins.exports.init((pages-6)*pagesz); 142 checkFlintstoneAt((pages-6)*pagesz); 143 144 ins.exports.init(pages*pagesz-12); // Should work 145 // Dest goes OOB 146 assertErrorMessage(() => ins.exports.init(pages*pagesz-6), 147 WebAssembly.RuntimeError, 148 /index out of bounds/); 149 150 // memory.copy 151 152 // Dest and src are in bounds 153 ins.exports.copy((pages-10)*pagesz, (pages-5)*pagesz); 154 checkFlintstoneAt((pages-10)*pagesz); 155 156 // Dest goes OOB 157 assertErrorMessage(() => ins.exports.copy((pages)*pagesz-6, (pages-5)*pagesz, 12), 158 WebAssembly.RuntimeError, 159 /index out of bounds/); 160 161 ins.exports.copy((pages)*pagesz-12, (pages-1)*pagesz); // Should work 162 // Src goes OOB 163 assertErrorMessage(() => ins.exports.copy((pages)*pagesz-12, (pages)*pagesz-6), 164 WebAssembly.RuntimeError, 165 /index out of bounds/); 166 167 168 // memory.fill 169 let lastpg = (pages-1)*pagesz; 170 ins.exports.fill(lastpg, 0x37, pagesz); 171 for ( let i=0; i < pagesz/4; i++ ) 172 assertEq(buf[lastpg/4+i], 0x37373737); 173 174 assertErrorMessage(() => ins.exports.fill(lastpg, 0x42, pagesz+1), 175 WebAssembly.RuntimeError, 176 /index out of bounds/); 177 178 done: 179 if (pages < maxpages) { 180 let res = 0; 181 182 res = ins.exports.grow1(); 183 if (res == -1) break done; 184 assertEq(res, pages); 185 186 res = ins.exports.grow1(); 187 if (res == -1) break done; 188 assertEq(res, pages+1); 189 190 res = ins.exports.grow1(); 191 if (res == -1) break done; 192 assertEq(res, pages+2); 193 194 assertEq(ins.exports.get_varaddr((pages+2)*pagesz), 0); 195 196 let i = 0; 197 while (ins.exports.grow1() != -1) { 198 i++; 199 } 200 // We can't assert equality because we might OOM before we get to the 201 // max, but we can assert we did not go beyond that. 202 assertEq(i <= maxpages-pages-3, true); 203 } 204 } 205 206 // Very large offsets should be allowed (but may of course be OOB). Observe 207 // that offset=0xffffffff is accepted by the validator even though this access 208 // could never succeed. 209 { 210 let ins = wasmEvalText(` 211 (module 212 (memory (export "mem") 1) 213 (func (export "get1") (param $p i32) (result i32) 214 (i32.load offset=0x80000000 (local.get $p))) 215 (func (export "get2") (param $p i32) (result i32) 216 (i32.load offset=0xfffffffc (local.get $p))) 217 (func (export "get3") (param $p i32) (result i32) 218 (i32.load offset=0xffffffff (local.get $p)))) 219 `); 220 assertErrorMessage(() => ins.exports.get1(0), 221 WebAssembly.RuntimeError, 222 /index out of bounds/); 223 assertErrorMessage(() => ins.exports.get2(0), 224 WebAssembly.RuntimeError, 225 /index out of bounds/); 226 assertErrorMessage(() => ins.exports.get3(0), 227 WebAssembly.RuntimeError, 228 /index out of bounds/); 229 } 230 231 { 232 let ins = wasmEvalText(` 233 (module 234 (memory (export "mem") 32768) 235 (func (export "get1") (param $p i32) (result i32) 236 (i32.load8_s offset=0x7fffffff (local.get $p)))) 237 `); 238 assertEq(ins.exports.get1(0), 0); 239 assertErrorMessage(() => ins.exports.get1(1), 240 WebAssembly.RuntimeError, 241 /index out of bounds/); 242 assertErrorMessage(() => ins.exports.get1(-1), 243 WebAssembly.RuntimeError, 244 /index out of bounds/); 245 } 246 247 { 248 let ins = wasmEvalText(` 249 (module 250 (memory (export "mem") 32769) 251 (func (export "get1") (param $p i32) (result i32) 252 (i32.load8_s offset=0x80000000 (local.get $p)))) 253 `); 254 assertEq(ins.exports.get1(0), 0); 255 assertEq(ins.exports.get1(65535), 0); 256 assertErrorMessage(() => ins.exports.get1(65536), 257 WebAssembly.RuntimeError, 258 /index out of bounds/); 259 } 260 261 { 262 let ins = wasmEvalText(` 263 (module 264 (memory (export "mem") ${pages_limit}) 265 (func (export "get1") (param $p i32) (result i32) 266 (i32.load8_s offset=${pages_limit*pagesz-1} (local.get $p)))) 267 `); 268 assertEq(ins.exports.get1(0), 0); 269 assertErrorMessage(() => ins.exports.get1(1), 270 WebAssembly.RuntimeError, 271 /index out of bounds/); 272 assertErrorMessage(() => ins.exports.get1(-1), 273 WebAssembly.RuntimeError, 274 /index out of bounds/); 275 } 276 277 // Fail to grow at the declared max 278 // Import and export 279 280 { 281 let ins = wasmEvalText(` 282 (module 283 (memory (export "mem") ${pages_limit} ${pages_limit}) 284 285 (func (export "set_it") (param $addr i32) (param $val i32) 286 (i32.store (local.get $addr) (local.get $val))) 287 288 (func (export "grow1") (result i32) 289 (memory.grow (i32.const 1))) 290 )`); 291 292 assertEq(ins.exports.grow1(), -1); // Because initial == max 293 294 let ins2 = wasmEvalText(` 295 (module 296 (import "" "mem" (memory 1)) 297 298 (func (export "get_it") (param $addr i32) (result i32) 299 (i32.load (local.get $addr))) 300 )`, 301 {"":ins.exports}) 302 303 ins.exports.set_it((pages_limit*pagesz)-4, 0xbaadf00d); 304 assertEq(ins2.exports.get_it((pages_limit*pagesz)-4), 0xbaadf00d|0) 305 } 306 307 // Fail to grow at the max heap size even if there is headroom 308 // in the declared max 309 if (pages_limit < 65536) { 310 let ins = wasmEvalText(` 311 (module 312 (memory (export "mem") ${pages_limit} ${pages_limit+2}) 313 314 (func (export "grow1") (result i32) 315 (memory.grow (i32.const 1))) 316 )`); 317 318 assertEq(ins.exports.grow1(), -1); // Because current is at the max heap size 319 } 320 321 // Fail to instantiate when the minimum is larger than the max heap size 322 if (pages_limit < 65536) { 323 assertErrorMessage(() => wasmEvalText(` 324 (module (memory (export "mem") ${pages_limit+1} ${pages_limit+1})) 325 `), 326 WebAssembly.RuntimeError, 327 /too many memory pages/); 328 }