Open kurrak opened 2 weeks ago
IIUC the way this is normally done on the web is to install a global exception handler on your page and report all unhandled exceptions that way. Exceptions thrown from native code (when using EXCEPTION_STACK_TRACES
) should have stack traces attacked just like Error's thrown by your JS code.
I think the window.onerror handler is the way to install a global error handler (at least on the web).
@aheejin might know more here.
@sbc100 thanks for reply and thoughts. Yes, we're working on web solution.
The problem with window.onerror
handler is that it is not called for errors that are handled in JS. We're trying to collect stack traces for all c++ exceptions not handled in c++. This is important, because we cannot guarantee that JS clients of our c++ API are never catching errors somewhere in call stack that in the end reaches out to c++.
To be honest, plugging into ___throw_exception_with_stack_trace
is not great solution either, as it is also called when c++ exception is handled in c++ (we wouldn't like to report such events). I'd love to know if there is any way to distinguish these two scenarios, too.
Side note: window.onerror
is also not called for errors that are thrown from c++ code called from within JS promise (in this case browser logs error starting with Uncaught (in promise)
message), which translates to JS promise rejection. This can be easly handled by additional window.onUnhandledRejection
, though.
So in addition to onerror
+ onUnhandledRejection
you would like to know when one of your users catches and exception generated by your code? This sounds like a somewhat unusual request, but there are probably ways you can me it work.
One way to do this would be to ask you users to call your exception reporting function whenever they catch and ignore exceptions from your code.
Another way would be something like ABORT_ON_WASM_EXCEPTIONS
which wraps ever wasm export in a try catch. See https://github.com/emscripten-core/emscripten/blob/543993ecf6fbf1c97c2ed56d062dc504978962c3/src/preamble.js#L525-L602. This approach does have runtime cost as well as code size cost though.
I'm not sure if I understood your request correctly. When -sEXCEPTION_STACK_TRACES
(or -sASSERIONS
or -O0
, both of which set -sEXCEPTION_STACK_TRACES
) is set, all native exceptions thrown in C++ call out to JS ___throw_exception_with_stack_trace
to get the stack traces embedded in the object, as you've observed. At this point we don't know where or whether exception is going to be handled. I'm not sure what you mean by "plugging into" ___throw_exception_with_stack_trace
.
And whenever you have that exception object in JS, you can access its WebAssebly.stack
property to get the stack trace string. It can be any of the handlers you mentioned.
I guess I don't understand what the problem is correctly. Can you elaborate more?
@aheejin, @sbc100 thanks for replies 🙌
I guess I don't understand what the problem is correctly. Can you elaborate more?
Sure! Here's the thing:
-fwasm-exceptions
One way to do this would be to ask you users to call your exception reporting function whenever they catch and ignore exceptions from your code.
This is specifically something I try to avoid.
Another way would be something like
ABORT_ON_WASM_EXCEPTIONS
which wraps ever wasm export in a try catch. See
ABORT_ON_WASM_EXCEPTIONS
sounds like a behaviour I want: to treat c++ exception not handled in c++ similarly to c++ crash. What I was missing before was the customisation point that I can plug my code to send proper stack trace to crash reporting system (window.onerror
and window.onunhandledrejection
events are not an option, because they can be easily not called whenever client code catches exception anywhere along throwing call stack). Now I see there is Module.onAbort
callback that seems exactly like what I need.
The challenge now is to get correct stack trace as onAbort
is called differenty depending on scenario:
abort()
function - onAbort's what
parameter is string with "cause" (which can be empty), but "current" call stack contains all necessary frameswhat
parameter contains string with call stack I'm interested in, but "current" call stack is just JS framesDo you see a good/correct way to distinguish these two scenarios in onAbort
callback so I can decide how to get correct call stack? Do you know there are other ways onAbort
can be called that I should handle differently?
As a side note: do you think onAbort
should receive WebAssembly.Exception
for scenario with not handled c++ exception?
So just to be clear, if I'm a user of your library, and your library crashes as part of my application, you want the crash report to go to your server by default? Wouldn't that be something that I, as the user of the library, would want to opt into explictly?
So just to be clear, if I'm a user of your library, and your library crashes as part of my application, you want the crash report to go to your server by default? Wouldn't that be something that I, as the user of the library, would want to opt into explictly?
Or is this actually a normal/common thing to do in the world of JS libraries? (I'm not super familiar with the latest JS library trends).
So just to be clear, if I'm a user of your library, and your library crashes as part of my application, you want the crash report to go to your server by default? Wouldn't that be something that I, as the user of the library, would want to opt into explictly? Or is this actually a normal/common thing to do in the world of JS libraries? (I'm not super familiar with the latest JS library trends).
To be specific: this is internal library used by multiple client apps within our organisation. That being said this behaviour is opt-in and available behind a setting passed during library setup. I want to keep it this way: one time configuration and no more responsibility on client app side for this to work.
@sbc100 our current idea for getting the access to correct call stack is to use --post-js
script to override Emscripten-generated abort
function. We'd wrap it in additional try/catch, get the call stack in catch block and rethrow it. We think this should work ok nevertheless of aborting scenario (crash vs. unhandled exception). Do you think it is a good approach?
there is a try .. catch in side handleMessage of file worker.mjs
, you may want to process with the exception throw
This is a question, not a bug.
We're trying to find a generic way to report stack traces for all exceptions unhandled in c++ (meaning: also for c++ exceptions that are handled in JS). We're using
-fwasm-exceptions
and-sEXCEPTION_STACK_TRACES
.We found out that Emscripten's
___throw_exception_with_stack_trace
JS function is called whenever c++ exception is thrown. What we'd like to do is plug into this function, so we can get a stack trace and send it to 3rd party crash reporting system.We've been trying different approaches, but had little to no success. We're looking for any guidance, or the reason for why it is bad/wrong idea in the first place.
Version of emscripten/emsdk: