-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use RuntimeError in abort() before module instantiation #18664
Conversation
We decided use a trap for `abort` function in case of Wasm EH in order to prevent infinite-looping (emscripten-core#16910). https://github.com/emscripten-core/emscripten/blob/44b2c2a1ecad39c534e14179acb49419dfee528b/src/preamble.js#L472-L474 The short reason is, in Wasm EH `RuntimeError` is treated as a foreign exception and caught by `catch_all`, so you try to abort the program and throw a `RuntimeError`, but it is caught by some `catch_all` used in the cleanup (=destructors, etc) code, causing the program to continue to run. `__trap` is defined in compiler-rt and exported when Wasm EH is enabled. This has worked so far, but in case we fail to instantiate a Wasm module and call `abort` because of it, we don't have access to the imported `Module['asm']['__trap']`, because `Module['asm']` has not been set: https://github.com/emscripten-core/emscripten/blob/44b2c2a1ecad39c534e14179acb49419dfee528b/src/preamble.js#L848 So the `abort` call will end like this: ```console TypeError: Cannot read properties of undefined (reading '__trap') at ___trap (/usr/local/google/home/aheejin/test/gl84/exported_api.js:5152:34) at abort (/usr/local/google/home/aheejin/test/gl84/exported_api.js:892:5) at /usr/local/google/home/aheejin/test/gl84/exported_api.js:1172:5 ``` which may not be the worst thing in the world given that we are crashing anyway, but not the situation we intended. This PR lets us throw `RuntimeError` in case we don't have the wasm module instantiated and have access to `Module['asm']['__trap']`. This is OK even with Wasm EH because we haven't been running the module, there's no risk of infinite-looping we tried to prevent in emscripten-core#16910. I'm not sure how to add a test for this, because the test would require a module that fails to instantiate. This was found while I was debugging something else.
src/preamble.js
Outdated
// Wasm EH code (because RuntimeError is considered as a foreign exception and | ||
// caught by 'catch_all'), but in case throwing RuntimeError is fine because | ||
// the module has not even been instantiated, even less running. | ||
if (typeof Module['asm'] !== 'undefined') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this check if (runtimeInitialized)
? I think that should work but I'm not sure. It's generally the right condition to check before calling into the wasm, like ___trap()
here, but maybe this place is special somehow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (runtimeInitialized)
seems to work, thanks. Didn't know that variable exited.
Do you know where the offending call to abort is coming from exactly? I'm happy to land this fix but it also seems wrong to be a calling abort if the program isn't even running yet. I'd like to look into fixing that too. |
Co-authored-by: Alon Zakai <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm but I'm also curious where the problem happens. Is it in a global ctor or other startup code?
Oh, I think it can't be the wasm module at all, because then Then I think it has to be what you said before @aheejin , that it errors during a failure to instantiate the wasm in the JS code. @sbc100 I think such a call to |
The case I was debugging was this: #18592 (comment) And the callsite involved in this case was here, in Line 848 in 30ba0ae
Actually, it is not the initialization itself that fails, even though this can happen when intitialization fails too. What fails in this example is this line: Line 818 in 30ba0ae
which transfers the control flow here: Lines 821 to 849 in 30ba0ae
which ends with the abort call.
|
Makes sense, thanks for the details @aheejin |
We decided use a trap for
abort
function in case of Wasm EH in order to prevent infinite-looping (#16910).emscripten/src/preamble.js
Lines 472 to 474 in 44b2c2a
The short reason is, in Wasm EH
RuntimeError
is treated as a foreign exception and caught bycatch_all
, so you try to abort the program and throw aRuntimeError
, but it is caught by somecatch_all
used in the cleanup (=destructors, etc) code, causing the program to continue to run.__trap
is defined in compiler-rt and exported when Wasm EH is enabled.This has worked so far, but in case we fail to instantiate a Wasm module and call
abort
because of it, we don't have access to the importedModule['asm']['__trap']
, becauseModule['asm']
has not been set:emscripten/src/preamble.js
Line 848 in 44b2c2a
And we haven't had the opportunity to run this code:
emscripten/src/preamble.js
Line 975 in 44b2c2a
So the
abort
call will end like this:which may not be the worst thing in the world given that we are crashing anyway, but not the situation we intended.
This PR lets us throw
RuntimeError
in case we don't have the wasm module instantiated and have access toModule['asm']['__trap']
. This is OK even with Wasm EH because we haven't been running the module, there's no risk of infinite-looping we tried to prevent in #16910.I'm not sure how to add a test for this, because the test would require a module that fails to instantiate. This was found while I was debugging something else.