Skip to content

Commit fbc5327

Browse files
authored
Add test for ABORT_ON_WASM_EXCEPTIONS + exception during main (#17479)
The special handling of `abortWrapperDepth` in `callMain` was previously untested. Also simplify the increamenting/decremening of `abortWrapperDepth` in `callMain`.
1 parent b241b08 commit fbc5327

8 files changed

+52
-26
lines changed

src/postamble.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ function callMain(args) {
158158

159159
#if ABORT_ON_WASM_EXCEPTIONS
160160
// See abortWrapperDepth in preamble.js!
161-
abortWrapperDepth += 2;
161+
abortWrapperDepth += 1;
162162
#endif
163163

164164
#if STANDALONE_WASM
@@ -192,7 +192,7 @@ function callMain(args) {
192192
#if ABORT_ON_WASM_EXCEPTIONS
193193
finally {
194194
// See abortWrapperDepth in preamble.js!
195-
abortWrapperDepth -= 2;
195+
abortWrapperDepth -= 1;
196196
}
197197
#endif
198198
}

src/preamble.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,6 @@ function createExportWrapper(name, fixedasm) {
564564
#endif
565565

566566
#if ABORT_ON_WASM_EXCEPTIONS
567-
// When exception catching is enabled (!DISABLE_EXCEPTION_CATCHING)
568567
// `abortWrapperDepth` counts the recursion level of the wrapper function so
569568
// that we only handle exceptions at the top level letting the exception
570569
// mechanics work uninterrupted at the inner level. Additionally,
@@ -580,13 +579,10 @@ function makeAbortWrapper(original) {
580579
throw "program has already aborted!";
581580
}
582581

583-
#if !DISABLE_EXCEPTION_CATCHING
584582
abortWrapperDepth += 1;
585-
#endif
586583
try {
587584
return original.apply(null, arguments);
588-
}
589-
catch (e) {
585+
} catch (e) {
590586
if (
591587
ABORT // rethrow exception if abort() was called in the original function call above
592588
|| abortWrapperDepth > 1 // rethrow exceptions not caught at the top level if exception catching is enabled; rethrow from exceptions from within callMain
@@ -599,12 +595,10 @@ function makeAbortWrapper(original) {
599595

600596
abort("unhandled exception: " + [e, e.stack]);
601597
}
602-
#if !DISABLE_EXCEPTION_CATCHING
603598
finally {
604599
abortWrapperDepth -= 1;
605600
}
606-
#endif
607-
}
601+
}
608602
}
609603

610604
// Instrument all the exported functions to:

src/settings.js

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1947,18 +1947,20 @@ var SEPARATE_DWARF_URL = '';
19471947
// [link]
19481948
var ERROR_ON_WASM_CHANGES_AFTER_LINK = false;
19491949

1950-
// Whether the program should abort when an unhandled WASM exception is encountered.
1951-
// This makes the Emscripten program behave more like a native program where the OS
1952-
// would terminate the process and no further code can be executed when an unhandled
1953-
// exception (e.g. out-of-bounds memory access) happens.
1950+
// Abort on unhandled excptions that occur when calling exported WebAssembly
1951+
// functions. This makes the program behave more like a native program where the
1952+
// OS would terminate the process and no further code can be executed when an
1953+
// unhandled exception (e.g. out-of-bounds memory access) happens.
19541954
// This will instrument all exported functions to catch thrown exceptions and
1955-
// call abort() when they happen. Once the program aborts any exported function calls
1956-
// will fail with a "program has already aborted" exception to prevent calls into
1957-
// code with a potentially corrupted program state.
1958-
// This adds a small fixed amount to code size in optimized builds and a slight overhead
1959-
// for the extra instrumented function indirection.
1960-
// Enable this if you want Emscripten to handle unhandled exceptions nicely at the
1961-
// cost of a few bytes extra.
1955+
// call abort() when they happen. Once the program aborts any exported function
1956+
// calls will fail with a "program has already aborted" exception to prevent
1957+
// calls into code with a potentially corrupted program state.
1958+
// This adds a small fixed amount to code size in optimized builds and a slight
1959+
// overhead for the extra instrumented function indirection. Enable this if you
1960+
// want Emscripten to handle unhandled exceptions nicely at the cost of a few
1961+
// bytes extra.
1962+
// Exceptions that occur within the `main` function are already handled via an
1963+
// alternative mechanimsm.
19621964
// [link]
19631965
var ABORT_ON_WASM_EXCEPTIONS = false;
19641966

tests/core/test_abort_on_exception.cpp renamed to tests/core/test_abort_on_exceptions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@ EMSCRIPTEN_BINDINGS(test_abort_on_exception) {
2828

2929
int main() {
3030
return 0;
31-
}
31+
}

tests/core/test_abort_on_exception.out renamed to tests/core/test_abort_on_exceptions.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
crashing
2-
true
2+
exception caught; runtime should be dead
33
again
44
program has already aborted!
55
ccall
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright 2022 The Emscripten Authors. All rights reserved.
3+
* Emscripten is available under two separate licenses, the MIT license and the
4+
* University of Illinois/NCSA Open Source License. Both these licenses can be
5+
* found in the LICENSE file.
6+
*/
7+
8+
#include <stdio.h>
9+
#include <emscripten.h>
10+
11+
EM_JS(void, throwException, (void), {
12+
throw new Error("crash");
13+
});
14+
15+
int main() {
16+
printf("crashing during main\n");
17+
throwException();
18+
return 0;
19+
}

tests/core/test_abort_on_exception_post.js renamed to tests/core/test_abort_on_exceptions_post.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ addOnPostRun(function() {
55
}
66
catch(e) {
77
// Catch the abort
8-
out(true);
8+
out("exception caught; runtime should be dead");
99
}
1010
out("again");
1111
try {

tests/test_core.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9341,8 +9341,19 @@ def test_abort_on_exceptions(self):
93419341
self.set_setting('ALLOW_TABLE_GROWTH')
93429342
self.set_setting('EXPORTED_RUNTIME_METHODS', ['ccall', 'cwrap'])
93439343
self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$addFunction'])
9344-
self.emcc_args += ['-lembind', '--post-js', test_file('core/test_abort_on_exception_post.js')]
9345-
self.do_core_test('test_abort_on_exception.cpp', interleaved_output=False)
9344+
self.emcc_args += ['-lembind', '--post-js', test_file('core/test_abort_on_exceptions_post.js')]
9345+
self.do_core_test('test_abort_on_exceptions.cpp', interleaved_output=False)
9346+
9347+
def test_abort_on_exceptions_main(self):
9348+
# The unhandled exception wrappers should not kick in for exceptions thrown during main
9349+
self.set_setting('ABORT_ON_WASM_EXCEPTIONS')
9350+
self.emcc_args.append('--minify=0')
9351+
output = self.do_runf(test_file('core/test_abort_on_exceptions_main.c'), assert_returncode=NON_ZERO)
9352+
# The exception should make it all the way out
9353+
self.assertContained('Error: crash', output)
9354+
# And not be translated into abort by makeAbortWrapper
9355+
self.assertNotContained('unhandled exception', output)
9356+
self.assertNotContained('Aborted', output)
93469357

93479358
@needs_dylink
93489359
def test_gl_main_module(self):

0 commit comments

Comments
 (0)