From 70fc522dc170a2a8177a68b8396bb7d644620172 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 20 Mar 2026 05:41:58 +0000 Subject: [PATCH] [EH] Deprecate EXPORT_EXCEPTION_HANDLING_HELPERS This effectively removes `EXPORT_EXCEPTION_HANDLING_HELPERS` setting. This marks the setting as deprecated not to crash users' builds right away in case they are using it. Even though it still exists as a deprecated setting, setting it to true will not change anything. It used to export `getExceptionMessage` and a few more functions (`in/decrementexceptionRefCount`), but after #26493, `getExceptionMessage` is exported anyway when exceptions are used and either `-sASSERTIONS` or `-sEXCEPTION_STACK_TRACES` is set, which are set by default at `-O0`. For Wasm EH, the dependency is automatically detected. For Emscripten EH, we had to add `getExceptionMessage` to deps of `__cxa_throw`. This adds `in/decrementexceptionRefCount` to deps of `__cxa_throw` (for Emscripten EH) and `__throw_exception_with_stack_trace` (for Wasm EH) and removes `EXPORT_EXCEPTION_HANDLING_HELPERS`. (You can use it but it won't do anything additionally) --- ChangeLog.md | 3 +++ site/source/docs/porting/exceptions.rst | 11 +++++------ .../docs/tools_reference/settings_reference.rst | 3 +++ src/lib/libexceptions.js | 11 ++++++++++- src/settings.js | 1 + test/test_core.py | 13 +++---------- tools/link.py | 14 -------------- tools/settings.py | 1 + 8 files changed, 26 insertions(+), 31 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 8499c9baad459..df48acf873589 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,9 @@ See docs/process.md for more on how version tagging works. 5.0.4 (in development) ---------------------- +- `EXPORT_EXCEPTION_HANDLING_HELPERS` is deprecated and setting it will not do + anything. `getExceptionMessage` is exported anyway when `ASSERTIONS` or + `EXCEPTION_STACK_TRACES` is set, which are set by default at `-O0`. - The deprecated `EMSCRIPTEN` macro is now defined in `emscripten.h` rather than on the command line (`__EMSCRIPTEN__`, which is built into LLVM, should be used instead). (#26417) diff --git a/site/source/docs/porting/exceptions.rst b/site/source/docs/porting/exceptions.rst index 27e97ee6dad8d..250d7f193e553 100644 --- a/site/source/docs/porting/exceptions.rst +++ b/site/source/docs/porting/exceptions.rst @@ -144,9 +144,9 @@ message part is empty. If the thrown value is an instance of ``MyException`` that is a subclass of ``std::exception`` and its ``what`` message is ``My exception thrown``, this code will print ``MyException,My exception thrown``. -To use this function, you need to pass ``-sEXPORT_EXCEPTION_HANDLING_HELPERS`` -to the options. You need to enable either of Emscripten EH or Wasm EH to use -this option. +``getExceptionMessage`` is available when exceptions are used and either +``-sASSERTIONS`` or ``-sEXCEPTION_STACK_TRACES`` is set, which are by default +true at ``-O0``. If the stack pointer has been moved due to stack allocations within the Wasm function before an exception is thrown, you can use ``stackSave()`` and @@ -156,9 +156,8 @@ leaked. .. note:: If you catch a Wasm exception and do not rethrow it, you need to free the storage associated with the exception in JS using ``decrementExceptionRefcount`` method because the exception catching code in - Wasm does not have a chance to free it. See - ``test_EXPORT_EXCEPTION_HANDLING_HELPERS`` in test/test_core.py for an - example usage. + Wasm does not have a chance to free it. See ``test_getExceptionMessage`` in + ``test/test_core.py`` for an example usage. Using Exceptions and setjmp-longjmp Together diff --git a/site/source/docs/tools_reference/settings_reference.rst b/site/source/docs/tools_reference/settings_reference.rst index cf5e544de3c3d..ef836d053bbf5 100644 --- a/site/source/docs/tools_reference/settings_reference.rst +++ b/site/source/docs/tools_reference/settings_reference.rst @@ -1129,6 +1129,8 @@ manipulate the refcount manually to avoid memory leaks. See test_EXPORT_EXCEPTION_HANDLING_HELPERS in test/test_core.py for an example usage. +.. note:: This setting is deprecated + Default value: false .. _exception_stack_traces: @@ -3417,6 +3419,7 @@ these settings please open a bug (or reply to one of the existing bugs). - ``LEGALIZE_JS_FFI``: to disable JS type legalization use `-sWASM_BIGINT` or `-sSTANDALONE_WASM` - ``ASYNCIFY_EXPORTS``: please use JSPI_EXPORTS instead - ``LINKABLE``: under consideration for removal (https://github.com/emscripten-core/emscripten/issues/25262) + - ``EXPORT_EXCEPTION_HANDLING_HELPERS``: getExceptionMessage is automatically exported when ASSERTIONS or EXCEPTION_STACK_TRACES is 1 and throw is used .. _legacy-settings: diff --git a/src/lib/libexceptions.js b/src/lib/libexceptions.js index eb6eed4c6c0da..fd84b2e8114b6 100644 --- a/src/lib/libexceptions.js +++ b/src/lib/libexceptions.js @@ -91,6 +91,10 @@ var LibraryExceptions = { // 'new CppException', whose constructor calls getExceptionMessage. We can't // track the dependency there, so we track it here. '$getExceptionMessage', + // These functions can be necessary to prevent memory leaks from the JS + // side. Even though they are not used it here directly, we export them when + // 'throw' is used here. + '$decrementExceptionRefcount', '$incrementExceptionRefcount', #endif ], __cxa_throw: (ptr, type, destructor) => { @@ -314,7 +318,12 @@ 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', '$getExceptionMessage'], + __throw_exception_with_stack_trace__deps: [ + '$getCppExceptionTag', '$getExceptionMessage', + // These functions can be necessary to prevent memory leaks from the JS + // side. Even though they are not used it here directly, we export them + // when 'throw' is used here. + '$decrementExceptionRefcount', '$incrementExceptionRefcount'], __throw_exception_with_stack_trace: (ex) => { var e = new WebAssembly.Exception(getCppExceptionTag(), [ex], {traceStack: true}); e.message = getExceptionMessage(e); diff --git a/src/settings.js b/src/settings.js index 9230ab6206596..2aa74c60e20d1 100644 --- a/src/settings.js +++ b/src/settings.js @@ -767,6 +767,7 @@ var DISABLE_EXCEPTION_THROWING = false; // // See test_EXPORT_EXCEPTION_HANDLING_HELPERS in test/test_core.py for an // example usage. +// [deprecated] var EXPORT_EXCEPTION_HANDLING_HELPERS = false; // When this is enabled, exceptions will contain stack traces and uncaught diff --git a/test/test_core.py b/test/test_core.py index f129b2223a7f5..f9bddd574fb74 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -1499,9 +1499,8 @@ def test_exceptions_rethrow_missing(self): self.do_runf('main.cpp', None, assert_returncode=NON_ZERO) @with_all_eh_sjlj - def test_EXPORT_EXCEPTION_HANDLING_HELPERS(self): - self.set_setting('EXPORT_EXCEPTION_HANDLING_HELPERS') - + def test_getExceptionMessage(self): + self.set_setting('ASSERTIONS') self.maybe_closure() create_file('main.cpp', ''' #include @@ -1700,13 +1699,7 @@ def clear_all_relevant_settings(self): self.assert_fail([EMCC, test_file('hello_world.cpp'), '-fwasm-exceptions'] + self.get_cflags(), expected) clear_all_relevant_settings(self) - # EXPORT_EXCEPTION_HANDLING_HELPERS and EXCEPTION_STACK_TRACES requires - # either Emscripten EH or Wasm EH - self.set_setting('EXPORT_EXCEPTION_HANDLING_HELPERS') - expected = 'error: EXPORT_EXCEPTION_HANDLING_HELPERS requires either of -fexceptions or -fwasm-exceptions' - self.assert_fail([EMCC, test_file('hello_world.cpp')] + self.get_cflags(), expected) - clear_all_relevant_settings(self) - + # EXCEPTION_STACK_TRACES requires either Emscripten EH or Wasm EH self.set_setting('EXCEPTION_STACK_TRACES') expected = 'error: EXCEPTION_STACK_TRACES requires either of -fexceptions or -fwasm-exceptions' self.assert_fail([EMCC, test_file('hello_world.cpp')] + self.get_cflags(), expected) diff --git a/tools/link.py b/tools/link.py index 142236900a021..c9a28c6d8025d 100644 --- a/tools/link.py +++ b/tools/link.py @@ -1797,20 +1797,6 @@ def get_full_import_name(name): if settings.DISABLE_EXCEPTION_CATCHING and not settings.WASM_EXCEPTIONS: exit_with_error('EXCEPTION_STACK_TRACES requires either of -fexceptions or -fwasm-exceptions') - # Make `getExceptionMessage` and other necessary functions available for use. - if settings.EXPORT_EXCEPTION_HANDLING_HELPERS: - # If the user explicitly gave EXPORT_EXCEPTION_HANDLING_HELPERS=1 without - # enabling EH, errors out. - if settings.DISABLE_EXCEPTION_CATCHING and not settings.WASM_EXCEPTIONS: - exit_with_error('EXPORT_EXCEPTION_HANDLING_HELPERS requires either of -fexceptions or -fwasm-exceptions') - # We also export refcount incrementing and decrementing functions because if - # you catch an exception from JS, you may need to manipulate the refcount - # manually to avoid memory leaks. See test_EXPORT_EXCEPTION_HANDLING_HELPERS - # in test/test_core.py for an example usage. - settings.EXPORTED_FUNCTIONS += ['getExceptionMessage', 'incrementExceptionRefcount', 'decrementExceptionRefcount'] - if settings.WASM_EXCEPTIONS: - settings.REQUIRED_EXPORTS += ['__cpp_exception'] - if settings.SIDE_MODULE: # For side modules, we ignore all REQUIRED_EXPORTS that might have been added above. # They all come from either libc or compiler-rt. The exception is __wasm_call_ctors diff --git a/tools/settings.py b/tools/settings.py index 40a4af73eb1c4..bea1cd583e2f6 100644 --- a/tools/settings.py +++ b/tools/settings.py @@ -114,6 +114,7 @@ 'LEGALIZE_JS_FFI': 'to disable JS type legalization use `-sWASM_BIGINT` or `-sSTANDALONE_WASM`', 'ASYNCIFY_EXPORTS': 'please use JSPI_EXPORTS instead', 'LINKABLE': 'under consideration for removal (https://github.com/emscripten-core/emscripten/issues/25262)', + 'EXPORT_EXCEPTION_HANDLING_HELPERS': 'getExceptionMessage is automatically exported when ASSERTIONS or EXCEPTION_STACK_TRACES is 1 and throw is used', } # Settings that don't need to be externalized when serializing to json because they