tor-browser

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

bce.js (6155B)


      1 mem='\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'+
      2    '\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff'+
      3    '\x00'.repeat(65488) +
      4    '\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff'
      5 
      6 let accessWidth = {
      7  '8_s':  1,
      8  '8_u':  1,
      9  '16_s': 2,
     10  '16_u': 2,
     11  '':     4,
     12  'f32':  4,
     13  'f64':  8,
     14 }
     15 
     16 let baseOp = {
     17  '8_s':  'i32',
     18  '8_u':  'i32',
     19  '16_s': 'i32',
     20  '16_u': 'i32',
     21  '':     'i32',
     22  'f32':  'f32',
     23  'f64':  'f64',
     24 }
     25 
     26 function toSigned(width, num) {
     27  let unsignedMax = Math.pow(2, accessWidth[width] * 8) - 1;
     28  let signedMax = Math.pow(2, accessWidth[width] * 8 - 1) - 1;
     29 
     30  return (num <= signedMax ? num : -(unsignedMax + 1 - num));
     31 }
     32 
     33 function fromLittleEndianNum(width, bytes) {
     34  let base = 1;
     35  var res = 0;
     36  for (var i = 0; i < accessWidth[width]; i++) {
     37    res += base * bytes[i];
     38    base *= 256;
     39  }
     40  return res;
     41 }
     42 
     43 function getInt(width, offset, mem) {
     44  var bytes = [ ];
     45  for (var i = offset; i < offset + accessWidth[width]; i++) {
     46    if (i < mem.length)
     47      bytes.push(mem.charCodeAt(i));
     48    else
     49      bytes.push(0);
     50  }
     51 
     52  var res = fromLittleEndianNum(width, bytes);
     53  if (width == '8_s' || width == '16_s' || width == '')
     54    res = toSigned(width, res);
     55  return res;
     56 }
     57 
     58 function loadTwiceModule(type, ext, offset, align) {
     59    // TODO: Generate memory from byte string
     60    return wasmEvalText(
     61    `(module
     62       (memory 1)
     63       (data (i32.const 0) "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")
     64       (data (i32.const 16) "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")
     65       (data (i32.const 65520) "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")
     66       (func (param i32) (param i32) (result ${type})
     67         (drop (${type}.load${ext}
     68          offset=${offset}
     69          ${align != 0 ? 'align=' + align : ''}
     70          (local.get 0)
     71         ))
     72         (${type}.load${ext}
     73          offset=${offset}
     74          ${align != 0 ? 'align=' + align : ''}
     75          (local.get 1)
     76         )
     77       ) (export "" (func 0)))`
     78    ).exports[""];
     79 }
     80 
     81 function loadTwiceSameBasePlusConstModule(type, ext, offset, align, addConst) {
     82    return wasmEvalText(
     83    `(module
     84       (memory 1)
     85       (data (i32.const 0) "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")
     86       (data (i32.const 16) "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")
     87       (data (i32.const 65520) "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")
     88       (func (param i32) (result ${type})
     89         (drop (${type}.load${ext}
     90          offset=${offset}
     91          ${align != 0 ? 'align=' + align : ''}
     92          (local.get 0)
     93         ))
     94         (${type}.load${ext}
     95          offset=${offset}
     96          ${align != 0 ? 'align=' + align : ''}
     97          (i32.add (local.get 0) (i32.const ${addConst}))
     98         )
     99       ) (export "" (func 0)))`
    100    ).exports[""];
    101 }
    102 
    103 function loadTwiceSameBasePlusNonConstModule(type, ext, offset, align) {
    104    return wasmEvalText(
    105    `(module
    106       (memory 1)
    107       (data (i32.const 0) "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")
    108       (data (i32.const 16) "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")
    109       (data (i32.const 65520) "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")
    110       (func (param i32) (param i32) (result ${type})
    111         (drop (${type}.load${ext}
    112          offset=${offset}
    113          ${align != 0 ? 'align=' + align : ''}
    114          (local.get 0)
    115         ))
    116         (${type}.load${ext}
    117          offset=${offset}
    118          ${align != 0 ? 'align=' + align : ''}
    119          (i32.add (local.get 0) (local.get 1))
    120         )
    121       ) (export "" (func 0)))`
    122    ).exports[""];
    123 }
    124 
    125 /*
    126 * On x64 falsely removed bounds checks will be masked by the signal handlers.
    127 * Thus it is important that these tests be run on x86.
    128 */
    129 
    130 function testOOB(mod, args) {
    131    assertErrorMessage(() => mod(...args), WebAssembly.RuntimeError, /index out of bounds/);
    132 }
    133 
    134 function testOk(mod, args, expected, expectedType) {
    135    assertEq(mod(...args), expected);
    136 }
    137 
    138 // TODO: It would be nice to verify how many BCs are eliminated on positive tests.
    139 
    140 const align = 0;
    141 for (let offset of [0, 1, 2, 3, 4, 8, 16, 41, 0xfff8]) {
    142 
    143  var widths = ['8_s', '8_u', '16_s', '16_u', '']
    144 
    145  for (let width of widths) {
    146    // Accesses of 1 byte.
    147    let lastValidIndex = 0x10000 - offset - accessWidth[width];
    148    let op = baseOp[width];
    149 
    150    var mod = loadTwiceModule(op, width, offset, align);
    151 
    152    // Two consecutive loads from two different bases
    153    testOk(mod, [lastValidIndex, lastValidIndex], getInt(width, lastValidIndex + offset, mem), op);
    154    testOOB(mod, [lastValidIndex + 42, lastValidIndex + 42]);
    155    testOOB(mod, [lastValidIndex, lastValidIndex + 42]);
    156 
    157    mod = loadTwiceSameBasePlusConstModule(op, width, offset, align, 1);
    158 
    159    testOk(mod, [lastValidIndex-1], getInt(width, lastValidIndex + offset, mem), op);
    160    testOOB(mod, [lastValidIndex]);
    161 
    162    // Two consecutive loads from same base with different offsets
    163    mod = loadTwiceSameBasePlusConstModule(op, width, offset, align, 2);
    164 
    165    testOk(mod, [lastValidIndex-2], getInt(width, lastValidIndex + offset, mem), op);
    166    testOOB(mod, [lastValidIndex-1, 2]);
    167 
    168    mod = loadTwiceSameBasePlusConstModule(op, width, offset, align, lastValidIndex);
    169 
    170    testOk(mod, [0], getInt(width, lastValidIndex + offset, mem), op);
    171    testOOB(mod, [1]);
    172 
    173    mod = loadTwiceSameBasePlusNonConstModule(op, width, offset, align);
    174    testOk(mod, [0, 1], getInt(width, 1 + offset, mem), op);
    175    testOk(mod, [0, lastValidIndex], getInt(width, lastValidIndex + offset, mem), op);
    176    testOOB(mod, [1, lastValidIndex])
    177 
    178    // TODO: All of the above with mixed loads and stores
    179 
    180    // TODO: Branching - what do we want?
    181 
    182    // TODO: Just loops
    183    //         - loop invariant checks
    184    //         - loop dependant checks remaining inbounds
    185    //         - loop dependant checks going out-of bounds.
    186    //
    187    // TODO: Loops + branching
    188    //         - loop invariant checks guarded by a loop invariant branch?
    189  }
    190 }