Skip to content

Conversation

@alexcrichton
Copy link
Member

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.

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.
@alexcrichton alexcrichton requested a review from a team as a code owner October 20, 2025 19:52
@alexcrichton alexcrichton requested review from fitzgen and removed request for a team October 20, 2025 19:52
@alexcrichton
Copy link
Member Author

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...

@github-actions github-actions bot added the wasmtime:api Related to the API of the `wasmtime` crate itself label Oct 20, 2025
Copy link
Member

@fitzgen fitzgen left a 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!

Comment on lines 11 to 50
//! # 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.
Copy link
Member

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:

  1. An explanation of how VEH and continue handlers work and are intended to be used.
  2. 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.
  3. 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!

Copy link
Member Author

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...

@alexcrichton alexcrichton added this pull request to the merge queue Oct 21, 2025
Merged via the queue into bytecodealliance:main with commit 44ac8d3 Oct 21, 2025
45 checks passed
@alexcrichton alexcrichton deleted the fix-go branch October 21, 2025 20:05
alexcrichton added a commit to alexcrichton/wasmtime that referenced this pull request Oct 21, 2025
…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
alexcrichton added a commit that referenced this pull request Oct 21, 2025
…) (#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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

wasmtime:api Related to the API of the `wasmtime` crate itself

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants