I assume traps are for exception handling, but the C API isn't well documented, and I'm not sure how to use them.
I have a wasm module for testing that just imports a function and calls it. I'm filling the import with a Dart function (represented as a wasm_func_callback_with_env_t) and I'm able to call back from wasm into Dart successfully. Now I want to handle the case where the Dart function throws an exception.
My current approach is to convert the exception and stack trace into a string, and stick that string in a wasm_trap_t using wasm_trap_new. wasm_func_callback_with_env_t returns a wasm_trap_t, so naturally I just return the trap from the callback. The wasm function is being invoked with wasm_func_call, which also returns a wasm_trap_t, so I'm checking if it returns a non-null trap.
So I assumed the way all this would work is that if the callback returns a non-null trap, then the engine halts execution and immediately returns the trap from wasm_func_call (and doesn't execute the rest of the wasm function). I want to get the original Dart exception string from that trap, and throw it again as a Dart exception. But when I look at the return value of wasm_func_call, it's always null, regardless of whether wasm_func_callback_with_env_t returned a trap or not.
How should I be using traps? Also, why does wasm_instance_new take a wasm_trap_t**?
Hey :-),
For you, the sun is probably shining,
Which means for me, since hours, it's for sure sleeping.
Midnight is close.
My brain has turned off already.
However here is a short disclose,
As much as possible friendly:
https://github.com/wasmerio/wasmer/blob/master/lib/c-api/tests/wasm_c_api/wasm-c-api/example/trap.c.
I'll provide a longer answer later :-).
Hello @liamappelbe,
Your assumptions were perfectly correct. I faced the same bug today when I was implementing traps inside host functions for our Go integration (see our rewrite PR, https://github.com/wasmerio/wasmer-go/pull/143, or more specifically the code on my fork, here and here). I wrote https://github.com/wasmerio/wasmer/pull/1751 to fix that bug. I hope it will help you!
About your last question:
How should I be using traps? Also, why does
wasm_instance_newtake awasm_trap_t**?
I'm taking the risk of being ridiculous but… I've. No. Idea. We don't use this argument in our C API for the moment. We set the result of wasm_instance_new to null if an error occured, so we don't need to set an array of wasm_trap_t. I'm asking in the working group. [2mn later]. Done, https://github.com/WebAssembly/wasm-c-api/issues/158.
How should I be using traps? Also, why does wasm_instance_new take a wasm_trap_t**?
When instantiating there are two kind of errors that can happen:
What is the last one? Wasm modules can define an entry point start function. In case one is defined, the VM shall call it upon instantiation.
This is t he same as doing:
var instance = module.instantiate(imports);
instance.exports[start_func_name]();
But done automatically by the VM when instantiating.
As the last line is just a function call, and as such that function call can trap, we allow the instantiate function to return traps.
Hope this clarifies why is needed!
As the last line is just a function call, and as such that function call can trap, we allow the instantiate function to return traps.
Ok, that makes sense. I guess should pass in a pointer to a wasm_trap_t* set to null, and check if it's still null after instantiation. When you say it can "return traps", do you mean multiple traps, or just 1?
Also, can traps be generated directly by the wasm code, or only by imported functions?
First, wasm_instance_new does use the wasm_trap_t** argument. I'm fixing that. But it's going to be an array of 1 item, always. See my comment here, https://github.com/wasmerio/wasmer/pull/1761#issuecomment-716587899.
Second, traps can be generated by host functions. Check this example, https://github.com/wasmerio/wasmer/blob/7eddb46cb049f976a82ac7b8b8031f8ea9484cff/lib/c-api/tests/wasm_c_api/test-early-exit.c#L30-L36. Traps can also be generated by Wasm code, either by a runtime error, or manually with unreachable as such:
(module
(func (export "trap") (result i32) (unreachable) (i32.const 1)))
Correction, @MarkMcCaskey and I think that wasm_trap_t** in wasm_instance_new doesn't represent an array, but an “output paratemeter” of kind wasm_trap_t*. See https://github.com/wasmerio/wasmer/pull/1761 to get more details if you wish.