tor-browser

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

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 }