-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
[wasm] Block calls into managed code after a runtime assert #87043
Conversation
Tagging subscribers to 'arch-wasm': @lewing Issue DetailsRight now if an assertion is hit in native code at any point, while we call exit and flush buffers and whatnot, it's still possible to call back into managed code. This PR sets a flag when assertions are hit, and if the flag is set we reject attempts to call into managed code. The included sample's buttons let you verify that managed exceptions being thrown doesn't set the flag (since the caller can catch and handle them) but a native assert in the runtime will set it. I initially was setting the flag in response to calls to exit() as well, but then you can't call into managed code after Main returns, which isn't desirable with our current model. cc @vargaz
|
src/mono/wasm/runtime/loader/exit.ts
Outdated
@@ -6,6 +6,12 @@ import { mono_log_debug, consoleWebSocket, mono_log_error, mono_log_info_no_pref | |||
|
|||
export function abort_startup(reason: any, should_exit: boolean): void { | |||
mono_log_debug("abort_startup"); | |||
// FIXME: Should we set this after rejecting the promises? |
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.
I think this place is OK. You can remove the comment, I don't expect that somebody would try to recover from the rejections trowed here.
We also need to set runtimeExited
in mono_exit
method.
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.
Originally I was setting it in mono_exit, but it caused calls in to stop working after main(), which breaks a bunch of the samples
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.
Hmm.
We have dotnet.run()
API implemented as runMainAndExit
and I guess that's why.
It makes sense in console apps, but not so much in browser apps.
So perhaps web apps should not call runMainAndExit
but just runMain
. But that would break our (unit test) expectations about exit code of web apps.
@maraf what do you think ?
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.
I think the exit code is also important since a startup failure usually produces a nonzero exit code
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.
I think even web apps should call runMainAndExit
and after that the runtime should be in the "don't touch me state". Web apps and probably any "interactive apps" should have async main that exits when the app done.
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.
Would this be compatible with Blazor and Uno?
@jeromelaban
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.
I think Blazor has async main which never resolves the Task, right @maraf ?
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.
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.
@kg for Uno, we are using the runMain
API to start the apps to call in a synchronous entry point that exits right away. If runMainAndExit implies that apps need to have an async main, this will be a breaking change.
I tend to think that the idea of the Main
method handling exit in the browser does not make sense synchronously nor asynchronously, as terminating the app is not really possible (aside from closing the page/tab).
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.
There is Module.noExitRuntime
in the emscripten which is true in the browser. Perhaps we should set this new set_runtime_aborted
only in shell ? Or when Module.noExitRuntime == false
.
I think think that we also want to set emscripten's ABORT
flag by calling _proc_exit()
or abort()
js functions. At least on current thread.
Also we should register set_runtime_aborted
into Module.onAbort
callback.
If runtimeHelpers.runtimeExited is set, reject attempts to call managed code from JS Checkpoint: Flow message through from Environment.FailFast Ensure we stop pumping timers and background exec upon assert Store asserted state in driver.c If we set the asserted state multiple times don't trample the first message that was set Revert damaged files
4e6da6b
to
92a9e4d
Compare
@@ -125,6 +127,27 @@ function initializeExports(globalObjects: GlobalObjects): RuntimeAPI { | |||
return exportedRuntimeAPI; | |||
} | |||
|
|||
function set_runtime_aborted (module: any, reason: any) { |
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.
please move both methods to src\mono\wasm\runtime\run.ts
@@ -63,5 +69,8 @@ export function mono_wasm_schedule_timer(shortestDueTimeMs: number): void { | |||
} | |||
|
|||
function mono_wasm_schedule_timer_tick() { | |||
if (cwraps.mono_wasm_get_runtime_aborted()) |
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.
please add similar test into fatal_handler
in src\mono\wasm\runtime\loader\run.ts
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.
Loader cannot access cwraps
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.
Via runtimeHelpers same way as you did set_runtime_aborted
also with checking that it was already set
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.
I'm just saying that fatal_handler
doesn't have to try to exit if we are already aborted.
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.
Ah I see what you mean. Will do
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.
and maybe it should set abort if we are not aborted yet
// Someone may have already set an abort message or aborted the runtime. | ||
// For example, this will happen in the case of Environment.FailFast. | ||
// If we don't have a reason message of our own, see if we can get an existing one. | ||
if (!reason) |
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.
&& runtimeHelpers.get_runtime_abort_message
it may not exist yet when abort_startup
happens. Also conditional call to set_runtime_aborted
Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it. |
Right now if an assertion is hit in native code at any point, while we call exit and flush buffers and whatnot, it's still possible to call back into managed code.
This PR sets a flag when assertions are hit, and if the flag is set we reject attempts to call into managed code.
The included sample's buttons let you verify that managed exceptions being thrown doesn't set the flag (since the caller can catch and handle them) but a native assert in the runtime will set it.
I initially was setting the flag in response to calls to exit() as well, but then you can't call into managed code after Main returns, which isn't desirable with our current model.
cc @vargaz