Skip to content

Commit ca51766

Browse files
authored
Send unhandledrejection events to the main thread (#17535)
We send uncaught exceptions to the main thread where they can be handled in a central location, but we did not previously send unhandledrejection events that are created when a promise is rejected with no handler. Add a handler in worker.js that intercepts unhandledrejection events and throws them as errors so they are propagated to the main thread in the usual manner. The way this works varies slightly between Node and the browser, so add tests for both cases.
1 parent 8cf52d8 commit ca51766

File tree

7 files changed

+47
-1
lines changed

7 files changed

+47
-1
lines changed

ChangeLog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ See docs/process.md for more on how version tagging works.
2424
emscripten (llvm, wabt, binaryen). This should not effect any users of
2525
emscripten, only developers. (#17502)
2626
- The llvm version that emscripten uses was updated to 16.0.0 (#17534)
27+
- worker.js now propagates unhandled promise rejections to the main thread the
28+
same way it propagates uncaught exceptions.
2729

2830
3.1.17 - 07/22/2022
2931
------

src/worker.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ Module['instantiateWasm'] = (info, receiveInstance) => {
105105
}
106106
#endif
107107

108+
// Turn unhandled rejected promises into errors so that the main thread will be
109+
// notified about them.
110+
self.onunhandledrejection = (e) => {
111+
throw e.reason ?? e;
112+
};
113+
108114
self.onmessage = (e) => {
109115
try {
110116
if (e.data.cmd === 'load') { // Preload command that is called once per worker to parse and load the Emscripten code.

test/common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1559,7 +1559,7 @@ def run_browser(self, html_file, expected=None, message=None, timeout=None, extr
15591559
if extra_tries > 0:
15601560
print('[test error (see below), automatically retrying]')
15611561
print(e)
1562-
return self.run_browser(html_file, message, expected, timeout, extra_tries - 1)
1562+
return self.run_browser(html_file, expected, message, timeout, extra_tries - 1)
15631563
else:
15641564
raise e
15651565
finally:
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include <emscripten/emscripten.h>
2+
3+
int main() {
4+
EM_ASM({ Promise.reject("rejected!"); });
5+
emscripten_exit_with_live_runtime();
6+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
if (!ENVIRONMENT_IS_PTHREAD) {
2+
if (ENVIRONMENT_IS_NODE) {
3+
process.on('error', (e) => {
4+
if (e === 'rejected!') {
5+
console.log('passed');
6+
}
7+
});
8+
} else {
9+
addEventListener('error', (e) => {
10+
if (e.message === 'Uncaught rejected!') {
11+
console.log('passed');
12+
}
13+
});
14+
}
15+
}

test/test_browser.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5377,6 +5377,15 @@ def test_manual_pthread_proxy_hammer(self, args):
53775377
def test_assert_failure(self):
53785378
self.btest(test_file('browser/test_assert_failure.c'), 'abort:Assertion failed: false && "this is a test"')
53795379

5380+
@no_firefox('output slightly different in FireFox')
5381+
def test_pthread_unhandledrejection(self):
5382+
# Check that an unhandled promise rejection is propagated to the main thread
5383+
# as an error. This test is failing if it hangs!
5384+
self.btest(test_file('pthread/test_pthread_unhandledrejection.c'),
5385+
args=['-pthread', '-sPROXY_TO_PTHREAD', '--post-js',
5386+
test_file('pthread/test_pthread_unhandledrejection.post.js')],
5387+
expected='exception:Uncaught [object ErrorEvent] / undefined')
5388+
53805389
def test_full_js_library_strict(self):
53815390
self.btest_exit(test_file('hello_world.c'), args=['-sINCLUDE_FULL_LIBRARY', '-sSTRICT_JS'])
53825391

test/test_core.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9081,6 +9081,14 @@ def test_pthread_exit_main_stub(self):
90819081
self.set_setting('EXIT_RUNTIME')
90829082
self.do_run_in_out_file_test('core/pthread/test_pthread_exit_main.c')
90839083

9084+
@node_pthreads
9085+
def test_pthread_unhandledrejection(self):
9086+
# Check that an unhandled promise rejection is propagated to the main thread
9087+
# as an error.
9088+
self.set_setting('PROXY_TO_PTHREAD')
9089+
self.emcc_args += ['--post-js', test_file('pthread/test_pthread_unhandledrejection.post.js')]
9090+
self.do_runf(test_file('pthread/test_pthread_unhandledrejection.c'), 'passed')
9091+
90849092
@node_pthreads
90859093
@no_wasm2js('wasm2js does not support PROXY_TO_PTHREAD (custom section support)')
90869094
def test_pthread_offset_converter(self):

0 commit comments

Comments
 (0)