tor-browser

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

throw-to-js.js (7061B)


      1 // Tests for throwing exceptions to JS from Wasm.
      2 
      3 function assertWasmThrowsExn(thunk) {
      4  let thrown = false;
      5 
      6  try {
      7    thunk();
      8  } catch (exn) {
      9    thrown = true;
     10    assertEq(exn instanceof WebAssembly.Exception, true);
     11  }
     12 
     13  assertEq(thrown, true, "missing exception");
     14 }
     15 
     16 // Test that handler-less trys don't catch anything.
     17 assertWasmThrowsExn(() =>
     18  wasmEvalText(
     19    `(module
     20       (type (func (param)))
     21       (tag $exn (type 0))
     22       (func (export "f")
     23         try (throw $exn) end))`
     24  ).exports.f()
     25 );
     26 
     27 assertWasmThrowsExn(() =>
     28  wasmEvalText(
     29    `(module
     30       (type (func (param)))
     31       (tag $exn (type 0))
     32       (func $g (throw $exn))
     33       (func (export "f")
     34         try (call $g) end)
     35 )`
     36  ).exports.f()
     37 );
     38 
     39 assertWasmThrowsExn(() =>
     40  wasmEvalText(
     41    `(module
     42       (type (func (param)))
     43       (tag $exn (type 0))
     44       (func (export "f")
     45         try try (throw $exn) end end))`
     46  ).exports.f()
     47 );
     48 
     49 assertWasmThrowsExn(() =>
     50  wasmEvalText(
     51    `(module
     52       (tag $exn (param))
     53       (func (export "f")
     54         try
     55           try
     56             throw $exn
     57           delegate 0
     58         end))`
     59  ).exports.f()
     60 );
     61 
     62 assertWasmThrowsExn(() =>
     63  wasmEvalText(
     64    `(module
     65       (tag $exn (param))
     66       (func (export "f")
     67         try
     68           try
     69             throw $exn
     70           delegate 1
     71         end))`
     72  ).exports.f()
     73 );
     74 
     75 assertWasmThrowsExn(() =>
     76  wasmEvalText(
     77    `(module
     78       (tag $exn (param))
     79       (func (export "f")
     80         block
     81           try
     82             throw $exn
     83           delegate 0
     84         end))`
     85  ).exports.f()
     86 );
     87 
     88 assertWasmThrowsExn(() =>
     89  wasmEvalText(
     90    `(module
     91       (tag $exn (param))
     92       (func (export "f")
     93         loop
     94           try
     95             throw $exn
     96           delegate 0
     97         end))`
     98  ).exports.f()
     99 );
    100 
    101 assertWasmThrowsExn(() =>
    102  wasmEvalText(
    103    `(module
    104       (tag $exn (param))
    105       (func (export "f")
    106         (i32.const 1)
    107         if
    108           try
    109             throw $exn
    110           delegate 0
    111         end))`
    112  ).exports.f()
    113 );
    114 
    115 // Test throwing simple empty exceptions to JS.
    116 assertWasmThrowsExn(() =>
    117  wasmEvalText(
    118    `(module
    119       (type (func (param)))
    120       (tag $exn (type 0))
    121       (func (export "f")
    122         (throw $exn)))`
    123  ).exports.f()
    124 );
    125 
    126 // Test that wasm preserves the values of non-object exceptions that pass
    127 // through it back to JS.
    128 assertThrowsValue(
    129  () =>
    130    wasmEvalText(
    131      `(module
    132         (tag $exn)
    133         (import "m" "import" (func $import))
    134         (func (export "f")
    135           try
    136             (call $import)
    137           catch $exn
    138             ;; this block shouldn't be reached
    139           end))`,
    140      {
    141        m: {
    142          import: () => {
    143            throw 42;
    144          },
    145        },
    146      }
    147    ).exports.f(),
    148  42
    149 );
    150 
    151 // Like previous test, but using a rethrow instruction instead.
    152 assertThrowsValue(
    153  () =>
    154    wasmEvalText(
    155      `(module
    156         (import "m" "import" (func $import))
    157         (func (export "f")
    158           try
    159             (call $import)
    160           catch_all
    161             (rethrow 0)
    162           end))`,
    163      {
    164        m: {
    165          import: () => {
    166            throw 42;
    167          },
    168        },
    169      }
    170    ).exports.f(),
    171  42
    172 );
    173 
    174 // Test for throwing to JS and then back to Wasm.
    175 {
    176  var wasmThrower;
    177  let exports = wasmEvalText(
    178    `(module
    179       (type (func (param i32)))
    180       (tag $exn (type 0))
    181       (import "m" "import" (func $import (result i32)))
    182       (func (export "thrower")
    183         (i32.const 42)
    184         (throw $exn))
    185       (func (export "catcher") (result i32)
    186         try (result i32)
    187           (call $import)
    188         catch $exn
    189         end))`,
    190    {
    191      m: {
    192        import: () => {
    193          return wasmThrower();
    194        },
    195      },
    196    }
    197  ).exports;
    198 
    199  wasmThrower = exports.thrower;
    200  assertEq(exports.catcher(), 42);
    201 }
    202 
    203 // Tests for checking the tags of exceptions.
    204 {
    205  let exports = wasmEvalText(
    206    `(module
    207       (type (func (param i32)))
    208       (tag $exn (export "exn") (type 0))
    209       (func (export "thrower")
    210         (i32.const 42)
    211         (throw $exn)))`
    212  ).exports;
    213 
    214  let imports = {
    215    store: {
    216      throws: () => {
    217        return exports.thrower();
    218      },
    219      exn: exports.exn,
    220    },
    221  };
    222 
    223  // This passes the exception tag check and the exception is caught.
    224  assertEq(
    225    wasmEvalText(
    226      `(module
    227         (type (func (param i32)))
    228         (import "store" "throws" (func $thrower (result i32)))
    229         (import "store" "exn" (tag $exn (type 0)))
    230         (func (export "catches") (result i32)
    231           try (result i32)
    232             (call $thrower)
    233           catch $exn
    234             (i32.const 15)
    235             (i32.sub)
    236           end))`,
    237      imports
    238    ).exports.catches(),
    239    27
    240  );
    241 
    242  // This fails the exception tag check, despite the local exception having
    243  // a matching signature.
    244  assertWasmThrowsExn(() =>
    245    wasmEvalText(
    246      `(module
    247         (type (func (param i32)))
    248         (import "store" "throws" (func $thrower (result i32)))
    249         (tag $exn (type 0))
    250         (func (export "catchesFail") (result i32)
    251           try (result i32)
    252             (call $thrower)
    253           catch $exn ;; This should not recognise $exn, thus not unpack 42.
    254           end))`,
    255      imports
    256    ).exports.catchesFail()
    257  );
    258 }
    259 
    260 // Test that JS finally block executes after a Wasm throw.
    261 assertEq(
    262  (() => {
    263    try {
    264      wasmEvalText(
    265        `(module
    266           (type (func (param)))
    267           (tag $exn (type 0))
    268           (func (export "f")
    269             (throw $exn)))`
    270      ).exports.f();
    271    } finally {
    272      return true;
    273    }
    274    return false;
    275  })(),
    276  true
    277 );
    278 
    279 // Test that a wasm trap that passes through JS cannot be caught in Wasm.
    280 {
    281  let throwTrap = wasmEvalText(`(module (func (export "f") unreachable))`)
    282    .exports.f;
    283  let catcher = wasmEvalText(
    284    `(module
    285       (type (func))
    286       (tag $exn (type 0))
    287       (import "m" "f" (func $foreign (param) (result)))
    288       (func (export "f")
    289         try
    290           call $foreign
    291         catch $exn
    292         catch_all
    293         end))`,
    294    {
    295      m: {
    296        // JS frame that goes between the two wasm frames and just rethrows.
    297        f: () => {
    298          try {
    299            throwTrap();
    300          } catch (e) {
    301            throw e;
    302          }
    303        },
    304      },
    305    }
    306  ).exports.f;
    307 
    308  assertErrorMessage(
    309    () => catcher(),
    310    WebAssembly.RuntimeError,
    311    "unreachable executed"
    312  );
    313 }
    314 
    315 // Test delegate throwing out of function.
    316 assertWasmThrowsExn(() =>
    317  wasmEvalText(
    318    `(module
    319       (tag $exn (param))
    320       (func (export "f") (result i32)
    321         try (result i32)
    322           throw $exn
    323         delegate 0))`
    324  ).exports.f()
    325 );
    326 
    327 assertWasmThrowsExn(() =>
    328  wasmEvalText(
    329    `(module
    330       (tag $exn (param))
    331       (func (export "f") (result i32)
    332         try (result i32)
    333           i32.const 0
    334           if
    335             i32.const 1
    336             return
    337           else
    338             throw $exn
    339           end
    340           i32.const 0
    341         delegate 0))`
    342  ).exports.f()
    343 );