diff --git a/ChangeLog.md b/ChangeLog.md index d1118eb70b83b..25ebe0c2546a9 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -21,6 +21,8 @@ See docs/process.md for more on how version tagging works. 3.1.24 (in development) ----------------------- - In Wasm exception mode (`-fwasm-exceptions`), when `ASSERTIONS` is enabled, + uncaught exceptions will display stack traces and what() message. (#17979 and + #18003) uncaught exceptions will display stack traces. (#17979) - It is now possible to specify indirect dependencies on JS library functions directly in C/C++ source code. For example, in the case of a EM_JS or EM_ASM diff --git a/emcc.py b/emcc.py index 00581eda57756..1b0078dca9801 100755 --- a/emcc.py +++ b/emcc.py @@ -2633,6 +2633,7 @@ def get_full_import_name(name): # using the JS API, which needs this C++ tag exported. if settings.ASSERTIONS and settings.WASM_EXCEPTIONS: settings.EXPORTED_FUNCTIONS += ['___cpp_exception'] + settings.EXPORT_EXCEPTION_HANDLING_HELPERS = True # Make `getExceptionMessage` and other necessary functions available for use. if settings.EXPORT_EXCEPTION_HANDLING_HELPERS: @@ -2642,7 +2643,7 @@ def get_full_import_name(name): # What you need to do is different depending on the kind of EH you use # (https://github.com/emscripten-core/emscripten/issues/17115). settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$getExceptionMessage', '$incrementExceptionRefcount', '$decrementExceptionRefcount'] - settings.EXPORTED_FUNCTIONS += ['getExceptionMessage', '___get_exception_message'] + settings.EXPORTED_FUNCTIONS += ['getExceptionMessage', '___get_exception_message', '_free'] if settings.WASM_EXCEPTIONS: settings.EXPORTED_FUNCTIONS += ['___cpp_exception', '___cxa_increment_exception_refcount', '___cxa_decrement_exception_refcount', '___thrown_object_from_unwind_exception'] diff --git a/src/library_exceptions.js b/src/library_exceptions.js index 511030bab2791..3cca7181e6b83 100644 --- a/src/library_exceptions.js +++ b/src/library_exceptions.js @@ -396,11 +396,11 @@ var LibraryExceptions = { $getExceptionMessageCommon__deps: ['__get_exception_message', 'free', '$withStackSave'], $getExceptionMessageCommon: function(ptr) { return withStackSave(function() { - var type_addr_addr = stackAlloc(4); - var message_addr_addr = stackAlloc(4); - ___get_exception_message(ptr, type_addr_addr, message_addr_addr); - var type_addr = HEAP32[type_addr_addr >> 2]; - var message_addr = HEAP32[message_addr_addr >> 2]; + var type_addr_addr = stackAlloc({{{ POINTER_SIZE }}}); + var message_addr_addr = stackAlloc({{{ POINTER_SIZE }}}); + ___get_exception_message({{{ to64('ptr') }}}, {{{ to64('type_addr_addr') }}}, {{{ to64('message_addr_addr') }}}); + var type_addr = {{{ makeGetValue('type_addr_addr', 0, '*') }}}; + var message_addr = {{{ makeGetValue('message_addr_addr', 0, '*') }}}; var type = UTF8ToString(type_addr); _free(type_addr); var message; @@ -431,9 +431,10 @@ var LibraryExceptions = { // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Exception // In release builds, this function is not needed and the native // _Unwind_RaiseException in libunwind is used instead. - __throw_exception_with_stack_trace__deps: ['$getCppExceptionTag'], + __throw_exception_with_stack_trace__deps: ['$getCppExceptionTag', '$getExceptionMessage'], __throw_exception_with_stack_trace: function(ex) { var e = new WebAssembly.Exception(getCppExceptionTag(), [ex], {traceStack: true}); + e.message = getExceptionMessage(e); // The generated stack trace will be in the form of: // // Error diff --git a/system/lib/libcxxabi/src/cxa_exception.cpp b/system/lib/libcxxabi/src/cxa_exception.cpp index bbb6cd8ddbe4c..56e38c50d850c 100644 --- a/system/lib/libcxxabi/src/cxa_exception.cpp +++ b/system/lib/libcxxabi/src/cxa_exception.cpp @@ -256,7 +256,7 @@ exception. #if defined(__USING_WASM_EXCEPTIONS__) && !defined(NDEBUG) extern "C" { -void __throw_exception_with_stack_trace(_Unwind_Exception*, bool); +void __throw_exception_with_stack_trace(_Unwind_Exception*); } // extern "C" #endif @@ -293,7 +293,7 @@ __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) { #else // In debug mode, call a JS library function to use WebAssembly.Exception JS // API, which enables us to include stack traces - __throw_exception_with_stack_trace(&exception_header->unwindHeader, true); + __throw_exception_with_stack_trace(&exception_header->unwindHeader); #endif #else _Unwind_RaiseException(&exception_header->unwindHeader); diff --git a/test/test_other.py b/test/test_other.py index 118a04a38cd12..0aac2b3f142bc 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -7905,10 +7905,12 @@ def test_wasm_nope(self): self.assertContained('no native wasm support detected', out) @requires_v8 - def test_wasm_exceptions_stack_trace(self): + def test_wasm_exceptions_stack_trace_and_message(self): src = r''' + #include + void bar() { - throw 3; + throw std::runtime_error("my message"); } void foo() { bar(); @@ -7921,8 +7923,8 @@ def test_wasm_exceptions_stack_trace(self): emcc_args = ['-g', '-fwasm-exceptions'] self.v8_args.append('--experimental-wasm-eh') - # Stack trace example for this example code: - # exiting due to exception: [object WebAssembly.Exception],Error + # Stack trace and message example for this example code: + # exiting due to exception: [object WebAssembly.Exception],Error: std::runtime_error, my message # at __cxa_throw (wasm://wasm/009a7c9a:wasm-function[1551]:0x24367) # at bar() (wasm://wasm/009a7c9a:wasm-function[12]:0xf53) # at foo() (wasm://wasm/009a7c9a:wasm-function[19]:0x154e) @@ -7932,7 +7934,12 @@ def test_wasm_exceptions_stack_trace(self): # at callMain (test.js:4567:15) # at doRun (test.js:4621:23) # at run (test.js:4636:5) - stack_trace_checks = ['at __cxa_throw', 'at bar', 'at foo', 'at main'] + stack_trace_checks = [ + 'std::runtime_error,my message', + 'at __cxa_throw', + 'at bar', + 'at foo', + 'at main'] # We attach stack traces to exception objects only when ASSERTIONS is set self.set_setting('ASSERTIONS')