exception-handling icon indicating copy to clipboard operation
exception-handling copied to clipboard

Identity of exception objects across frames

Open eholk opened this issue 8 years ago • 4 comments

Should exceptions remain strictly equal across call frames?


let wasm_module = /* instantiate a module with appropriate functions */

var saved_exception = undefined

function called_by_wasm() {
  try {
    wasm_module.exports.function_that_throws_exception();
  } catch(e) {
    saved_exception = e
    throw e
  }
}

function call_wasm() {
  try {
    wasm_module.exports.function_that_calls_called_by_wasm();
  } catch (e) {
    console.info(e === saved_exception)
  }
}

Let's assume that wasm_module.exports.function_that_calls_called_by_wasm either does not contain a catch block or catches and rethrows the exception.

Should the console.info line be guaranteed to print true?

One could imagine an implementation strategy for rethrow that reconstructs an equivalent exception rather than throwing the exact same one. Do we want to require rethrow to reuse the same exception object?

I think this constraint would only apply to the JavaScript embedding. I imagine there exist platforms where "reuse the same exception object" doesn't mean much.

eholk avatar Jul 31 '17 18:07 eholk

Note that exceptions are opague. Hence, you can't save it in a local variable. However, since (Wasm origin) exceptions are a tuple of values that are pushed back on the stack when caught, one could easily rebuild the exception and throw it.

On the other hand, the exception could be coming from some other source (such as JavaScript) and you catch it with a "catch_all" clause. In this context, the exception is completely opague, and can't be represented in Wasm. As such, this latter case is the main reason for considering a "rethrow" instruciton.

KarlSchimpf avatar Jul 31 '17 19:07 KarlSchimpf

Oh sorry, the code snippets I included in my post were in JavaScript, and I left the Wasm code to the reader's imagination.

Here's a less imaginary version of the Wasm module:

(module
  (type $func_v_v)
  (import "env" "called_by_wasm" (func $called_by_wasm (type $func_v_v)))

  (exception $e (type $func_v_v))

  (export "function_that_throws_exception" (func $function_that_throws_exception))
  (func $function_that_throws_exception (type $func_v_v)
    (throw $e))

  (export "function_that_calls_called_by_wasm" (func $function_that_calls_called_by_wasm))
  (func $function_that_calls_called_by_wasm (type $func_v_v)
    (call $called_by_wasm)))

Alternatively, the last function could be instead:

  (export "function_that_calls_called_by_wasm" (func $function_that_calls_called_by_wasm))
  (func $function_that_calls_called_by_wasm (type $func_v_v)
    (try 
      (call $called_by_wasm)
      (catch_all
        (rethrow))))

As such, this latter case is the main reason for considering a "rethrow" instruction.

Ah, thanks. I was wondering if rethrow was specifically needed. This is a strong motivator.

eholk avatar Aug 01 '17 00:08 eholk

Yes, I think the assertion in the OP has to hold. This isn't even Wasm-specific, but a consequence of the JS semantics for exceptions, which are arbitrary values, so must not magically change their identity. This should also extend to rethrow in Wasm, which ought to treat a JS exception as an opaque value, as @KarlSchimpf points out.

rossberg avatar Aug 01 '17 12:08 rossberg

@Ms2ger Again, I'm not sure what the relationship between the commit you referenced and this issue?

aheejin avatar Jun 16 '20 20:06 aheejin