diff --git a/src/library_exceptions.js b/src/library_exceptions.js index be10a631c688e..b55d72094d96e 100644 --- a/src/library_exceptions.js +++ b/src/library_exceptions.js @@ -335,11 +335,20 @@ var LibraryExceptions = { // ... // // Remove this JS function name, which is in the second line, from the stack - // trace. Note that .stack does not yet exist in all browsers (see #18828). + // trace. + // + // Note that .stack does not yet exist in all browsers (see #18828). + // Also, WebAssembly.Exception.stack is currently readonly, but this can + // change, and it is implemented as writable in Chrome and Node. Will check + // the 'writable' condition for now and later resolve this by either + // deleting this altogether or removing this condition check. if (e.stack) { - var arr = e.stack.split('\n'); - arr.splice(1,1); - e.stack = arr.join('\n'); + var pd = Object.getOwnPropertyDescriptor(e, 'stack'); + if (pd && pd.writable) { + var arr = e.stack.split('\n'); + arr.splice(1,1); + e.stack = arr.join('\n'); + } } throw e; }, diff --git a/test/common.py b/test/common.py index 036c89886e5c4..511685934b89f 100644 --- a/test/common.py +++ b/test/common.py @@ -301,6 +301,16 @@ def decorated(self, *args, **kwargs): return decorated +def requires_spidermonkey(func): + assert callable(func) + + def decorated(self, *args, **kwargs): + self.require_spidermonkey() + return func(self, *args, **kwargs) + + return decorated + + def node_pthreads(f): @wraps(f) def decorated(self, *args, **kwargs): @@ -698,6 +708,14 @@ def require_node_canary(self): else: self.fail('node canary required to run this test. Use EMTEST_SKIP_NODE_CANARY to skip') + def require_spidermonkey(self): + if not config.SPIDERMONKEY_ENGINE or config.SPIDERMONKEY_ENGINE not in config.JS_ENGINES: + if 'EMTEST_SKIP_SPIDERMONKEY' in os.environ: + self.skipTest('test requires spidermonkey and EMTEST_SKIP_SPIDERMONKEY is set') + else: + self.fail('spidermonkey required to run this test. Use EMTEST_SKIP_SPIDERMONKEY to skip') + self.require_engine(config.SPIDERMONKEY_ENGINE) + def require_engine(self, engine): logger.debug(f'require_engine: {engine}') if self.required_engine and self.required_engine != engine: diff --git a/test/test_core.py b/test/test_core.py index b92cc592834a9..cf14d73337383 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -27,7 +27,7 @@ from common import RunnerCore, path_from_root, requires_native_clang, test_file, create_file from common import skip_if, needs_dylink, no_windows, no_mac, is_slow_test, parameterized from common import env_modify, with_env_modify, disabled, flaky, node_pthreads, also_with_wasm_bigint -from common import read_file, read_binary, requires_v8, requires_node, requires_node_canary +from common import read_file, read_binary, requires_v8, requires_node, requires_node_canary, requires_spidermonkey from common import compiler_for, crossplatform, no_4gb, no_2gb from common import with_both_sjlj, also_with_standalone_wasm, can_do_standalone, no_wasm64 from common import NON_ZERO, WEBIDL_BINDER, EMBUILDER, PYTHON @@ -9641,6 +9641,25 @@ def test_wasm_worker_wait_async(self): self.prep_wasm_worker_in_node() self.do_runf('atomic/test_wait_async.c', emcc_args=['-sWASM_WORKERS']) + @requires_spidermonkey + def test_exceptions_stack_trace_and_message_wasm_eh(self): + # Currently writing to WebAssembly.Exception.stack property is not allowed + # in Firefox, but we need to ensure generating stack traces runs on FireFox + # without erroring out, even though stack trace simplification will not be + # done. See https://github.com/emscripten-core/emscripten/pull/21050 + src = r''' + #include + int main() { + throw std::runtime_error("my message"); + return 0; + } + ''' + self.emcc_args = ['--profiling-funcs', '-gsource-map'] + self.emcc_args = ['-g', '-fwasm-exceptions'] + self.set_setting('EXCEPTION_STACK_TRACES', 1) + err = self.do_run(src, assert_returncode=NON_ZERO) + self.assertNotContained('setting getter-only property "stack"', err) + # Generate tests for everything def make_run(name, emcc_args, settings=None, env=None,