tor-browser

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

memory.js (20734B)


      1 const RuntimeError = WebAssembly.RuntimeError;
      2 
      3 function loadModuleSrc(type, ext, offset, align, drop = false) {
      4    let maybeResult = drop ? '' : `(result ${type})`;
      5    let maybeDrop = drop ? 'drop' : '';
      6    return `(module
      7       (memory 1)
      8       (data (i32.const 0) "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")
      9       (data (i32.const 16) "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")
     10       (func $load (param i32) ${maybeResult}
     11         (${type}.load${ext}
     12          offset=${offset}
     13          ${align != 0 ? 'align=' + align : ''}
     14          (local.get 0)
     15         )
     16         ${maybeDrop}
     17       ) (export "" (func 0)))`;
     18 }
     19 function loadModule(type, ext, offset, align, drop = false) {
     20    return wasmEvalText(loadModuleSrc(type, ext, offset, align, drop)).exports[""];
     21 }
     22 
     23 function storeModuleSrc(type, ext, offset, align) {
     24    var load_ext = ext === '' ? '' : ext + '_s';
     25    return `(module
     26       (memory 1)
     27       (data (i32.const 0) "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")
     28       (data (i32.const 16) "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")
     29       (func $store (param i32) (param ${type})
     30         (${type}.store${ext}
     31          offset=${offset}
     32          ${align != 0 ? 'align=' + align : ''}
     33          (local.get 0)
     34          (local.get 1)
     35         )
     36       ) (export "store" (func 0))
     37       (func $load (param i32) (result ${type})
     38        (${type}.load${load_ext}
     39         offset=${offset}
     40         ${align != 0 ? 'align=' + align : ''}
     41         (local.get 0)
     42        )
     43       ) (export "load" (func 1)))`;
     44 }
     45 function storeModule(type, ext, offset, align) {
     46    return wasmEvalText(storeModuleSrc(type, ext, offset, align)).exports;
     47 }
     48 
     49 function storeModuleCstSrc(type, ext, offset, align, value) {
     50    var load_ext = ext === '' ? '' : ext + '_s';
     51    return `(module
     52       (memory 1)
     53       (data (i32.const 0) "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")
     54       (data (i32.const 16) "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")
     55       (func $store (param i32)
     56         (${type}.store${ext}
     57          offset=${offset}
     58          ${align != 0 ? 'align=' + align : ''}
     59          (local.get 0)
     60          (${type}.const ${value})
     61         )
     62       ) (export "store" (func 0))
     63       (func $load (param i32) (result ${type})
     64        (${type}.load${load_ext}
     65         offset=${offset}
     66         ${align != 0 ? 'align=' + align : ''}
     67         (local.get 0)
     68        )
     69       ) (export "load" (func 1)))`;
     70 }
     71 function storeModuleCst(type, ext, offset, align, value) {
     72    return wasmEvalText(storeModuleCstSrc(type, ext, offset, align, value)).exports;
     73 }
     74 
     75 function testLoad(type, ext, base, offset, align, expect) {
     76    if (type === 'i64') {
     77        wasmAssert(loadModuleSrc(type, ext, offset, align), [{
     78            type,
     79            func: '$load',
     80            expected: expect,
     81            args: [`i32.const ${base}`]
     82        }]);
     83    }
     84    else {
     85        assertEq(loadModule(type, ext, offset, align)(base), expect);
     86    }
     87 }
     88 
     89 function testLoadOOB(type, ext, base, offset, align) {
     90    assertErrorMessage(() => loadModule(type, ext, offset, align, /*drop*/ true)(base), RuntimeError, /index out of bounds/);
     91 }
     92 
     93 function testStore(type, ext, base, offset, align, value) {
     94    if (type === 'i64') {
     95        wasmAssert(storeModuleSrc(type, ext, offset, align), [
     96            {type, func: '$store', args: [`i32.const ${base}`, `i64.const ${value}`]},
     97            {type, func: '$load', args: [`i32.const ${base}`], expected: value},
     98        ]);
     99        wasmAssert(storeModuleCstSrc(type, ext, offset, align, value), [
    100            {type, func: '$store', args: [`i32.const ${base}`]},
    101            {type, func: '$load', args: [`i32.const ${base}`], expected: value},
    102        ]);
    103    } else {
    104        let module = storeModule(type, ext, offset, align);
    105        let moduleCst = storeModuleCst(type, ext, offset, align, value);
    106        module.store(base, value);
    107        assertEq(module.load(base), value);
    108        moduleCst.store(base);
    109        assertEq(moduleCst.load(base), value);
    110    }
    111 }
    112 
    113 function testStoreOOB(type, ext, base, offset, align, value) {
    114    if (type === 'i64') {
    115        assertErrorMessage(() => wasmAssert(
    116            storeModuleSrc(type, ext, offset, align),
    117            [{type, func: '$store', args: [`i32.const ${base}`, `i64.const ${value}`]}]
    118        ), RuntimeError, /index out of bounds/);
    119    } else {
    120        assertErrorMessage(() => storeModule(type, ext, offset, align).store(base, value), RuntimeError, /index out of bounds/);
    121    }
    122 }
    123 
    124 function badLoadModule(type, ext) {
    125    wasmFailValidateText( `(module (func (param i32) (${type}.load${ext} (local.get 0))) (export "" (func 0)))`, /memory index/);
    126 }
    127 
    128 function badStoreModule(type, ext) {
    129    wasmFailValidateText(`(module (func (param i32) (${type}.store${ext} (local.get 0) (${type}.const 0))) (export "" (func 0)))`, /memory index/);
    130 }
    131 
    132 // Can't touch memory.
    133 for (let [type, ext] of [
    134    ['i32', ''],
    135    ['i32', '8_s'],
    136    ['i32', '8_u'],
    137    ['i32', '16_s'],
    138    ['i32', '16_u'],
    139    ['i64', ''],
    140    ['i64', '8_s'],
    141    ['i64', '8_u'],
    142    ['i64', '16_s'],
    143    ['i64', '16_u'],
    144    ['i64', '32_s'],
    145    ['i64', '32_u'],
    146    ['f32', ''],
    147    ['f64', ''],
    148 ])
    149 {
    150    badLoadModule(type, ext);
    151 }
    152 
    153 for (let [type, ext] of [
    154    ['i32', ''],
    155    ['i32', '8'],
    156    ['i32', '16'],
    157    ['i64', ''],
    158    ['i64', '8'],
    159    ['i64', '16'],
    160    ['i64', '32'],
    161    ['f32', ''],
    162    ['f64', ''],
    163 ])
    164 {
    165    badStoreModule(type, ext);
    166 }
    167 
    168 assertEq(getJitCompilerOptions()['wasm.fold-offsets'], 1);
    169 
    170 for (var foldOffsets = 0; foldOffsets <= 1; foldOffsets++) {
    171    setJitCompilerOption('wasm.fold-offsets', foldOffsets | 0);
    172 
    173    testLoad('i32', '', 0, 0, 0, 0x03020100);
    174    testLoad('i32', '', 1, 0, 1, 0x04030201);
    175    testLoad('i32', '', 0, 4, 0, 0x07060504);
    176    testLoad('i32', '', 1, 3, 4, 0x07060504);
    177    testLoad('f32', '', 0, 0, 0, 3.820471434542632e-37);
    178    testLoad('f32', '', 1, 0, 1, 1.539989614439558e-36);
    179    testLoad('f32', '', 0, 4, 0, 1.0082513512365273e-34);
    180    testLoad('f32', '', 1, 3, 4, 1.0082513512365273e-34);
    181    testLoad('f64', '', 0, 0, 0, 7.949928895127363e-275);
    182    testLoad('f64', '', 1, 0, 1, 5.447603722011605e-270);
    183    testLoad('f64', '', 0, 8, 0, 3.6919162048650923e-236);
    184    testLoad('f64', '', 1, 7, 8, 3.6919162048650923e-236);
    185 
    186    testLoad('i32', '8_s', 16, 0, 0, -0x10);
    187    testLoad('i32', '8_u', 16, 0, 0, 0xf0);
    188    testLoad('i32', '16_s', 16, 0, 0, -0xe10);
    189    testLoad('i32', '16_u', 16, 0, 0, 0xf1f0);
    190 
    191    testStore('i32', '', 0, 0, 0, -0x3f3e2c2c);
    192    testStore('i32', '', 1, 0, 1, -0x3f3e2c2c);
    193    testStore('i32', '', 0, 1, 1, -0x3f3e2c2c);
    194    testStore('i32', '', 1, 1, 4, -0x3f3e2c2c);
    195 
    196    testStore('f32', '', 0, 0, 0, 0.01234566979110241);
    197    testStore('f32', '', 1, 0, 1, 0.01234566979110241);
    198    testStore('f32', '', 0, 4, 0, 0.01234566979110241);
    199    testStore('f32', '', 1, 3, 4, 0.01234566979110241);
    200    testStore('f64', '', 0, 0, 0, 0.89012345);
    201    testStore('f64', '', 1, 0, 1, 0.89012345);
    202    testStore('f64', '', 0, 8, 0, 0.89012345);
    203    testStore('f64', '', 1, 7, 8, 0.89012345);
    204 
    205    testStore('i32', '8', 0, 0, 0, 0x23);
    206    testStore('i32', '16', 0, 0, 0, 0x2345);
    207 
    208    wasmFailValidateText('(module (memory 2 1))', /maximum length 1 is less than initial length 2/);
    209 
    210    // Test bounds checks and edge cases.
    211 
    212    for (let align of [0,1,2,4]) {
    213 
    214        for (let offset of [0, 1, 2, 3, 4, 8, 16, 41, 0xfff8]) {
    215            // Accesses of 1 byte.
    216            let lastValidIndex = 0x10000 - 1 - offset;
    217 
    218            if (align < 2) {
    219                testLoad('i32', '8_s', lastValidIndex, offset, align, 0);
    220                testLoadOOB('i32', '8_s', lastValidIndex + 1, offset, align);
    221 
    222                testLoad('i32', '8_u', lastValidIndex, offset, align, 0);
    223                testLoadOOB('i32', '8_u', lastValidIndex + 1, offset, align);
    224 
    225                testStore('i32', '8', lastValidIndex, offset, align, -42);
    226                testStoreOOB('i32', '8', lastValidIndex + 1, offset, align, -42);
    227            }
    228 
    229            // Accesses of 2 bytes.
    230            lastValidIndex = 0x10000 - 2 - offset;
    231 
    232            if (align < 4) {
    233                testLoad('i32', '16_s', lastValidIndex, offset, align, 0);
    234                testLoadOOB('i32', '16_s', lastValidIndex + 1, offset, align);
    235 
    236                testLoad('i32', '16_u', lastValidIndex, offset, align, 0);
    237                testLoadOOB('i32', '16_u', lastValidIndex + 1, offset, align);
    238 
    239                testStore('i32', '16', lastValidIndex, offset, align, -32768);
    240                testStoreOOB('i32', '16', lastValidIndex + 1, offset, align, -32768);
    241            }
    242 
    243            // Accesses of 4 bytes.
    244            lastValidIndex = 0x10000 - 4 - offset;
    245 
    246            testLoad('i32', '', lastValidIndex, offset, align, 0);
    247            testLoadOOB('i32', '', lastValidIndex + 1, offset, align);
    248 
    249            testLoad('f32', '', lastValidIndex, offset, align, 0);
    250            testLoadOOB('f32', '', lastValidIndex + 1, offset, align);
    251 
    252            testStore('i32', '', lastValidIndex, offset, align, 1337);
    253            testStoreOOB('i32', '', lastValidIndex + 1, offset, align, 1337);
    254 
    255            testStore('f32', '', lastValidIndex, offset, align, Math.fround(13.37));
    256            testStoreOOB('f32', '', lastValidIndex + 1, offset, align, Math.fround(13.37));
    257 
    258            // Accesses of 8 bytes.
    259            lastValidIndex = 0x10000 - 8 - offset;
    260 
    261            testLoad('f64', '', lastValidIndex, offset, align, 0);
    262            testLoadOOB('f64', '', lastValidIndex + 1, offset, align);
    263 
    264            testStore('f64', '', lastValidIndex, offset, align, 1.23456789);
    265            testStoreOOB('f64', '', lastValidIndex + 1, offset, align, 1.23456789);
    266        }
    267 
    268        // Ensure wrapping doesn't apply.
    269        offset = 0x7fffffff;
    270        for (let index of [0, 1, 2, 3, 0x7fffffff, 0x80000000, 0x80000001]) {
    271            if (align < 2) {
    272                testLoadOOB('i32', '8_s', index, offset, align);
    273            }
    274            if (align < 4) {
    275                testLoadOOB('i32', '16_s', index, offset, align);
    276            }
    277            testLoadOOB('i32', '', index, offset, align);
    278            testLoadOOB('f32', '', index, offset, align);
    279            testLoadOOB('f64', '', index, offset, align);
    280        }
    281 
    282        // Ensure out of bounds when the offset is greater than the immediate range.
    283        index = 0;
    284        for (let offset of [0x80000000, 0xfffffffe, 0xffffffff]) {
    285            testLoadOOB('i32', '8_s', index, offset, 1);
    286            testLoadOOB('i32', '16_s', index, offset, 1);
    287            testLoadOOB('i32', '16_s', index, offset, 2);
    288            testLoadOOB('i32', '', index, offset, 1);
    289            testLoadOOB('i32', '', index, offset, 4);
    290            testLoadOOB('f32', '', index, offset, 1);
    291            testLoadOOB('f32', '', index, offset, 4);
    292            testLoadOOB('f64', '', index, offset, 1);
    293            testLoadOOB('f64', '', index, offset, 8);
    294        }
    295 
    296        wasmFailValidateText('(module (memory 1) (func (f64.store offset=0 (i32.const 0) (i32.const 0))))', mismatchError("i32", "f64"));
    297        wasmFailValidateText('(module (memory 1) (func (f64.store offset=0 (i32.const 0) (f32.const 0))))', mismatchError("f32", "f64"));
    298 
    299        wasmFailValidateText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (i32.const 0))))', mismatchError("i32", "f32"));
    300        wasmFailValidateText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (f64.const 0))))', mismatchError("f64", "f32"));
    301 
    302        wasmFailValidateText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f32.const 0))))', mismatchError("f32", "i32"));
    303        wasmFailValidateText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f64.const 0))))', mismatchError("f64", "i32"));
    304 
    305        // Test high number of registers.
    306        function testRegisters() {
    307            assertEq(wasmEvalText(
    308                `(module
    309              (memory 1)
    310              (data (i32.const 0) "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")
    311              (data (i32.const 16) "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")
    312              (func (param i32) (result i32) (local i32 i32 i32 i32 f32 f64)
    313               (local.set 1 (i32.load8_s offset=4 (local.get 0)))
    314               (local.set 2 (i32.load16_s (local.get 1)))
    315               (i32.store8 offset=4 (local.get 0) (local.get 1))
    316               (local.set 3 (i32.load16_u (local.get 2)))
    317               (i32.store16 (local.get 1) (local.get 2))
    318               (local.set 4 (i32.load (local.get 2)))
    319               (i32.store (local.get 1) (local.get 2))
    320               (local.set 5 (f32.load (local.get 4)))
    321               (f32.store (local.get 4) (local.get 5))
    322               (local.set 6 (f64.load (local.get 4)))
    323               (f64.store (local.get 4) (local.get 6))
    324               (i32.add
    325                (i32.add
    326                 (local.get 0)
    327                 (local.get 1)
    328                )
    329                (i32.add
    330                 (i32.add
    331                  (local.get 2)
    332                  (local.get 3)
    333                 )
    334                 (i32.add
    335                  (local.get 4)
    336                  (i32.reinterpret_f32 (local.get 5))
    337                 )
    338                )
    339               )
    340              ) (export "" (func 0)))`
    341            ).exports[""](1), 50464523);
    342        }
    343 
    344        testRegisters();
    345 
    346        testLoad('i64', '', 0, 0, 0, '0x0706050403020100');
    347        testLoad('i64', '', 1, 0, 0, '0x0807060504030201');
    348        testLoad('i64', '', 0, 1, 0, '0x0807060504030201');
    349        testLoad('i64', '', 1, 1, 4, '0x0908070605040302');
    350 
    351        testLoad('i64', '8_s', 16, 0, 0, -0x10);
    352        testLoad('i64', '8_u', 16, 0, 0, 0xf0);
    353        testLoad('i64', '16_s', 16, 0, 0, -0xe10);
    354        testLoad('i64', '16_u', 16, 0, 0, 0xf1f0);
    355        testLoad('i64', '32_s', 16, 0, 0, 0xf3f2f1f0 | 0);
    356        testLoad('i64', '32_u', 16, 0, 0, '0xf3f2f1f0');
    357 
    358        testStore('i64', '', 0, 0, 0, '0xc0c1d3d4e6e7090a');
    359        testStore('i64', '', 1, 0, 0, '0xc0c1d3d4e6e7090a');
    360        testStore('i64', '', 0, 1, 0, '0xc0c1d3d4e6e7090a');
    361        testStore('i64', '', 1, 1, 4, '0xc0c1d3d4e6e7090a');
    362        testStore('i64', '8', 0, 0, 0, 0x23);
    363        testStore('i64', '16', 0, 0, 0, 0x23);
    364        testStore('i64', '32', 0, 0, 0, 0x23);
    365 
    366        for (let offset of [0, 1, 2, 3, 4, 8, 16, 41, 0xfff8]) {
    367            // Accesses of 1 byte.
    368            let lastValidIndex = 0x10000 - 1 - offset;
    369 
    370            if (align < 2) {
    371                testLoad('i64', '8_s', lastValidIndex, offset, align, 0);
    372                testLoadOOB('i64', '8_s', lastValidIndex + 1, offset, align);
    373 
    374                testLoad('i64', '8_u', lastValidIndex, offset, align, 0);
    375                testLoadOOB('i64', '8_u', lastValidIndex + 1, offset, align);
    376 
    377                testStore('i64', '8', lastValidIndex, offset, align, -42);
    378                testStoreOOB('i64', '8', lastValidIndex + 1, offset, align, -42);
    379            }
    380 
    381            // Accesses of 2 bytes.
    382            lastValidIndex = 0x10000 - 2 - offset;
    383 
    384            if (align < 4) {
    385                testLoad('i64', '16_s', lastValidIndex, offset, align, 0);
    386                testLoadOOB('i64', '16_s', lastValidIndex + 1, offset, align);
    387 
    388                testLoad('i64', '16_u', lastValidIndex, offset, align, 0);
    389                testLoadOOB('i64', '16_u', lastValidIndex + 1, offset, align);
    390 
    391                testStore('i64', '16', lastValidIndex, offset, align, -32768);
    392                testStoreOOB('i64', '16', lastValidIndex + 1, offset, align, -32768);
    393            }
    394 
    395            // Accesses of 4 bytes.
    396            lastValidIndex = 0x10000 - 4 - offset;
    397 
    398            testLoad('i64', '32_s', lastValidIndex, offset, align, 0);
    399            testLoadOOB('i64', '32_s', lastValidIndex + 1, offset, align);
    400 
    401            testLoad('i64', '32_u', lastValidIndex, offset, align, 0);
    402            testLoadOOB('i64', '32_u', lastValidIndex + 1, offset, align);
    403 
    404            testStore('i64', '32', lastValidIndex, offset, align, 0xf1231337 | 0);
    405            testStoreOOB('i64', '32', lastValidIndex + 1, offset, align, 0xf1231337 | 0);
    406 
    407            // Accesses of 8 bytes.
    408            lastValidIndex = 0x10000 - 8 - offset;
    409 
    410            testLoad('i64', '', lastValidIndex, offset, align, 0);
    411            testLoadOOB('i64', '', lastValidIndex + 1, offset, align);
    412 
    413            testStore('i64', '', lastValidIndex, offset, align, '0x1234567887654321');
    414            testStoreOOB('i64', '', lastValidIndex + 1, offset, align, '0x1234567887654321');
    415        }
    416    }
    417 }
    418 
    419 setJitCompilerOption('wasm.fold-offsets', 1);
    420 
    421 // Test active segments with a memory index.
    422 
    423 {
    424    function makeIt(flag, memindex) {
    425        return new Uint8Array([0x00, 0x61, 0x73, 0x6d,
    426                               0x01, 0x00, 0x00, 0x00,
    427                               0x05,                   // Memory section
    428                               0x03,                   // Section size
    429                               0x01,                   // One memory
    430                               0x00,                   // Unshared, min only
    431                               0x01,                   // Min
    432                               0x0b,                   // Data section
    433                               0x0a,                   // Section size
    434                               0x01,                   // One data segment
    435                               flag,                   // Flag should be 2, or > 2 if invalid
    436                               memindex,               // Memory index should be 0, or > 0 if invalid
    437                               0x41,                   // Init expr: i32.const
    438                               0x00,                   // Init expr: zero (payload)
    439                               0x0b,                   // Init expr: end
    440                               0x03,                   // Three bytes, because why not?
    441                               0x01,
    442                               0x02,
    443                               0x03]);
    444    }
    445 
    446    // Should succeed because this is what an active segment with index looks like
    447    new WebAssembly.Module(makeIt(0x02, 0x00));
    448 
    449    // Should fail because the kind is unknown
    450    assertErrorMessage(() => new WebAssembly.Module(makeIt(0x03, 0x00)),
    451                       WebAssembly.CompileError,
    452                       /invalid data initializer-kind/);
    453 
    454    // Should fail because the memory index is bad
    455    assertErrorMessage(() => new WebAssembly.Module(makeIt(0x02, 0x01)),
    456                       WebAssembly.CompileError,
    457                       /invalid memory index/);
    458 }
    459 
    460 // Misc syntax for data.
    461 
    462 // When memory index is present it must be zero, and the offset must be present too;
    463 // but it's OK for there to be neither
    464 new WebAssembly.Module(wasmTextToBinary(`(module (memory 1) (data 0 (i32.const 0) ""))`));
    465 new WebAssembly.Module(wasmTextToBinary(`(module (memory 1) (data 0 (offset (i32.const 0)) ""))`));
    466 new WebAssembly.Module(wasmTextToBinary(`(module (memory 1) (data ""))`));
    467 assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`(module (memory 1) (data 0 ""))`)),
    468                   SyntaxError,
    469                   /wasm text error/);
    470 assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`(module (memory 1) (data 1 (i32.const 0) ""))`)),
    471                   WebAssembly.CompileError,
    472                   /invalid memory index/);
    473 
    474 
    475 // Make sure we handle memory instructions without memory
    476 
    477 var nomem = /memory index out of range/;
    478 
    479 assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`(module (func (result i32) memory.size))`)),
    480                   WebAssembly.CompileError,
    481                   nomem);
    482 
    483 assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`(module (func (result i32) (memory.grow (i32.const 1))))`)),
    484                   WebAssembly.CompileError,
    485                   nomem);
    486 
    487 assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`
    488 (module (func (param i32 i32 i32)
    489  (memory.copy (local.get 0) (local.get 1) (local.get 2))))`)),
    490                   WebAssembly.CompileError,
    491                   nomem);
    492 
    493 assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`
    494 (module (func (param i32 i32 i32)
    495  (memory.fill (local.get 0) (local.get 1) (local.get 2))))`)),
    496                   WebAssembly.CompileError,
    497                   nomem);
    498 
    499 assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`
    500 (module
    501  (data $d "01234")
    502  (func (param i32 i32)
    503    (memory.init $d (local.get 0) (local.get 1))))`)),
    504                   WebAssembly.CompileError,
    505                   nomem);