alexcrichton opened issue #14222:
The general fiber implementation for Wasmtime has custom integration with ASan which is necessary to avoid asan producing false positives. This is not replicated into stack switching's custom routines for swapping stacks meaning that when running stack-switching wasms with ASan it's possible to generate what I believe are false positive errors. This has come up a few times during fuzzing on OSS-Fuzz but so far hasn't been easily reproducible locally. The failure looks like:
Command: /mnt/scratch0/clusterfuzz/resources/platform/linux/unshare -c -n /mnt/scratch0/clusterfuzz/bot/builds/clusterfuzz-builds_wasmtime_9d7f296cb3c934976ab46f0ee760a3a07ef3344a/revisions/wast_tests -rss_limit_mb=2560 -timeout=60 -runs=100 /mnt/scratch0/clusterfuzz/bot/inputs/fuzzer-testcases/crash-9606210045240f6c4bfdd79464f4b9b90599f91b Time ran: 5.373565673828125 INFO: Running with entropic power schedule (0xFF, 100). INFO: Seed: 3582697355 INFO: Loaded 1 modules (1651543 inline 8-bit counters): 1651543 [0x5bb9b0c137f0, 0x5bb9b0da6b47), INFO: Loaded 1 PC tables (1651543 PCs): 1651543 [0x5bb9b0da6b48,0x5bb9b26da0b8), /mnt/scratch0/clusterfuzz/bot/builds/clusterfuzz-builds_wasmtime_9d7f296cb3c934976ab46f0ee760a3a07ef3344a/revisions/wast_tests: Running 1 inputs 100 time(s) each. Running: /mnt/scratch0/clusterfuzz/bot/inputs/fuzzer-testcases/crash-9606210045240f6c4bfdd79464f4b9b90599f91b ==252==WARNING: ASan is ignoring requested __asan_handle_no_return: stack type: default top: 0x7ffdfe090000; bottom 0x7847b599c000; size: 0x07b6486f4000 (8479480692736) False positive error reports may follow For details see https://github.com/google/sanitizers/issues/189 ================================================================= ==252==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7847b5325ab1 at pc 0x5bb9a948b7ee bp 0x7847b5325a70 sp 0x7847b5325230 WRITE of size 7 at 0x7847b5325ab1 thread T0 #0 0x5bb9a948b7ed in __asan_memcpy #1 0x5bb9aa33f43e in <core::result::Result<wasmtime::runtime::vm::stack_switching::stack::VMContinuationStack, wasmtime_internal_core::error::error::Error> as core::ops::try_trait::Try>::branch /rustc/14cae681329a63c622a6e1fbe1d30f9374bc51d8/library/core/src/result.rs:2177:16 #2 0x5bb9aa33f43e in <wasmtime::runtime::store::StoreOpaque>::allocate_continuation [wasmtime/crates/wasmtime/src/runtime/store.rs:2141](https://github.com/bytecodealliance/wasmtime/blob/6901aa7cee056f45015e84a3650dd9850865b735/crates/wasmtime/src/runtime/store.rs#L2141):21 #3 0x5bb9a9efaa44 in wasmtime::runtime::vm::stack_switching::cont_new [wasmtime/crates/wasmtime/src/runtime/vm/stack_switching.rs:325](https://github.com/bytecodealliance/wasmtime/blob/6901aa7cee056f45015e84a3650dd9850865b735/crates/wasmtime/src/runtime/vm/stack_switching.rs#L325):25 #4 0x5bb9a9efaa44 in wasmtime::runtime::vm::libcalls::cont_new [wasmtime/crates/wasmtime/src/runtime/vm/libcalls.rs:1124](https://github.com/bytecodealliance/wasmtime/blob/6901aa7cee056f45015e84a3650dd9850865b735/crates/wasmtime/src/runtime/vm/libcalls.rs#L1124):9 #5 0x5bb9a9efaa44 in wasmtime::runtime::vm::libcalls::raw::cont_new::{closure#0} [wasmtime/crates/wasmtime/src/runtime/vm/libcalls.rs:122](https://github.com/bytecodealliance/wasmtime/blob/6901aa7cee056f45015e84a3650dd9850865b735/crates/wasmtime/src/runtime/vm/libcalls.rs#L122):29 #6 0x5bb9a9efaa44 in <wasmtime::runtime::vm::instance::Instance>::enter_host_from_wasm::<core::result::Result<core::option::Option<wasmtime::runtime::vm::libcalls::AllocationSize>, wasmtime_internal_core::error::error::Error>, wasmtime::runtime::vm::libcalls::raw::cont_new::{closure#0}>::{closure#0} [wasmtime/crates/wasmtime/src/runtime/vm/instance.rs:340](https://github.com/bytecodealliance/wasmtime/blob/6901aa7cee056f45015e84a3650dd9850865b735/crates/wasmtime/src/runtime/vm/instance.rs#L340):53 #7 0x5bb9a9efaa44 in wasmtime::runtime::vm::traphandlers::catch_unwind_and_record_trap::<core::result::Result<core::option::Option<wasmtime::runtime::vm::libcalls::AllocationSize>, wasmtime_internal_core::error::error::Error>, <wasmtime::runtime::vm::instance::Instance>::enter_host_from_wasm<core::result::Result<core::option::Option<wasmtime::runtime::vm::libcalls::AllocationSize>, wasmtime_internal_core::error::error::Error>, wasmtime::runtime::vm::libcalls::raw::cont_new::{closure#0}>::{closure#0}>::{closure#0} [wasmtime/crates/wasmtime/src/runtime/vm/traphandlers.rs:136](https://github.com/bytecodealliance/wasmtime/blob/6901aa7cee056f45015e84a3650dd9850865b735/crates/wasmtime/src/runtime/vm/traphandlers.rs#L136):62 ...This particular fuzz bug was executing
tests/misc_testsuite/stack-switching/resume_throw.wast, but I've seen others generate the same fault.Unfortunately I don't have a reproduction at this time. My hunch is that a fuzz-generated module using stack switching would probably pretty quickly generate false positives like this. Until a deterministic reproducer is found, however, it'll be hard to fix this and verify it's fixed.
alexcrichton added the fuzz-bug label to Issue #14222.
alexcrichton added the wasm-proposal:stack-switching label to Issue #14222.
dhil commented on issue #14222:
I'm looking into this issue. My initial idea was to replicate the wasmtime-fiber ASan-integration. Though, there is one obstacle here which is the fact that continuation switching uses cranelift's stack switch instruction, which we cannot readily instrument. I see three paths forward:
- Enable cranelift to emit ASan hooks.
- In ASan-enabled Wasmtime builds use ASan-aware stack switching stubs instead of cranelift's stack switch instruction.
- Maintain status quo. Keep skipping stack switching tests on ASan runs.
For 1, I haven't found any precedent for ASan in the cranelift API. Thus, I think this would be a rather massive and potentially invasive change. I am also not convinced it is the right thing to do -- it seems to me that you'd generally want to keep instrumentation separable from core emission logic. If we are ardent about enabling stack switching tests with ASan, then I think option 2 is my preference. It would largely mirror what wasmtime-fiber does. The downsides are we would have to maintain some libcall stack switching primitives just for ASan builds, and it wouldn't be genuinely testing mainline stack switching as it would sidestep the cranelift stack switch instruction. Clearly, option 3 is the easiest.
Let me know your thoughts on this matter @alexcrichton.
alexcrichton commented on issue #14222:
I'll caution that I haven't thought about this too too deeply, but AFAIK this will largely boil down to invoking
__sanitizer_{start,finish}_switch_fiberat the right times with the right parameters. Cranelift probably isn't the right place for such instrumentation, and I agree that the status quo isn't viable long-term. One other possible idea though would be to manually inject instrumentation in the CLIF during translation when asan is enabled. For example we could have something inlibcalls.rswhich manages the__sanitizer_*hooks which is #[cfg]'d and such. This would mean that module compilation needs to be aware of whether the runtime uses as an, which is a new thing, but not the worst to plumb around in theory.Reading over the
mod asaninwasmtime-internal-fiberthough I'm also reminded what we do for stacks where everything is permanently allocated as a stack and never released. I'm not sure if that hack is still necessary but that'll likely also be applicable for stack-switching in the long-term too.
Last updated: Sep 20 2026 at 19:05 UTC