diff --git a/emcc.py b/emcc.py index 37a8a25ce588..87a8c3879e91 100755 --- a/emcc.py +++ b/emcc.py @@ -2566,6 +2566,9 @@ def get_full_import_name(name): if settings.SUPPORT_LONGJMP == 'wasm': settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.append('__c_longjmp') + if settings.EXCEPTION_HANDLING: + settings.REQUIRED_EXPORTS += ['__trap'] + return target, wasm_target diff --git a/src/preamble.js b/src/preamble.js index 2090af133dbb..c4472becda99 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -605,12 +605,20 @@ function abort(what) { // Use a wasm runtime error, because a JS error might be seen as a foreign // exception, which means we'd run destructors on it. We need the error to // simply make the program stop. + // FIXME This approach does not work in Wasm EH because it currently does not assume + // all RuntimeErrors are from traps; it decides whether a RuntimeError is from + // a trap or not based on a hidden field within the object. So at the moment + // we don't have a way of throwing a wasm trap from JS. TODO Make a JS API that + // allows this in the wasm spec. // Suppress closure compiler warning here. Closure compiler's builtin extern // defintion for WebAssembly.RuntimeError claims it takes no arguments even // though it can. // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed. - +#if EXCEPTION_HANDLING == 1 + // See above, in the meantime, we resort to wasm code for trapping. + ___trap(); +#else /** @suppress {checkTypes} */ var e = new WebAssembly.RuntimeError(what); @@ -621,6 +629,7 @@ function abort(what) { // in code paths apart from instantiation where an exception is expected // to be thrown when abort is called. throw e; +#endif } // {{MEM_INITIALIZER}} diff --git a/system/lib/compiler-rt/__trap.c b/system/lib/compiler-rt/__trap.c new file mode 100644 index 000000000000..8c714078ae91 --- /dev/null +++ b/system/lib/compiler-rt/__trap.c @@ -0,0 +1,3 @@ +void __trap() { + __builtin_trap(); +} diff --git a/tests/test_core.py b/tests/test_core.py index 2a03fac6f32d..a8d0bf337a6f 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1639,6 +1639,24 @@ class Polymorphic {virtual void member(){}}; } ''', 'exception caught: std::bad_typeid') + @with_both_eh_sjlj + def test_abort_no_dtors(self): + # abort() should not run destructors + out = self.do_run(r''' +#include +#include + +struct Foo { + ~Foo() { std::cout << "Destructing Foo" << std::endl; } +}; + +int main() { + Foo f; + abort(); +} +''', assert_returncode=NON_ZERO) + self.assertNotContained('Destructing Foo', out) + def test_iostream_ctors(self): # iostream stuff must be globally constructed before user global # constructors, so iostream works in global constructors diff --git a/tools/system_libs.py b/tools/system_libs.py index 4994f21ff805..dd0d64b45e1d 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -708,7 +708,8 @@ class libcompiler_rt(MTLibrary, SjLjLibrary): 'stack_ops.S', 'stack_limits.S', 'emscripten_setjmp.c', - 'emscripten_exception_builtins.c' + 'emscripten_exception_builtins.c', + '__trap.c', ])