Skip to content

[EH] rethrowing current exception from catch lead to loss of callstack #20301

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ravisumit33 opened this issue Sep 20, 2023 · 1 comment · Fixed by #20372
Closed

[EH] rethrowing current exception from catch lead to loss of callstack #20301

ravisumit33 opened this issue Sep 20, 2023 · 1 comment · Fixed by #20372
Assignees

Comments

@ravisumit33
Copy link
Contributor

ravisumit33 commented Sep 20, 2023

Please include the following in your bug report:

Version of emscripten/emsdk:

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.35 (a90c5abb489c516f59c0d16864d953d4bedd37da)
clang version 17.0.0 (https://github.com/llvm/llvm-project 6865cff8ea8b07d9f2385fd92cecb422404f0f35)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: ~/emsdk/upstream/bin

test.cpp

#include <emscripten.h>
#include <exception>

void fun2() {
    throw "error";
}

void  EMSCRIPTEN_KEEPALIVE fun1() {
    try {
        fun2();
    } catch(...) {
        auto e = std::current_exception();
        std::rethrow_exception(e);
    }
}

Above program is built with -sEXCEPTION_STACK_TRACES=1. fun1 is exported on Module & is called from js side as below:

test.js

 try {
    console.log(Module._fun1());
  } catch (e) {
    console.log(e.stack);
  }

Ideally, full callstack including both fun2 & fun1 should get printed. However, in Wasm EH no callstack is obtained while in Emscripten EH below callstack is obtained:

char const*
    at ___resumeException (http://localhost:8000/build/test.js:1043:25)
    at fun1 (http://localhost:8000/build/test.wasm:wasm-function[25]:0xb4d)
    at Module._fun1 (http://localhost:8000/build/test.js:1273:69)

Both of these scenarios are wrong and should print the actual callStack.

aheejin added a commit to aheejin/emscripten that referenced this issue Oct 2, 2023
In Wasm EH, even if we set `-sASSERTION` or `-sEXCEPTION_STACK_TRACES`,
if we rethrow an exception in the code, we lose the effect of that
option because previously we called `__throw_exception_with_stack_trace`
only in `__cxa_throw`:
https://github.com/emscripten-core/emscripten/blob/9ce7020632aa6f7578c6e40e197b800a4dd7073f/system/lib/libcxxabi/src/cxa_exception.cpp#L294-L296

This adds the same mechanism to `__cxa_rethrow` (which is used for
C++ `throw;`) and `__cxa_rethrow_primary_exception` (which is used for
`std::rethrow_exception`).

This does not solve the problem of losing stack traces _before_ the
rethrowing. libc++abi's `__cxa_rethrow` and
`__cxa_rethrow_primary_exception` are implemented as throwing a pointer
in the same way we first throw it and they are not aware of any
metadata. This happens even in the native platform with GDB; GDB's
backtrace only shows stack traces after rethrowing. We may try to fix
this later by passing `exnref`
(WebAssembly/exception-handling#281) to the
library, but this is likely to take some time.

Partially fixes emscripten-core#20301.
@aheejin
Copy link
Member

aheejin commented Oct 2, 2023

Thanks for reporting. As I described in #20372, that we lose stack traces before rethrowing cannot be solved easily at the moment, both for Emscripten EH and Wasm EH. The native gdb backtraces don't support it either. We might be able to fix it later, but I think that will take some time.

The problem that we completely lose stack traces in Wasm EH after rethrowing is a bug, which should be fixed by #20372.

aheejin added a commit that referenced this issue Oct 3, 2023
In Wasm EH, even if we set `-sASSERTION` or `-sEXCEPTION_STACK_TRACES`,
if we rethrow an exception in the code, we lose the effect of that
option because previously we called `__throw_exception_with_stack_trace`
only in `__cxa_throw`:
https://github.com/emscripten-core/emscripten/blob/9ce7020632aa6f7578c6e40e197b800a4dd7073f/system/lib/libcxxabi/src/cxa_exception.cpp#L294-L296

This adds the same mechanism to `__cxa_rethrow` (which is used for
C++ `throw;`) and `__cxa_rethrow_primary_exception` (which is used for
`std::rethrow_exception`).

This does not solve the problem of losing stack traces _before_ the
rethrowing. libc++abi's `__cxa_rethrow` and
`__cxa_rethrow_primary_exception` are implemented as throwing a pointer
in the same way we first throw it and they are not aware of any
metadata. This happens even in the native platform with GDB; GDB's
backtrace only shows stack traces after rethrowing. We may try to fix
this later by passing `exnref`
(WebAssembly/exception-handling#281) to the
library, but this is likely to take some time.

Partially fixes #20301.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants