tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }