-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Description
How to reproduce:
- Compile with Emscripten EH
- Throw exception from C++
- Catch in C++
- In the C++ catch, rethrow in JS and catch as JS object
- Save JS
valin C++ - Outside of C++ catch, rethrow
val - Try to catch in C++
RuntimeError: memory access out of bounds
#include <iostream>
#include <emscripten/val.h>
using namespace emscripten;
int main() {
val error;
try {
throw std::runtime_error("oopsie");
} catch (const std::runtime_error &) {
// Internal API: see https://github.com/emscripten-core/emscripten/issues/25963
error = val::take_ownership(emscripten::internal::_emval_from_current_cxa_exception());
}
try {
error.throw_();
} catch (const std::runtime_error &ex) {
std::clog << "Caught: " << ex.what() << '\n';
}
}em++ ./rethrow.cpp -o ./rethrow -lembind -fexceptions -std=c++20 -vCompile log
"/home/swdv/emsdk/upstream/bin/clang++" -target wasm32-unknown-emscripten -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-cxx-exceptions -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr --sysroot=/home/swdv/emsdk/upstream/emscripten/cache/sysroot -DEMSCRIPTEN -Xclang -iwithsysroot/include/fakesdl -Xclang -iwithsysroot/include/compat -fexceptions -std=c++20 -v -c ./rethrow.cpp -o /tmp/emscripten_temp_pi6iqhvl/rethrow.o
clang version 23.0.0git (https:/github.com/llvm/llvm-project b6e5e8ecb57088dcdc0a72515869a52d24669bdd)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /home/swdv/emsdk/upstream/bin
Build config: +assertions
(in-process)
"/home/swdv/emsdk/upstream/bin/clang-23" -cc1 -triple wasm32-unknown-emscripten -emit-obj -disable-free -clear-ast-before-backend -main-file-name rethrow.cpp -mrelocation-model static -mframe-pointer=none -ffp-contract=on -fno-rounding-math -mconstructor-aliases -target-cpu generic -fvisibility=hidden -debugger-tuning=gdb -fdebug-compilation-dir=/home/swdv/webtest -v -fcoverage-compilation-dir=/home/swdv/webtest -resource-dir /home/swdv/emsdk/upstream/lib/clang/23 -D EMSCRIPTEN -isysroot /home/swdv/emsdk/upstream/emscripten/cache/sysroot -internal-isystem /home/swdv/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten/c++/v1 -internal-isystem /home/swdv/emsdk/upstream/emscripten/cache/sysroot/include/c++/v1 -internal-isystem /home/swdv/emsdk/upstream/lib/clang/23/include -internal-isystem /home/swdv/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten -internal-isystem /home/swdv/emsdk/upstream/emscripten/cache/sysroot/include -std=c++20 -fdeprecated-macro -ferror-limit 19 -fmessage-length=120 -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -fcolor-diagnostics -iwithsysroot/include/fakesdl -iwithsysroot/include/compat -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-cxx-exceptions -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr -o /tmp/emscripten_temp_pi6iqhvl/rethrow.o -x c++ ./rethrow.cpp
clang -cc1 version 23.0.0git based upon LLVM 23.0.0git default target x86_64-unknown-linux-gnu
ignoring nonexistent directory "/home/swdv/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten/c++/v1"
ignoring nonexistent directory "/home/swdv/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten"
#include "..." search starts here:
#include <...> search starts here:
/home/swdv/emsdk/upstream/emscripten/cache/sysroot/include/fakesdl
/home/swdv/emsdk/upstream/emscripten/cache/sysroot/include/compat
/home/swdv/emsdk/upstream/emscripten/cache/sysroot/include/c++/v1
/home/swdv/emsdk/upstream/lib/clang/23/include
/home/swdv/emsdk/upstream/emscripten/cache/sysroot/include
End of search list.
/home/swdv/emsdk/upstream/bin/clang --version
/home/swdv/emsdk/upstream/bin/wasm-ld -o ./rethrow.wasm /tmp/tmpazlgyhzilibemscripten_js_symbols.so --strip-debug --export=emscripten_stack_get_end --export=emscripten_stack_get_free --export=emscripten_stack_get_base --export=emscripten_stack_get_current --export=emscripten_stack_init --export=_emscripten_stack_alloc --export=__getTypeName --export=__cxa_can_catch --export=__cxa_increment_exception_refcount --export=__cxa_decrement_exception_refcount --export=setThrew --export=__cxa_free_exception --export=__wasm_call_ctors --export=_emscripten_stack_restore --export=__get_exception_message --export=free --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__start_em_lib_deps --export-if-defined=__stop_em_lib_deps --export-if-defined=__start_em_js --export-if-defined=__stop_em_js --export-if-defined=main --export-if-defined=__main_argc_argv --export-if-defined=fflush --export-table -z stack-size=65536 --no-growable-memory --initial-heap=16777216 --no-entry --stack-first --table-base=1 /tmp/emscripten_temp_pi6iqhvl/rethrow.o -lembind-rtti -L/home/swdv/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten -L/home/swdv/emsdk/upstream/emscripten/src/lib -lGL-getprocaddr -lal -lhtml5 -lstubs-debug -lnoexit -lc-debug -ldlmalloc-debug -lcompiler_rt -lc++-debug -lc++abi-debug -lsockets -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-cxx-exceptions -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr
/home/swdv/emsdk/upstream/bin/llvm-objcopy ./rethrow.wasm ./rethrow.wasm '--remove-section=.debug*' --remove-section=producers --remove-section=name
/home/swdv/emsdk/node/22.16.0_64bit/bin/node /home/swdv/emsdk/upstream/emscripten/tools/compiler.mjs -
RuntimeError: memory access out of bounds
at wasm://wasm/00128e82:wasm-function[1445]:0x428ec
at /home/swdv/webtest/rethrow:609:12
at getExceptionMessageCommon (/home/swdv/webtest/rethrow:4706:7)
at getExceptionMessage (/home/swdv/webtest/rethrow:4719:38)
at new CppException (/home/swdv/webtest/rethrow:334:21)
at ___resumeException (/home/swdv/webtest/rethrow:1165:25)
at wasm://wasm/00128e82:wasm-function[54]:0x1b32
at wasm://wasm/00128e82:wasm-function[99]:0x2dde
at /home/swdv/webtest/rethrow:609:12
at callMain (/home/swdv/webtest/rethrow:5726:15)
Compare with -fwasm-exceptions, which prints Caught: oopsie, as intended.
Probable cause
It seems the cause may be as follows:
___cxa_end_catchsetsexceptionLast = 0;after the first C++ catch
emscripten/src/lib/libexceptions.js
Lines 172 to 173 in 3407c19
___cxa_decrement_exception_refcount(info.excPtr); exceptionLast = 0; // XXX in decRef? - Later in JS
findMatchingCatchseesexceptionLastis not set, causing the error
emscripten/src/lib/libexceptions.js
Lines 218 to 229 in 3407c19
$findMatchingCatch: (args) => { var thrown = #if EXCEPTION_STACK_TRACES exceptionLast?.excPtr; #else exceptionLast; #endif if (!thrown) { // just pass through the null ptr setTempRet0(0); return 0; }
When thrown from C++, ___cxa_throw/___cxa_rethrow would set exceptionLast, but that doesn't happen when rethrown from JS.
I don't think removing exceptionLast = 0; would solve it, because then I think it may rethrow the wrong exception. EDIT: It will rethrow the wrong exception and already does in other cases, see comment below.
Version
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 5.0.1-git (14fc538)
clang version 23.0.0git (llvm/llvm-project@b6e5e8e)