Skip to content

Commit 3d0ff6e

Browse files
authored
[EH] Add EXCEPTION_STACK_TRACES option (#18642)
This adds `EXCEPTION_STACK_TRACES` option, which embeds stack traces into exception objects even when `ASSERTIONS` is not set. This is for the users who wants exception stack traces but don't want to incur the full overhead of `ASSERTIONS`. Exception stack traces are enabled when either of `ASSERTIONS` or `EXCEPTION_STACK_TRACES` is true. This currently works only for Wasm EH. The reason this option's name is not `WASM_EXCEPTION_STACK_TRACES` is I think this can work for Emscripten EH later if something like #18535 lands. Fixes #18533.
1 parent 98899a7 commit 3d0ff6e

File tree

7 files changed

+57
-8
lines changed

7 files changed

+57
-8
lines changed

ChangeLog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ See docs/process.md for more on how version tagging works.
2020

2121
3.1.32 (in development)
2222
-----------------------
23+
- In Wasm exception mode (`-fwasm-exceptions`), when
24+
`EXCEPTION_STACK_TRACES` is enabled, uncaught exceptions will display stack
25+
traces. This defaults to true when `ASSERTIONS` is enabled. This option is
26+
mainly for the users who want only exceptions' stack traces without turning
27+
`ASSERTIONS` on. This option currently works only for Wasm exceptions
28+
(-fwasm-exceptions). (#18642)
2329

2430
3.1.31 - 01/26/23
2531
-----------------

emcc.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2796,9 +2796,13 @@ def get_full_import_name(name):
27962796
if settings.WASM_EXCEPTIONS:
27972797
settings.REQUIRED_EXPORTS += ['__trap']
27982798

2799-
# When ASSERTIONS is set, we include stack traces in Wasm exception objects
2800-
# using the JS API, which needs this C++ tag exported.
2801-
if settings.ASSERTIONS and settings.WASM_EXCEPTIONS:
2799+
# When ASSERTIONS or EXCEPTION_STACK_TRACES is set, we include stack traces in
2800+
# Wasm exception objects using the JS API, which needs this C++ tag exported.
2801+
if settings.ASSERTIONS:
2802+
if 'EXCEPTION_STACK_TRACES' in user_settings and not settings.EXCEPTION_STACK_TRACES:
2803+
exit_with_error('EXCEPTION_STACK_TRACES cannot be disabled when ASSERTIONS are enabled')
2804+
default_setting('EXCEPTION_STACK_TRACES', 1)
2805+
if settings.EXCEPTION_STACK_TRACES and settings.WASM_EXCEPTIONS:
28022806
settings.EXPORTED_FUNCTIONS += ['___cpp_exception']
28032807
settings.EXPORT_EXCEPTION_HANDLING_HELPERS = True
28042808

src/library_exceptions.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ var LibraryExceptions = {
401401
#endif
402402
},
403403

404-
#if ASSERTIONS
404+
#if EXCEPTION_STACK_TRACES
405405
// Throw a WebAssembly.Exception object with the C++ tag with a stack trace
406406
// embedded. WebAssembly.Exception is a JS object representing a Wasm
407407
// exception, provided by Wasm JS API:

src/settings.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,13 @@ var EXCEPTION_CATCHING_ALLOWED = [];
708708
// example usage.
709709
var EXPORT_EXCEPTION_HANDLING_HELPERS = false;
710710

711+
// When this is enabled, exceptions will contain stack traces and uncaught
712+
// exceptions will display stack traces upon exiting. This defaults to true when
713+
// ASSERTIONS is enabled. This option is for users who want exceptions' stack
714+
// traces but do not want other overheads ASSERTIONS can incur. This currently
715+
// works only for Wasm exceptions (-fwasm-exceptions).
716+
var EXCEPTION_STACK_TRACES = false;
717+
711718
// Internal: Tracks whether Emscripten should link in exception throwing (C++
712719
// 'throw') support library. This does not need to be set directly, but pass
713720
// -fno-exceptions to the build disable exceptions support. (This is basically

src/shell.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ var read_,
173173
function logExceptionOnExit(e) {
174174
if (e instanceof ExitStatus) return;
175175
let toLog = e;
176-
#if ASSERTIONS
176+
#if EXCEPTION_STACK_TRACES
177177
if (e && typeof e == 'object' && e.stack) {
178178
toLog = [e, e.stack];
179179
}

test/test_other.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8062,7 +8062,12 @@ def test_wasm_nope(self):
80628062
out = self.run_js('a.out.js', assert_returncode=NON_ZERO)
80638063
self.assertContained('no native wasm support detected', out)
80648064

8065-
@requires_wasm_eh
8065+
# FIXME Node v18.13 (LTS as of Jan 2023) has not yet implemented the new
8066+
# optional 'traceStack' option in WebAssembly.Exception constructor
8067+
# (https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/Exception/Exception)
8068+
# and embeds stack traces unconditionally. Change this back to
8069+
# @requires_wasm_eh if this issue is fixed later.
8070+
@requires_v8
80668071
def test_wasm_exceptions_stack_trace_and_message(self):
80678072
src = r'''
80688073
#include <stdexcept>
@@ -8098,12 +8103,30 @@ def test_wasm_exceptions_stack_trace_and_message(self):
80988103
'at foo',
80998104
'at main']
81008105

8101-
# We attach stack traces to exception objects only when ASSERTIONS is set
8102-
self.set_setting('ASSERTIONS')
8106+
# Stack traces are enabled when either of ASSERTIONS or
8107+
# EXCEPTION_STACK_TRACES is enabled. You can't disable
8108+
# EXCEPTION_STACK_TRACES when ASSERTIONS is enabled.
8109+
8110+
# Prints stack traces
8111+
self.set_setting('ASSERTIONS', 1)
8112+
self.set_setting('EXCEPTION_STACK_TRACES', 1)
81038113
self.do_run(src, emcc_args=emcc_args, assert_all=True,
81048114
assert_returncode=NON_ZERO, expected_output=stack_trace_checks)
81058115

8116+
# Prints stack traces
8117+
self.set_setting('ASSERTIONS', 0)
8118+
self.set_setting('EXCEPTION_STACK_TRACES', 1)
8119+
self.do_run(src, emcc_args=emcc_args, assert_all=True,
8120+
assert_returncode=NON_ZERO, expected_output=stack_trace_checks)
8121+
8122+
# Not allowed
8123+
create_file('src.cpp', src)
8124+
err = self.expect_fail([EMCC, 'src.cpp', '-sASSERTIONS=1', '-sEXCEPTION_STACK_TRACES=0'])
8125+
self.assertContained('EXCEPTION_STACK_TRACES cannot be disabled when ASSERTIONS are enabled', err)
8126+
8127+
# Doesn't print stack traces
81068128
self.set_setting('ASSERTIONS', 0)
8129+
self.set_setting('EXCEPTION_STACK_TRACES', 0)
81078130
err = self.do_run(src, emcc_args=emcc_args, assert_returncode=NON_ZERO)
81088131
for check in stack_trace_checks:
81098132
self.assertNotContained(check, err)

tools/system_libs.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,15 @@ class libcxxabi(NoExceptLibrary, MTLibrary, DebugLibrary):
13781378
]
13791379
includes = ['system/lib/libcxx/src']
13801380

1381+
def __init__(self, **kwargs):
1382+
super().__init__(**kwargs)
1383+
# TODO EXCEPTION_STACK_TRACES currently requires the debug version of
1384+
# libc++abi, causing the debug version of libc++abi to be linked, which
1385+
# increases code size. libc++abi is not a big library to begin with, but if
1386+
# this becomes a problem, consider making EXCEPTION_STACK_TRACES work with
1387+
# the non-debug version of libc++abi.
1388+
self.is_debug |= settings.EXCEPTION_STACK_TRACES
1389+
13811390
def get_cflags(self):
13821391
cflags = super().get_cflags()
13831392
if not self.is_mt and not self.is_ww:

0 commit comments

Comments
 (0)