Skip to content

Commit 97b7bcc

Browse files
committed
[EH] Make abort() work with EH
We used to implement `abort()` with throwing a JS exception. emscripten-core#9730 changed it to `RuntimeError`, because it is the class a trap becomes once it hits a JS frame. But this turned out to be not working, because Wasm EH currently does not assume all `RuntimeError`s are from traps; it decides whether a `RuntimeError` is from a trap or not based on a hidden field within the object. Relevant past discussion: WebAssembly/exception-handling#89 (comment) So at the moment we don't have a way of throwing a trap from JS, which is inconvenient. I think we eventually want to make JS API for this, but for the moment, this PR resorts to a wasm function that traps. This at least makes calling `std::terminate` work. So far calling it exhausted the call stack and aborted. Fixes emscripten-core#16407.
1 parent f650912 commit 97b7bcc

File tree

5 files changed

+35
-2
lines changed

5 files changed

+35
-2
lines changed

emcc.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2566,6 +2566,9 @@ def get_full_import_name(name):
25662566
if settings.SUPPORT_LONGJMP == 'wasm':
25672567
settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.append('__c_longjmp')
25682568

2569+
if settings.EXCEPTION_HANDLING:
2570+
settings.REQUIRED_EXPORTS += ['__trap']
2571+
25692572
return target, wasm_target
25702573

25712574

src/preamble.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,12 +605,20 @@ function abort(what) {
605605
// Use a wasm runtime error, because a JS error might be seen as a foreign
606606
// exception, which means we'd run destructors on it. We need the error to
607607
// simply make the program stop.
608+
// FIXME This is not working now, because Wasm EH currently does not assume
609+
// all RuntimeErrors are from traps; it decides whether a RuntimeError is from
610+
// a trap or not based on a hidden field within the object. So at the moment
611+
// we don't have a way of throwing a trap from JS. TODO Make a JS API that
612+
// allows this.
608613

609614
// Suppress closure compiler warning here. Closure compiler's builtin extern
610615
// defintion for WebAssembly.RuntimeError claims it takes no arguments even
611616
// though it can.
612617
// TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed.
613-
618+
#if EXCEPTION_HANDLING == 1
619+
// In the meantime, we resort to wasm code for trapping.
620+
___trap();
621+
#else
614622
/** @suppress {checkTypes} */
615623
var e = new WebAssembly.RuntimeError(what);
616624

@@ -621,6 +629,7 @@ function abort(what) {
621629
// in code paths apart from instantiation where an exception is expected
622630
// to be thrown when abort is called.
623631
throw e;
632+
#endif
624633
}
625634

626635
// {{MEM_INITIALIZER}}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.globl __trap
2+
3+
__trap:
4+
.functype __trap() -> ()
5+
unreachable
6+
end_function

tests/test_core.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,6 +1639,20 @@ class Polymorphic {virtual void member(){}};
16391639
}
16401640
''', 'exception caught: std::bad_typeid')
16411641

1642+
@with_both_eh_sjlj
1643+
def test_terminate_abort(self):
1644+
# std::terminate eventually calls abort(). We used ti implement abort() with
1645+
# throwing a JS exception, but this can be again caught by std::terminate's
1646+
# cleanup and cause an infinite loop. When Wasm EH is enabled, abort() is
1647+
# implemented by a trap now.
1648+
err = self.do_run(r'''
1649+
#include <exception>
1650+
int main() {
1651+
std::terminate();
1652+
}
1653+
''', assert_returncode=NON_ZERO)
1654+
self.assertNotContained('Maximum call stack size exceeded', err)
1655+
16421656
def test_iostream_ctors(self):
16431657
# iostream stuff must be globally constructed before user global
16441658
# constructors, so iostream works in global constructors

tools/system_libs.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,8 @@ class libcompiler_rt(MTLibrary, SjLjLibrary):
708708
'stack_ops.S',
709709
'stack_limits.S',
710710
'emscripten_setjmp.c',
711-
'emscripten_exception_builtins.c'
711+
'emscripten_exception_builtins.c',
712+
'exception_builtins.S'
712713
])
713714

714715

0 commit comments

Comments
 (0)