Description
Spinning out the discussion from here and today's Cranelift meeting. The question is should Wasmtime be using C-unwind
in more locations?
Current state of the world that this could apply to:
- When Wasmtime calls
setjmp
the shim usesextern "C"
. - After calling
setjmp
Wasmtime makes its way to here (through exclusively Wasmtime-defined code) with this definition ofVMArrayCallNative
which usesextern "C"
- Signal handlers are defined as
extern "C"
but will calllongjmp
- Windows vectored exception handlers are defined as
extern "system"
and calllongjmp
- The
raise
libcall transitively invokeslongjmp
here but the entrypoint forraise
is defined here withextern "C"
- The upcoming unwinder uses
extern "C"
for__cranelift_throw
, and this is presumably the same pattern we'll use in Wasmtime.
Rust defines foreign unwinding here, specifically:
Unwinding with the wrong ABI is undefined behavior:
- Causing an unwind into Rust code from a foreign function that was called via a function declaration or pointer declared with a non-unwinding ABI, such as "C", "system", etc. (For example, this case occurs when such a function written in C++ throws an exception that is uncaught and propagates to Rust.)
If "causing an unwind" includes longjmp and custom Cranelift-defined unwinds then every single location listed above is UB. @bjorn3 mentioned this shouldn't work at all on Windows right now, but something must work on Windows insofar that tests are passing, and we didn't bottom it out in the Cranelift meeting what was going on.
In short, extern "C"
guarantees that there's a aborting landing pad to catch unwinds, and we're guaranteed to skip it in all of the above cases as longjmp
doesn't run this landing pad (nor does Cranelift-based unwinding). With extern "C-unwind"
, however, it's still the case that longjmp
and Cranelift don't run Rust landing pads which is still UB if they exist (in theory).
In essence I'm not sure how best to proceed here. At the end of the day at a functional level we want a guarantee that when we longjmp
in Wasmtime there's no Rust destructors on the stack, but even if that is the case (as we think it is today) it's still not clear whether this is all UB and needs to change one way or another. Will changing to C-unwind
fix things? Do we need to use inline assembly stubs or similar more aggressively?