-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Fix compatibility with the Go runtime on Windows for exceptions #11892
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
Conversation
This commit fixes some fallout of bytecodealliance#11592 where that PR resulted in Wasmtime no longer running within the context of the Go runtime (e.g. `wasmtime-go`). The reasons for this are quite Windows-specific and I've attempted to document the situation in `vectored_exceptions.go`. The basic TL;DR; is that by returning from a vectored exception handler (which bytecodealliance#11592 introduced) we're now subjecting ourselves to "continue handlers" as well, and Go's continue handlers will abort the process for non-Go exceptions. Some logic is added here to try to bypass Go's continue handlers and get back to wasm.
|
I have, yet again as is the case with wasmtime-go and integrating on various platforms, lost an embarassingly large amount of time debugging this... |
crates/wasmtime/src/runtime/vm/sys/windows/vectored_exceptions.rs
Outdated
Show resolved
Hide resolved
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.
Sounds like this one was super fun to track down!
| //! # Continue Handlers | ||
| //! | ||
| //! Most of this is pretty standard, there's not quite as much subtlety here as | ||
| //! compared to Unix. One perhaps surprising part though is the use of a | ||
| //! "Vectored Continue Handler" in addition to an exception handler. Strictly | ||
| //! this is not necessary as our exception handler will return | ||
| //! `EXCEPTION_CONTINUE_EXECUTION` for handled exceptions. It's been seen in | ||
| //! runtimes such as Go, for example, that continue handlers are used to dump | ||
| //! exception information and abort the process (as opposed to using an | ||
| //! exception handler). | ||
| //! | ||
| //! Windows's behavior here seems to first execute the ordered list of vectored | ||
| //! exception handlers until one returns `EXCEPTION_CONTINUE_EXECUTION`. If this | ||
| //! list is exhausted then it seems to go to default SEH routines which abort | ||
| //! the process. If the exception is handled then the ordered list of vectored | ||
| //! continue handlers is then consulted. The first one to return | ||
| //! `EXCEPTION_CONTINUE_EXECUTION` short-circuits the rest of the list. If the | ||
| //! list is exhausted then the program resumes. | ||
| //! | ||
| //! Go's behavior here is to return `EXCEPTION_CONTINUE_EXECUTION` for all | ||
| //! Go-looking exceptions. The Go runtime has one continue handler that then | ||
| //! returns execution back to the program for what appears to be async | ||
| //! preempts/etc. Go then has a final continue handler which aborts the process | ||
| //! with an error message indicating what happened. | ||
| //! | ||
| //! Wasmtime here is orchestrated a bit differently. We have a priority | ||
| //! exception handler which will look for a wasm trap, and if found, returns | ||
| //! `EXCEPTION_CONTINUE_EXECUTION`. This means that the Go continue handlers | ||
| //! then run which eventually aborts the process, not what we want. In an | ||
| //! attempt to short-circuit this logic Wasmtime also installs a continue | ||
| //! handler to return `EXCEPTION_CONTINUE_EXECUTION` and skip as many continue | ||
| //! handlers as possible. | ||
| //! | ||
| //! To implement the continue handler in Wasmtime a thread-local variable | ||
| //! `LAST_EXCEPTION_PC` is used here which is set during the exception handler | ||
| //! and then tested during the continue handler. If it matches the current PC | ||
| //! then it's assume that Wasmtime is the one that processed the exception and | ||
| //! the `EXCEPTION_CONTINUE_EXECUTION` is returned. | ||
| //! | ||
| //! This is all... a bit... roundabout. Sorry. |
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.
The title of this section suggests that this is an overview of how continue handlers work, and then it proceeds to be a discussion about working around how the go runtime (ab)uses them. I think this comment could be a little more clear if we explicitly had a few different sections:
- An explanation of how VEH and continue handlers work and are intended to be used.
- An explanation of how the go runtime (ab)uses the system, and how this doesn't play nice / compose with other runtimes that need to install handlers, like Wasmtime.
- A description of what we are doing to work around (2).
All that said, this comment was super helpful for understanding the issues involved. Thanks for writing this stuff up!
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.
Good point! I reorganized to make it flow better like you suggested, I think I was a bit too frustrated with all of this yesterday to write clearly...
…codealliance#11892) * Fix compatibility with the Go runtime on Windows for exceptions This commit fixes some fallout of bytecodealliance#11592 where that PR resulted in Wasmtime no longer running within the context of the Go runtime (e.g. `wasmtime-go`). The reasons for this are quite Windows-specific and I've attempted to document the situation in `vectored_exceptions.go`. The basic TL;DR; is that by returning from a vectored exception handler (which bytecodealliance#11592 introduced) we're now subjecting ourselves to "continue handlers" as well, and Go's continue handlers will abort the process for non-Go exceptions. Some logic is added here to try to bypass Go's continue handlers and get back to wasm. * Fix typos * Review comments
…) (#11900) * Fix compatibility with the Go runtime on Windows for exceptions This commit fixes some fallout of #11592 where that PR resulted in Wasmtime no longer running within the context of the Go runtime (e.g. `wasmtime-go`). The reasons for this are quite Windows-specific and I've attempted to document the situation in `vectored_exceptions.go`. The basic TL;DR; is that by returning from a vectored exception handler (which #11592 introduced) we're now subjecting ourselves to "continue handlers" as well, and Go's continue handlers will abort the process for non-Go exceptions. Some logic is added here to try to bypass Go's continue handlers and get back to wasm. * Fix typos * Review comments
This commit fixes some fallout of #11592 where that PR resulted in Wasmtime no longer running within the context of the Go runtime (e.g.
wasmtime-go). The reasons for this are quite Windows-specific and I've attempted to document the situation invectored_exceptions.go. The basic TL;DR; is that by returning from a vectored exception handler (which #11592 introduced) we're now subjecting ourselves to "continue handlers" as well, and Go's continue handlers will abort the process for non-Go exceptions. Some logic is added here to try to bypass Go's continue handlers and get back to wasm.