From 6f33a260c223caadc4a7e63f072696cd01887ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Hillerstr=C3=B6m?= Date: Mon, 5 Oct 2026 15:15:07 +0100 Subject: [PATCH 1/2] [stack-switching] Fix ASan-host interop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes an issue with stack-switching on ASan-enabled builds where resuming continuations from a different host-to-Wasm invocation causes a panic. Because each host invocation creates a fresh initial stack information, it would inadvertently discard the previous stack bounds on a suspended continuation, leaving it without the `asan_stack_bottom` information. The fix is to extend the ASan stack-switch handshake with both source and target `VMCommonStackInformation` pointers: 1. Before switching, the start hook receives `(source_csi, target_csi)`. 2. It supplies the target's known bounds to `__sanitizer_start_switch_fiber`. 3. It temporarily records the source CSI in a thread-local in-flight slot. 4. Immediately after switching, the finish hook obtains the previous stack’s bounds from `__sanitizer_finish_switch_fiber`. 5. It stores those bounds in the recorded source CSI and clears the in-flight slot. prtest:full --- .../stack_switching/instructions.rs | 39 ++++--- crates/environ/src/builtin.rs | 7 +- crates/wasmtime/src/runtime/vm/libcalls.rs | 9 +- .../src/runtime/vm/stack_switching/asan.rs | 109 +++++++++++++----- .../stack-switching/issue14508.wast | 28 +++++ 5 files changed, 151 insertions(+), 41 deletions(-) create mode 100644 tests/misc_testsuite/stack-switching/issue14508.wast diff --git a/crates/cranelift/src/func_environ/stack_switching/instructions.rs b/crates/cranelift/src/func_environ/stack_switching/instructions.rs index b1f50c0d9d92..e088b1bddfc9 100644 --- a/crates/cranelift/src/func_environ/stack_switching/instructions.rs +++ b/crates/cranelift/src/func_environ/stack_switching/instructions.rs @@ -30,10 +30,10 @@ fn emit_stack_switch<'a>( store_context_ptr: ir::Value, load_context_ptr: ir::Value, payload: ir::Value, - asan_target_csi: impl FnOnce( + asan_stack_information: impl FnOnce( &mut crate::func_environ::FuncEnvironment<'a>, &mut FunctionBuilder, - ) -> ir::Value, + ) -> (ir::Value, ir::Value), ) -> ir::Value { if !env.compiler.tunables().asan_stack_switching { return builder @@ -42,9 +42,9 @@ fn emit_stack_switch<'a>( } // ASan-aware stack switching. - // The `asan_target_csi` is provided as a function to lazily load - // the necessary ASan bookkeeping. - let target_csi = asan_target_csi(env, builder); + // The stack information is provided as a function to lazily load the + // necessary ASan bookkeeping. + let (source_csi, target_csi) = asan_stack_information(env, builder); let pointer_type = env.pointer_type(); let slot = env.get_or_create_asan_fake_stack_slot(builder); let fake_stack_save = builder.ins().stack_addr(pointer_type, slot, 0); @@ -60,7 +60,7 @@ fn emit_stack_switch<'a>( ); builder.ins().call( asan_start_switch_fiber, - &[vmctx, fake_stack_save, target_csi], + &[vmctx, fake_stack_save, source_csi, target_csi], ); let result = builder @@ -1914,7 +1914,12 @@ fn translate_resume_impl<'a>( control_context_ptr, control_context_ptr, resume_payload, - |env, builder| last_ancestor.common_stack_information(env, builder).address, + |env, builder| { + ( + parent_csi.address, + last_ancestor.common_stack_information(env, builder).address, + ) + }, ); // At this point we know nothing about the continuation that just @@ -2234,9 +2239,12 @@ pub(crate) fn translate_suspend<'a>( control_context_ptr, suspend_payload, |env, builder| { - handler_stack_chain - .get_common_stack_information(env, builder) - .address + ( + active_contref_csi.address, + handler_stack_chain + .get_common_stack_information(env, builder) + .address, + ) }, ); @@ -2511,9 +2519,14 @@ pub(crate) fn translate_switch<'a>( tmp_control_context, switch_payload, |env, builder| { - switchee_contref_last_ancestor - .common_stack_information(env, builder) - .address + ( + switcher_contref + .common_stack_information(env, builder) + .address, + switchee_contref_last_ancestor + .common_stack_information(env, builder) + .address, + ) }, ) }; diff --git a/crates/environ/src/builtin.rs b/crates/environ/src/builtin.rs index 7d214e6988bb..2403db6e8508 100644 --- a/crates/environ/src/builtin.rs +++ b/crates/environ/src/builtin.rs @@ -191,7 +191,12 @@ macro_rules! foreach_builtin_function { // Helpers used around stack switch instructions in // ASan-instrumented builds. #[cfg(feature = "stack-switching")] - asan_start_switch_fiber(vmctx: vmctx, fake_stack_save: pointer, target_csi: pointer); + asan_start_switch_fiber( + vmctx: vmctx, + fake_stack_save: pointer, + source_csi: pointer, + target_csi: pointer + ); #[cfg(feature = "stack-switching")] asan_finish_switch_fiber(vmctx: vmctx, fake_stack: pointer); } diff --git a/crates/wasmtime/src/runtime/vm/libcalls.rs b/crates/wasmtime/src/runtime/vm/libcalls.rs index 9caf42d7ae4a..9bc8b9688d0f 100644 --- a/crates/wasmtime/src/runtime/vm/libcalls.rs +++ b/crates/wasmtime/src/runtime/vm/libcalls.rs @@ -1195,9 +1195,16 @@ unsafe fn asan_start_switch_fiber( _store: &mut dyn VMStore, _instance: InstanceId, fake_stack_save: *mut u8, + source_csi: *mut u8, target_csi: *mut u8, ) { - unsafe { crate::vm::stack_switching::asan::start_switch_fiber(fake_stack_save, target_csi) } + unsafe { + crate::vm::stack_switching::asan::start_switch_fiber( + fake_stack_save, + source_csi, + target_csi, + ) + } } #[cfg(feature = "stack-switching")] diff --git a/crates/wasmtime/src/runtime/vm/stack_switching/asan.rs b/crates/wasmtime/src/runtime/vm/stack_switching/asan.rs index 84318cce7aaa..ef6099155c8a 100644 --- a/crates/wasmtime/src/runtime/vm/stack_switching/asan.rs +++ b/crates/wasmtime/src/runtime/vm/stack_switching/asan.rs @@ -7,19 +7,26 @@ //! ```text //! stack A stack B //! ------- ------- -//! start_switch_fiber(&save_a, B's bounds) +//! start_switch_fiber(&save_a, A's CSI, B's bounds) //! stack_switch(A -> B) ----------------------> resumes //! finish_switch_fiber(save_b) +//! records A's bounds //! ... runs on B ... -//! start_switch_fiber(&save_b, A's bounds) +//! start_switch_fiber( +//! &save_b, +//! B's CSI, +//! A's bounds) //! resumes <----------------------------------- stack_switch(B -> A) //! finish_switch_fiber(save_a) +//! records B's bounds //! ``` //! //! Here `save_a` and `save_b` are stack slots in the generated Wasm //! frames. The `start_switch_fiber` writes an opaque ASan fake-stack //! token into the slot belonging to the stack being suspended. This -//! token is exclusively for ASan bookkeeping. +//! token is exclusively for ASan bookkeeping. We separately remember +//! the suspended stack's `VMCommonStackInformation` until the matching +//! `finish_switch_fiber`, which reports that stack's bounds. //! //! A fresh continuation has no suspended generated frame at which to //! execute the right-hand `finish_switch_fiber`. Its entry trampoline @@ -32,8 +39,16 @@ mod enabled { use crate::vm::{VMCommonStackInformation, VMContRef, VMStackChain, VmPtr}; + use core::cell::Cell; use core::ptr::NonNull; + std::thread_local! { + /// The stack whose bounds ASan will report at the next matching + /// `__sanitizer_finish_switch_fiber` call. + static PENDING_SOURCE_CSI: Cell<*mut VMCommonStackInformation> = + const { Cell::new(core::ptr::null_mut()) }; + } + unsafe fn continuation_from_args(args: *mut crate::vm::VMHostArray) -> *mut VMContRef { unsafe { args.cast::() @@ -61,44 +76,79 @@ mod enabled { (bottom.as_ptr(), csi.asan_stack_size) } + #[cfg_attr(asan, sanitize(address = "off"))] + unsafe fn begin_switch( + fake_stack_save: Option<&mut *mut u8>, + bottom: *const u8, + size: usize, + source_csi: *mut VMCommonStackInformation, + ) { + assert!(!source_csi.is_null()); + PENDING_SOURCE_CSI.with(|pending| { + let previous = pending.replace(source_csi); + assert!( + previous.is_null(), + "ASan stack-switch handshakes must not overlap" + ); + }); + unsafe { __sanitizer_start_switch_fiber(fake_stack_save, bottom, size) }; + } + + #[cfg_attr(asan, sanitize(address = "off"))] + unsafe fn finish_switch(fake_stack: *mut u8) { + unsafe { + let mut bottom = core::ptr::null(); + let mut size = 0; + __sanitizer_finish_switch_fiber(fake_stack, &mut bottom, &mut size); + + let source_csi = PENDING_SOURCE_CSI.with(|pending| { + let source_csi = pending.get(); + pending.set(core::ptr::null_mut()); + source_csi + }); + let source_csi = &mut *NonNull::new(source_csi) + .expect("ASan stack-switch completion requires a source stack") + .as_ptr(); + source_csi.asan_stack_bottom = Some(VmPtr::from( + NonNull::new(bottom.cast_mut()) + .expect("ASan must report the previous stack's bounds"), + )); + source_csi.asan_stack_size = size; + } + } + /// Begins ASan's stack-switch handshake. /// /// `fake_stack_save` points to storage in the generated Wasm frame /// that survives until this same stack is resumed. - pub unsafe extern "C" fn start_switch_fiber(fake_stack_save: *mut u8, target_csi: *mut u8) { + pub unsafe extern "C" fn start_switch_fiber( + fake_stack_save: *mut u8, + source_csi: *mut u8, + target_csi: *mut u8, + ) { unsafe { let (bottom, size) = stack_range(target_csi.cast()); - __sanitizer_start_switch_fiber(Some(&mut *fake_stack_save.cast()), bottom, size); + begin_switch( + Some(&mut *fake_stack_save.cast()), + bottom, + size, + source_csi.cast(), + ); } } /// Completes ASan's stack-switch handshake after this stack is /// resumed. pub unsafe extern "C" fn finish_switch_fiber(fake_stack: *mut u8) { - unsafe { - let mut bottom = core::ptr::null(); - let mut size = 0; - __sanitizer_finish_switch_fiber(fake_stack, &mut bottom, &mut size); - } + unsafe { finish_switch(fake_stack) } } /// Completes the first switch onto a newly-created continuation stack /// and records the parent stack's bounds. #[cfg_attr(asan, sanitize(address = "off"))] #[cfg(all(feature = "stack-switching"))] - pub unsafe fn fiber_start_complete(args: *mut crate::vm::VMHostArray) { - unsafe { - let mut bottom = core::ptr::null(); - let mut size = 0; - __sanitizer_finish_switch_fiber(core::ptr::null_mut(), &mut bottom, &mut size); - - let parent = &mut *parent_csi(continuation_from_args(args)); - parent.asan_stack_bottom = Some(VmPtr::from( - NonNull::new(bottom.cast_mut()) - .expect("ASan must report the previous stack's bounds"), - )); - parent.asan_stack_size = size; - } + pub unsafe fn fiber_start_complete(_args: *mut crate::vm::VMHostArray) { + unsafe { finish_switch(core::ptr::null_mut()) } } /// Begins a non-returning switch from a completed or trapped @@ -107,9 +157,11 @@ mod enabled { #[cfg(all(feature = "stack-switching"))] pub unsafe extern "C" fn fiber_exit(args: *mut crate::vm::VMHostArray) { unsafe { - let parent = parent_csi(continuation_from_args(args)); + let contref = continuation_from_args(args); + let parent = parent_csi(contref); let (bottom, size) = stack_range(parent); - __sanitizer_start_switch_fiber(None, bottom, size); + let source = core::ptr::addr_of_mut!((*contref).common_stack_information); + begin_switch(None, bottom, size, source); } } @@ -130,7 +182,12 @@ mod enabled { #[cfg(not(asan))] mod disabled { #[allow(dead_code, reason = "Used by ASan builds")] - pub unsafe extern "C" fn start_switch_fiber(_fake_stack_save: *mut u8, _target_csi: *mut u8) {} + pub unsafe extern "C" fn start_switch_fiber( + _fake_stack_save: *mut u8, + _source_csi: *mut u8, + _target_csi: *mut u8, + ) { + } /// Completes ASan's stack-switch handshake after this stack is /// resumed. diff --git a/tests/misc_testsuite/stack-switching/issue14508.wast b/tests/misc_testsuite/stack-switching/issue14508.wast new file mode 100644 index 000000000000..90d10b0288ca --- /dev/null +++ b/tests/misc_testsuite/stack-switching/issue14508.wast @@ -0,0 +1,28 @@ +;;! stack_switching = true +;;! function_references = true +;;! bulk_memory = true + +;; Sourced from https://github.com/bytecodealliance/wasmtime/issues/14508 +(module + (type $ft (func)) + (type $ct (cont $ft)) + (tag $t) + (global $k (mut (ref null $ct)) (ref.null $ct)) + + (func $body (suspend $t) (suspend $t)) + (elem declare func $body) + + (func (export "first") + (block $h (result (ref $ct)) + (resume $ct (on $t $h) (cont.new $ct (ref.func $body))) + (unreachable)) + (global.set $k)) + + (func (export "second") + (block $h (result (ref $ct)) + (resume $ct (on $t $h) (global.get $k)) + (unreachable)) + (global.set $k)) +) +(invoke "first") +(invoke "second") From 8ece7901a42ce310e13a19b1e572ca571610ac1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Hillerstr=C3=B6m?= Date: Wed, 7 Oct 2026 11:39:32 +0100 Subject: [PATCH 2/2] Consolidate ASan-related fields for stack switching into a bespoke structure. This commit also removes the `PENDING_CSI` global, which was used to communicate bookkeeping information between ASan stack switches. This change does inflate the `VMCommonStackInformation` and by extension `VMContRef` objects. However, I think this space can subsequently be reclaimed selecting a zero-size no-op implementation of the structure in non-ASan builds (requires changing direct field accessor to be indirect via function calls). I will look into this in a future PR. prtest:full --- crates/cranelift/src/alias_region.rs | 5 + .../stack_switching/instructions.rs | 12 ++- crates/environ/src/builtin.rs | 2 +- crates/environ/src/vmoffsets.rs | 6 ++ crates/environ/src/vmtypes.rs | 41 +++++--- crates/wasmtime/src/runtime/store.rs | 4 +- crates/wasmtime/src/runtime/vm/libcalls.rs | 3 +- .../src/runtime/vm/stack_switching.rs | 6 +- .../src/runtime/vm/stack_switching/asan.rs | 94 ++++++++++--------- .../resume-suspend-data-passing.wat | 64 ++++++------- .../disas/stack-switching/resume-suspend.wat | 60 ++++++------ .../stack-switching/symmetric-switch.wat | 80 ++++++++-------- 12 files changed, 206 insertions(+), 171 deletions(-) diff --git a/crates/cranelift/src/alias_region.rs b/crates/cranelift/src/alias_region.rs index a6022b2c36f1..456da99c6cac 100644 --- a/crates/cranelift/src/alias_region.rs +++ b/crates/cranelift/src/alias_region.rs @@ -85,6 +85,11 @@ enum VmType { VMGcHeader, VMDrcHeader, VMCopyingHeader, + #[allow( + dead_code, + reason = "generated uniformly for all VM types via `for_each_vm_type!`" + )] + VMAsanStackSupport, } /// A key that uniquely identifies an alias region across an entire compilation. diff --git a/crates/cranelift/src/func_environ/stack_switching/instructions.rs b/crates/cranelift/src/func_environ/stack_switching/instructions.rs index e088b1bddfc9..27ec7185e08f 100644 --- a/crates/cranelift/src/func_environ/stack_switching/instructions.rs +++ b/crates/cranelift/src/func_environ/stack_switching/instructions.rs @@ -42,8 +42,8 @@ fn emit_stack_switch<'a>( } // ASan-aware stack switching. - // The stack information is provided as a function to lazily load the - // necessary ASan bookkeeping. + // The `asan_target_csi` is provided as a function to lazily load + // the necessary ASan bookkeeping. let (source_csi, target_csi) = asan_stack_information(env, builder); let pointer_type = env.pointer_type(); let slot = env.get_or_create_asan_fake_stack_slot(builder); @@ -74,7 +74,7 @@ fn emit_stack_switch<'a>( ); builder .ins() - .call(asan_finish_switch_fiber, &[vmctx, fake_stack]); + .call(asan_finish_switch_fiber, &[vmctx, fake_stack, source_csi]); result } @@ -2240,7 +2240,9 @@ pub(crate) fn translate_suspend<'a>( suspend_payload, |env, builder| { ( - active_contref_csi.address, + end_of_chain_contref + .common_stack_information(env, builder) + .address, handler_stack_chain .get_common_stack_information(env, builder) .address, @@ -2520,7 +2522,7 @@ pub(crate) fn translate_switch<'a>( switch_payload, |env, builder| { ( - switcher_contref + switcher_contref_last_ancestor .common_stack_information(env, builder) .address, switchee_contref_last_ancestor diff --git a/crates/environ/src/builtin.rs b/crates/environ/src/builtin.rs index 2403db6e8508..bc4e2f5554da 100644 --- a/crates/environ/src/builtin.rs +++ b/crates/environ/src/builtin.rs @@ -198,7 +198,7 @@ macro_rules! foreach_builtin_function { target_csi: pointer ); #[cfg(feature = "stack-switching")] - asan_finish_switch_fiber(vmctx: vmctx, fake_stack: pointer); + asan_finish_switch_fiber(vmctx: vmctx, fake_stack: pointer, current_csi: pointer); } }; } diff --git a/crates/environ/src/vmoffsets.rs b/crates/environ/src/vmoffsets.rs index 511436017b24..9ab53ba1a01f 100644 --- a/crates/environ/src/vmoffsets.rs +++ b/crates/environ/src/vmoffsets.rs @@ -71,6 +71,9 @@ macro_rules! define_vm_type_offsets { (@size ($p:expr) VMStackLimits) => { u32::from(($p).vm_stack_limits().size()) }; (@size ($p:expr) VMHostArray) => { u32::from(($p).vm_host_array().size()) }; (@size ($p:expr) VMPayloads) => { u32::from(($p).vm_payloads().size()) }; + (@size ($p:expr) VMAsanStackSupport) => { + u32::from(($p).vm_asan_stack_support().size()) + }; (@size ($p:expr) VMCommonStackInformation) => { u32::from(($p).vm_common_stack_information().size()) }; @@ -117,6 +120,9 @@ macro_rules! define_vm_type_offsets { (@align ($p:expr) VMStackLimits) => { u32::from(($p).vm_stack_limits().align()) }; (@align ($p:expr) VMHostArray) => { u32::from(($p).vm_host_array().align()) }; (@align ($p:expr) VMPayloads) => { u32::from(($p).vm_payloads().align()) }; + (@align ($p:expr) VMAsanStackSupport) => { + u32::from(($p).vm_asan_stack_support().align()) + }; (@align ($p:expr) VMCommonStackInformation) => { u32::from(($p).vm_common_stack_information().align()) }; diff --git a/crates/environ/src/vmtypes.rs b/crates/environ/src/vmtypes.rs index 19ba87fb120a..fbd9d31b0192 100644 --- a/crates/environ/src/vmtypes.rs +++ b/crates/environ/src/vmtypes.rs @@ -617,6 +617,28 @@ macro_rules! for_each_vm_type { pub gc_ref_data: Option>, } + /// AddressSanitizer bookkeeping associated with a stack. + #[derive(Debug, Clone, Default)] + #[repr(C)] + #[snake_name = vm_asan_stack_support] + pub struct VMAsanStackSupport { + /// Bottom of the usable stack range reported to ASan, + /// or `None` until ASan discovers an initial stack's + /// bounds. Technically only needed by the runtime, + /// but we are using `VmPtr` here to avoid introducing + /// macro rules for `*mut u8` just for the sake of ASan + /// builds. + pub stack_bottom: Option>, + + /// Size of the usable stack range reported to ASan. + pub stack_size: usize, + + /// The stack whose bounds ASan will report when the next + /// stack-switch handshake is completed on this stack. + /// `None` when no handshake is pending. + pub pending_source_csi: Option>, + } + /// The information saved for every stack, whether it is a /// continuation's or the initial stack's. #[derive(Debug, Clone)] @@ -638,16 +660,9 @@ macro_rules! for_each_vm_type { /// The index within `handlers` of the first `switch` handler. pub first_switch_handler_index: u32, - /// Bottom of the usable stack range reported to ASan, - /// or `None` until ASan discovers an initial stack's - /// bounds. Technically only needed by the runtime, - /// but we are using `VmPtr` here to avoid introducing - /// macro rules for `*mut u8` just for the sake of ASan - /// builds. - pub asan_stack_bottom: Option>, - - /// Size of the usable stack range reported to ASan. - pub asan_stack_size: usize, + /// AddressSanitizer bookkeeping for this stack. + #[aggregate] + pub asan: VMAsanStackSupport, } /// A continuation. @@ -663,13 +678,13 @@ macro_rules! for_each_vm_type { #[aggregate] pub parent_chain: VMStackChain, + /// Revision counter. + pub revision: usize, + /// The end of this continuation's parent chain while it is /// `Suspended` or `Fresh`, and `None` while it is running. pub last_ancestor: Option>, - /// Revision counter. - pub revision: usize, - /// The stack this continuation runs on. #[aggregate] pub stack: VMContinuationStack, diff --git a/crates/wasmtime/src/runtime/store.rs b/crates/wasmtime/src/runtime/store.rs index 294c3281a1d4..573679983d41 100644 --- a/crates/wasmtime/src/runtime/store.rs +++ b/crates/wasmtime/src/runtime/store.rs @@ -2166,11 +2166,11 @@ at https://bytecodealliance.org/security. let asan_range = stack .asan_range() .expect("supported continuation stacks have a usable range"); - continuation.common_stack_information.asan_stack_bottom = Some(vm::VmPtr::from( + continuation.common_stack_information.asan.stack_bottom = Some(vm::VmPtr::from( NonNull::new(asan_range.start as *mut u8) .expect("a continuation stack's ASan range must have a non-null bottom"), )); - continuation.common_stack_information.asan_stack_size = asan_range.len(); + continuation.common_stack_information.asan.stack_size = asan_range.len(); } continuation.stack = stack; let ptr = continuation.deref_mut() as *mut VMContRef; diff --git a/crates/wasmtime/src/runtime/vm/libcalls.rs b/crates/wasmtime/src/runtime/vm/libcalls.rs index 9bc8b9688d0f..e8bc4529cddf 100644 --- a/crates/wasmtime/src/runtime/vm/libcalls.rs +++ b/crates/wasmtime/src/runtime/vm/libcalls.rs @@ -1212,8 +1212,9 @@ unsafe fn asan_finish_switch_fiber( _store: &mut dyn VMStore, _instance: InstanceId, fake_stack: *mut u8, + current_csi: *mut u8, ) { - unsafe { crate::vm::stack_switching::asan::finish_switch_fiber(fake_stack) } + unsafe { crate::vm::stack_switching::asan::finish_switch_fiber(fake_stack, current_csi) } } #[cfg(feature = "gc")] diff --git a/crates/wasmtime/src/runtime/vm/stack_switching.rs b/crates/wasmtime/src/runtime/vm/stack_switching.rs index a029b977f087..235af7d75ae0 100644 --- a/crates/wasmtime/src/runtime/vm/stack_switching.rs +++ b/crates/wasmtime/src/runtime/vm/stack_switching.rs @@ -90,8 +90,7 @@ impl VMCommonStackInformation { state: VMStackState::Running, handlers: VMHostArray::empty(), first_switch_handler_index: 0, - asan_stack_bottom: None, - asan_stack_size: 0, + asan: Default::default(), } } } @@ -158,8 +157,7 @@ impl VMContRef { state, handlers, first_switch_handler_index: 0, - asan_stack_bottom: None, - asan_stack_size: 0, + asan: Default::default(), }; let parent_chain = VMStackChain::Absent; let last_ancestor = None; diff --git a/crates/wasmtime/src/runtime/vm/stack_switching/asan.rs b/crates/wasmtime/src/runtime/vm/stack_switching/asan.rs index ef6099155c8a..8a52c5f705f2 100644 --- a/crates/wasmtime/src/runtime/vm/stack_switching/asan.rs +++ b/crates/wasmtime/src/runtime/vm/stack_switching/asan.rs @@ -7,26 +7,27 @@ //! ```text //! stack A stack B //! ------- ------- -//! start_switch_fiber(&save_a, A's CSI, B's bounds) +//! start_switch_fiber(&save_a, A's CSI, B's CSI) +//! B.CSI.asan.pending_source_csi = A's CSI //! stack_switch(A -> B) ----------------------> resumes -//! finish_switch_fiber(save_b) +//! finish_switch_fiber(save_b, B's CSI) +//! source = take(B.CSI.asan.pending_source_csi) //! records A's bounds //! ... runs on B ... -//! start_switch_fiber( -//! &save_b, -//! B's CSI, -//! A's bounds) +//! start_switch_fiber(&save_b, B's CSI, A's CSI) +//! A.CSI.asan.pending_source_csi = B's CSI //! resumes <----------------------------------- stack_switch(B -> A) -//! finish_switch_fiber(save_a) +//! finish_switch_fiber(save_a, A's CSI) +//! source = take(A.CSI.asan.pending_source_csi) //! records B's bounds //! ``` //! //! Here `save_a` and `save_b` are stack slots in the generated Wasm //! frames. The `start_switch_fiber` writes an opaque ASan fake-stack //! token into the slot belonging to the stack being suspended. This -//! token is exclusively for ASan bookkeeping. We separately remember -//! the suspended stack's `VMCommonStackInformation` until the matching -//! `finish_switch_fiber`, which reports that stack's bounds. +//! token is exclusively for ASan bookkeeping. The target stack's +//! `VMCommonStackInformation` separately remembers the source stack +//! until the matching `finish_switch_fiber` reports its bounds. //! //! A fresh continuation has no suspended generated frame at which to //! execute the right-hand `finish_switch_fiber`. Its entry trampoline @@ -39,16 +40,8 @@ mod enabled { use crate::vm::{VMCommonStackInformation, VMContRef, VMStackChain, VmPtr}; - use core::cell::Cell; use core::ptr::NonNull; - std::thread_local! { - /// The stack whose bounds ASan will report at the next matching - /// `__sanitizer_finish_switch_fiber` call. - static PENDING_SOURCE_CSI: Cell<*mut VMCommonStackInformation> = - const { Cell::new(core::ptr::null_mut()) }; - } - unsafe fn continuation_from_args(args: *mut crate::vm::VMHostArray) -> *mut VMContRef { unsafe { args.cast::() @@ -71,9 +64,10 @@ mod enabled { unsafe fn stack_range(csi: *const VMCommonStackInformation) -> (*const u8, usize) { let csi = unsafe { &*csi }; let bottom = csi - .asan_stack_bottom + .asan + .stack_bottom .expect("ASan requires the destination stack's bounds"); - (bottom.as_ptr(), csi.asan_stack_size) + (bottom.as_ptr(), csi.asan.stack_size) } #[cfg_attr(asan, sanitize(address = "off"))] @@ -82,38 +76,47 @@ mod enabled { bottom: *const u8, size: usize, source_csi: *mut VMCommonStackInformation, + target_csi: *mut VMCommonStackInformation, ) { - assert!(!source_csi.is_null()); - PENDING_SOURCE_CSI.with(|pending| { - let previous = pending.replace(source_csi); + unsafe { + let source_csi = + NonNull::new(source_csi).expect("ASan stack-switch start requires a source stack"); + let target_csi = &mut *NonNull::new(target_csi) + .expect("ASan stack-switch start requires a target stack") + .as_ptr(); + let previous = target_csi + .asan + .pending_source_csi + .replace(VmPtr::from(source_csi)); assert!( - previous.is_null(), - "ASan stack-switch handshakes must not overlap" + previous.is_none(), + "target stack already has a pending ASan stack-switch handshake" ); - }); - unsafe { __sanitizer_start_switch_fiber(fake_stack_save, bottom, size) }; + __sanitizer_start_switch_fiber(fake_stack_save, bottom, size); + } } #[cfg_attr(asan, sanitize(address = "off"))] - unsafe fn finish_switch(fake_stack: *mut u8) { + unsafe fn finish_switch(fake_stack: *mut u8, current_csi: *mut VMCommonStackInformation) { unsafe { let mut bottom = core::ptr::null(); let mut size = 0; __sanitizer_finish_switch_fiber(fake_stack, &mut bottom, &mut size); - let source_csi = PENDING_SOURCE_CSI.with(|pending| { - let source_csi = pending.get(); - pending.set(core::ptr::null_mut()); - source_csi - }); - let source_csi = &mut *NonNull::new(source_csi) - .expect("ASan stack-switch completion requires a source stack") + let current_csi = &mut *NonNull::new(current_csi) + .expect("ASan stack-switch completion requires the current stack") .as_ptr(); - source_csi.asan_stack_bottom = Some(VmPtr::from( + let source_csi = current_csi + .asan + .pending_source_csi + .take() + .expect("ASan stack-switch completion requires a source stack"); + let source_csi = &mut *source_csi.as_ptr(); + source_csi.asan.stack_bottom = Some(VmPtr::from( NonNull::new(bottom.cast_mut()) .expect("ASan must report the previous stack's bounds"), )); - source_csi.asan_stack_size = size; + source_csi.asan.stack_size = size; } } @@ -133,22 +136,27 @@ mod enabled { bottom, size, source_csi.cast(), + target_csi.cast(), ); } } /// Completes ASan's stack-switch handshake after this stack is /// resumed. - pub unsafe extern "C" fn finish_switch_fiber(fake_stack: *mut u8) { - unsafe { finish_switch(fake_stack) } + pub unsafe extern "C" fn finish_switch_fiber(fake_stack: *mut u8, current_csi: *mut u8) { + unsafe { finish_switch(fake_stack, current_csi.cast()) } } /// Completes the first switch onto a newly-created continuation stack /// and records the parent stack's bounds. #[cfg_attr(asan, sanitize(address = "off"))] #[cfg(all(feature = "stack-switching"))] - pub unsafe fn fiber_start_complete(_args: *mut crate::vm::VMHostArray) { - unsafe { finish_switch(core::ptr::null_mut()) } + pub unsafe fn fiber_start_complete(args: *mut crate::vm::VMHostArray) { + unsafe { + let contref = continuation_from_args(args); + let current = core::ptr::addr_of_mut!((*contref).common_stack_information); + finish_switch(core::ptr::null_mut(), current); + } } /// Begins a non-returning switch from a completed or trapped @@ -161,7 +169,7 @@ mod enabled { let parent = parent_csi(contref); let (bottom, size) = stack_range(parent); let source = core::ptr::addr_of_mut!((*contref).common_stack_information); - begin_switch(None, bottom, size, source); + begin_switch(None, bottom, size, source, parent); } } @@ -192,7 +200,7 @@ mod disabled { /// Completes ASan's stack-switch handshake after this stack is /// resumed. #[allow(dead_code, reason = "Used by ASan builds")] - pub unsafe extern "C" fn finish_switch_fiber(_fake_stack: *mut u8) {} + pub unsafe extern "C" fn finish_switch_fiber(_fake_stack: *mut u8, _current_csi: *mut u8) {} } #[cfg(not(asan))] diff --git a/tests/disas/stack-switching/resume-suspend-data-passing.wat b/tests/disas/stack-switching/resume-suspend-data-passing.wat index 230cc2e0e25f..b7d82b9cef37 100644 --- a/tests/disas/stack-switching/resume-suspend-data-passing.wat +++ b/tests/disas/stack-switching/resume-suspend-data-passing.wat @@ -42,15 +42,15 @@ ;; region0 = 123 "" ;; region1 = 160 "" ;; region2 = 106 "" -;; region3 = 153 "" +;; region3 = 206 "" ;; region4 = 214 "" ;; region5 = 13 "" ;; region6 = 55 "" -;; region7 = 211 "" +;; region7 = 26 "" ;; region8 = 118 "" ;; region9 = 82 "" ;; region10 = 255 "" -;; region11 = 26 "" +;; region11 = 221 "" ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly can_move region0 gv0+8 ;; gv2 = load.i64 notrap aligned region1 gv1+24 @@ -61,10 +61,10 @@ ;; block0(v0: i64, v1: i64): ;; @003c v3 = iconst.i32 10 ;; @0044 v7 = load.i64 notrap aligned readonly can_move region0 v0+8 -;; @0044 v31 = iconst.i64 160 +;; @0044 v31 = iconst.i64 168 ;; @0044 v34 = stack_addr.i64 ss0 ;; @0044 v37 = iconst.i64 0 -;; @0044 v47 = iconst.i64 112 +;; @0044 v47 = iconst.i64 120 ;; @0044 v50 = iconst.i64 -24 ;; v77 = iconst.i64 0x0002_0000_0000 ;; @0044 v43 = iconst.i64 32 @@ -86,8 +86,8 @@ ;; @0044 jump block5 ;; ;; block5: -;; @0044 v14 = load.i64 notrap aligned region3 v11+80 -;; @0044 v15 = load.i64 notrap aligned region3 v11+88 +;; @0044 v14 = load.i64 notrap aligned region3 v11+88 +;; @0044 v15 = load.i64 notrap aligned region3 v11+96 ;; v82 = iconst.i64 40 ;; v83 = iadd v15, v82 ; v82 = 40 ;; @0044 v18 = load.i64 notrap aligned region4 v83+8 @@ -116,10 +116,10 @@ ;; @0044 brif v88, block8, block6(v90) ;; ;; block8: -;; @0044 store.i64 notrap aligned region7 v11, v9+96 +;; @0044 store.i64 notrap aligned region7 v11, v9+112 ;; v91 = iconst.i32 1 -;; v92 = iconst.i64 160 -;; v93 = iadd.i64 v9, v92 ; v92 = 160 +;; v92 = iconst.i64 168 +;; v93 = iadd.i64 v9, v92 ; v92 = 168 ;; @0044 store notrap aligned region8 v91, v93+4 ; v91 = 1 ;; @0044 store.i64 notrap aligned region4 v34, v93+8 ;; @0044 store.i32 notrap aligned region6 v4, v34 @@ -127,10 +127,10 @@ ;; v94 = iconst.i32 3 ;; @0044 store notrap aligned region10 v94, v9+32 ; v94 = 3 ;; v95 = iconst.i64 0 -;; @0044 store notrap aligned region3 v95, v11+80 ; v95 = 0 ;; @0044 store notrap aligned region3 v95, v11+88 ; v95 = 0 -;; v96 = iconst.i64 112 -;; v97 = iadd.i64 v11, v96 ; v96 = 112 +;; @0044 store notrap aligned region3 v95, v11+96 ; v95 = 0 +;; v96 = iconst.i64 120 +;; v97 = iadd.i64 v11, v96 ; v96 = 120 ;; @0044 v49 = load.i64 notrap aligned region11 v97 ;; v98 = iconst.i64 -24 ;; v99 = iadd v49, v98 ; v98 = -24 @@ -183,9 +183,9 @@ ;; region0 = 123 "" ;; region1 = 160 "" ;; region2 = 28 "" -;; region3 = 211 "" +;; region3 = 26 "" ;; region4 = 106 "" -;; region5 = 153 "" +;; region5 = 206 "" ;; region6 = 255 "" ;; region7 = 231 "" ;; region8 = 243 "" @@ -198,7 +198,7 @@ ;; region15 = 214 "" ;; region16 = 55 "" ;; region17 = 82 "" -;; region18 = 26 "" +;; region18 = 221 "" ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly can_move region0 gv0+8 ;; gv2 = load.i64 notrap aligned region1 gv1+24 @@ -231,12 +231,12 @@ ;; @0062 v52 = stack_addr.i64 ss0 ;; @0062 v53 = iconst.i64 48 ;; @0062 v54 = iadd v0, v53 ; v53 = 48 -;; @0062 v61 = iconst.i64 112 +;; @0062 v61 = iconst.i64 120 ;; @0062 v64 = iconst.i64 -24 ;; v143 = iconst.i64 0x0001_0000_0000 ;; @0062 v59 = iconst.i64 32 ;; @0062 v77 = iconst.i64 4 -;; @0062 v119 = iconst.i64 160 +;; @0062 v119 = iconst.i64 168 ;; @005c jump block2(v14) ;; ;; block2(v15: i128): @@ -254,13 +254,13 @@ ;; v148 = iconst.i64 1 ;; v149 = iadd v21, v148 ; v148 = 1 ;; @0062 store notrap aligned region2 v149, v16+104 -;; @0062 v25 = load.i64 notrap aligned region3 v16+96 +;; @0062 v25 = load.i64 notrap aligned region3 v16+112 ;; @0062 v27 = load.i64 notrap aligned region4 v26+88 ;; @0062 v28 = load.i64 notrap aligned region4 v26+96 -;; @0062 store notrap aligned region5 v27, v25+80 -;; @0062 store notrap aligned region5 v28, v25+88 +;; @0062 store notrap aligned region5 v27, v25+88 +;; @0062 store notrap aligned region5 v28, v25+96 ;; v150 = iconst.i64 0 -;; @0062 store notrap aligned region3 v150, v16+96 ; v150 = 0 +;; @0062 store notrap aligned region3 v150, v16+112 ; v150 = 0 ;; v151 = iconst.i64 2 ;; @0062 store notrap aligned region4 v151, v26+88 ; v151 = 2 ;; @0062 store notrap aligned region4 v16, v26+96 @@ -292,8 +292,8 @@ ;; @0062 store notrap aligned region16 v156, v52 ;; @0062 store notrap aligned region17 v152, v155 ; v152 = 1 ;; @0062 store notrap aligned region12 v152, v28+56 ; v152 = 1 -;; v157 = iconst.i64 112 -;; v158 = iadd v25, v157 ; v157 = 112 +;; v157 = iconst.i64 120 +;; v158 = iadd v25, v157 ; v157 = 120 ;; @0062 v63 = load.i64 notrap aligned region18 v158 ;; v159 = iconst.i64 -24 ;; v160 = iadd v63, v159 ; v159 = -24 @@ -330,14 +330,14 @@ ;; @0062 v87 = load.i64 notrap aligned region12 v28+24 ;; @0062 store notrap aligned region9 v87, v26+80 ;; v174 = iconst.i32 0 -;; v175 = iconst.i64 136 -;; v176 = iadd.i64 v69, v175 ; v175 = 136 +;; v175 = iconst.i64 144 +;; v176 = iadd.i64 v69, v175 ; v175 = 144 ;; @0062 store notrap aligned region17 v174, v176 ; v174 = 0 ;; @0062 store notrap aligned region14 v174, v176+4 ; v174 = 0 ;; v177 = iconst.i64 0 ;; @0062 store notrap aligned region15 v177, v176+8 ; v177 = 0 -;; v178 = iconst.i64 160 -;; v179 = iadd.i64 v69, v178 ; v178 = 160 +;; v178 = iconst.i64 168 +;; v179 = iadd.i64 v69, v178 ; v178 = 168 ;; @0062 store notrap aligned region17 v174, v179 ; v174 = 0 ;; @0062 store notrap aligned region14 v174, v179+4 ; v174 = 0 ;; @0062 store notrap aligned region15 v177, v179+8 ; v177 = 0 @@ -368,8 +368,8 @@ ;; @0062 trap user12 ;; ;; block13: -;; v169 = iconst.i64 160 -;; v170 = iadd.i64 v69, v169 ; v169 = 160 +;; v169 = iconst.i64 168 +;; v170 = iadd.i64 v69, v169 ; v169 = 168 ;; @0062 v121 = load.i64 notrap aligned region15 v170+8 ;; @0062 v122 = load.i32 notrap aligned region16 v121 ;; v171 = iconst.i32 0 @@ -391,8 +391,8 @@ ;; @0062 store notrap aligned region9 v129, v26+80 ;; @0062 v132 = iconst.i32 4 ;; @0062 store notrap aligned region6 v132, v69+32 ; v132 = 4 -;; @0062 v133 = iconst.i64 136 -;; @0062 v134 = iadd.i64 v69, v133 ; v133 = 136 +;; @0062 v133 = iconst.i64 144 +;; @0062 v134 = iadd.i64 v69, v133 ; v133 = 144 ;; @0062 v135 = load.i64 notrap aligned region15 v134+8 ;; v163 = iconst.i32 0 ;; @0062 store notrap aligned region17 v163, v134 ; v163 = 0 diff --git a/tests/disas/stack-switching/resume-suspend.wat b/tests/disas/stack-switching/resume-suspend.wat index c00d4a95f8de..7713591d7fff 100644 --- a/tests/disas/stack-switching/resume-suspend.wat +++ b/tests/disas/stack-switching/resume-suspend.wat @@ -27,14 +27,14 @@ ;; region0 = 123 "" ;; region1 = 160 "" ;; region2 = 106 "" -;; region3 = 153 "" +;; region3 = 206 "" ;; region4 = 214 "" ;; region5 = 13 "" ;; region6 = 55 "" -;; region7 = 211 "" +;; region7 = 26 "" ;; region8 = 118 "" ;; region9 = 255 "" -;; region10 = 26 "" +;; region10 = 221 "" ;; region11 = 82 "" ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly can_move region0 gv0+8 @@ -59,8 +59,8 @@ ;; @003b jump block3 ;; ;; block3: -;; @003b v11 = load.i64 notrap aligned region3 v8+80 -;; @003b v12 = load.i64 notrap aligned region3 v8+88 +;; @003b v11 = load.i64 notrap aligned region3 v8+88 +;; @003b v12 = load.i64 notrap aligned region3 v8+96 ;; v73 = iconst.i64 40 ;; v74 = iadd v12, v73 ; v73 = 40 ;; @003b v15 = load.i64 notrap aligned region4 v74+8 @@ -89,20 +89,20 @@ ;; @003b brif v79, block6, block4(v81) ;; ;; block6: -;; @003b store.i64 notrap aligned region7 v8, v6+96 +;; @003b store.i64 notrap aligned region7 v8, v6+112 ;; v82 = iconst.i32 1 -;; @003b v28 = iconst.i64 160 -;; @003b v29 = iadd.i64 v6, v28 ; v28 = 160 +;; @003b v28 = iconst.i64 168 +;; @003b v29 = iadd.i64 v6, v28 ; v28 = 168 ;; @003b store notrap aligned region8 v82, v29+4 ; v82 = 1 ;; @003b v31 = stack_addr.i64 ss0 ;; @003b store notrap aligned region4 v31, v29+8 ;; v83 = iconst.i32 3 ;; @003b store notrap aligned region9 v83, v6+32 ; v83 = 3 ;; @003b v32 = iconst.i64 0 -;; @003b store notrap aligned region3 v32, v8+80 ; v32 = 0 ;; @003b store notrap aligned region3 v32, v8+88 ; v32 = 0 -;; @003b v42 = iconst.i64 112 -;; @003b v43 = iadd.i64 v8, v42 ; v42 = 112 +;; @003b store notrap aligned region3 v32, v8+96 ; v32 = 0 +;; @003b v42 = iconst.i64 120 +;; @003b v43 = iadd.i64 v8, v42 ; v42 = 120 ;; @003b v44 = load.i64 notrap aligned region10 v43 ;; @003b v45 = iconst.i64 -24 ;; @003b v46 = iadd v44, v45 ; v45 = -24 @@ -117,7 +117,7 @@ ;; @003b brif v51, block8, block9 ;; ;; block8 cold: -;; v87 = iadd.i64 v6, v28 ; v28 = 160 +;; v87 = iadd.i64 v6, v28 ; v28 = 168 ;; @003b v54 = load.i64 notrap aligned region4 v87+8 ;; @003b v55 = load.i32 notrap aligned region6 v54 ;; v88 = iconst.i32 0 @@ -131,7 +131,7 @@ ;; @003b trap user12 ;; ;; block9: -;; v84 = iadd.i64 v6, v28 ; v28 = 160 +;; v84 = iadd.i64 v6, v28 ; v28 = 168 ;; @003b v61 = load.i64 notrap aligned region4 v84+8 ;; v85 = iconst.i32 0 ;; @003b store notrap aligned region11 v85, v84 ; v85 = 0 @@ -149,9 +149,9 @@ ;; region0 = 123 "" ;; region1 = 160 "" ;; region2 = 28 "" -;; region3 = 211 "" +;; region3 = 26 "" ;; region4 = 106 "" -;; region5 = 153 "" +;; region5 = 206 "" ;; region6 = 255 "" ;; region7 = 231 "" ;; region8 = 243 "" @@ -164,7 +164,7 @@ ;; region15 = 214 "" ;; region16 = 55 "" ;; region17 = 82 "" -;; region18 = 26 "" +;; region18 = 221 "" ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly can_move region0 gv0+8 ;; gv2 = load.i64 notrap aligned region1 gv1+24 @@ -201,14 +201,14 @@ ;; @004e v29 = iconst.i64 1 ;; @004e v30 = iadd v27, v29 ; v29 = 1 ;; @004e store notrap aligned region2 v30, v158+104 -;; @004e v31 = load.i64 notrap aligned region3 v158+96 +;; @004e v31 = load.i64 notrap aligned region3 v158+112 ;; @004e v32 = load.i64 notrap aligned readonly can_move region0 v0+8 ;; @004e v33 = load.i64 notrap aligned region4 v32+88 ;; @004e v34 = load.i64 notrap aligned region4 v32+96 -;; @004e store notrap aligned region5 v33, v31+80 -;; @004e store notrap aligned region5 v34, v31+88 +;; @004e store notrap aligned region5 v33, v31+88 +;; @004e store notrap aligned region5 v34, v31+96 ;; @0040 v2 = iconst.i64 0 -;; @004e store notrap aligned region3 v2, v158+96 ; v2 = 0 +;; @004e store notrap aligned region3 v2, v158+112 ; v2 = 0 ;; @004e v36 = iconst.i64 2 ;; @004e store notrap aligned region4 v36, v32+88 ; v36 = 2 ;; @004e store notrap aligned region4 v158, v32+96 @@ -242,8 +242,8 @@ ;; @004e store notrap aligned region16 v60, v58 ;; @004e store notrap aligned region17 v40, v56 ; v40 = 1 ;; @004e store notrap aligned region12 v40, v34+56 ; v40 = 1 -;; @004e v67 = iconst.i64 112 -;; @004e v68 = iadd v31, v67 ; v67 = 112 +;; @004e v67 = iconst.i64 120 +;; @004e v68 = iadd v31, v67 ; v67 = 120 ;; @004e v69 = load.i64 notrap aligned region18 v68 ;; @004e v70 = iconst.i64 -24 ;; @004e v71 = iadd v69, v70 ; v70 = -24 @@ -280,14 +280,14 @@ ;; @004e v93 = load.i64 notrap aligned region12 v34+24 ;; @004e store notrap aligned region9 v93, v32+80 ;; v174 = iconst.i32 0 -;; v175 = iconst.i64 136 -;; v176 = iadd.i64 v75, v175 ; v175 = 136 +;; v175 = iconst.i64 144 +;; v176 = iadd.i64 v75, v175 ; v175 = 144 ;; @004e store notrap aligned region17 v174, v176 ; v174 = 0 ;; @004e store notrap aligned region14 v174, v176+4 ; v174 = 0 ;; v177 = iconst.i64 0 ;; @004e store notrap aligned region15 v177, v176+8 ; v177 = 0 -;; v178 = iconst.i64 160 -;; v179 = iadd.i64 v75, v178 ; v178 = 160 +;; v178 = iconst.i64 168 +;; v179 = iadd.i64 v75, v178 ; v178 = 168 ;; @004e store notrap aligned region17 v174, v179 ; v174 = 0 ;; @004e store notrap aligned region14 v174, v179+4 ; v174 = 0 ;; @004e store notrap aligned region15 v177, v179+8 ; v177 = 0 @@ -318,8 +318,8 @@ ;; @004e trap user12 ;; ;; block11: -;; @004e v125 = iconst.i64 160 -;; @004e v126 = iadd.i64 v75, v125 ; v125 = 160 +;; @004e v125 = iconst.i64 168 +;; @004e v126 = iadd.i64 v75, v125 ; v125 = 168 ;; @004e v127 = load.i64 notrap aligned region15 v126+8 ;; v171 = iconst.i32 0 ;; @004e store notrap aligned region17 v171, v126 ; v171 = 0 @@ -345,8 +345,8 @@ ;; @004e store notrap aligned region9 v134, v32+80 ;; @004e v137 = iconst.i32 4 ;; @004e store notrap aligned region6 v137, v75+32 ; v137 = 4 -;; @004e v138 = iconst.i64 136 -;; @004e v139 = iadd.i64 v75, v138 ; v138 = 136 +;; @004e v138 = iconst.i64 144 +;; @004e v139 = iadd.i64 v75, v138 ; v138 = 144 ;; @004e v140 = load.i64 notrap aligned region15 v139+8 ;; v166 = iconst.i32 0 ;; @004e store notrap aligned region17 v166, v139 ; v166 = 0 diff --git a/tests/disas/stack-switching/symmetric-switch.wat b/tests/disas/stack-switching/symmetric-switch.wat index e457e5514d5a..7085d0649a2f 100644 --- a/tests/disas/stack-switching/symmetric-switch.wat +++ b/tests/disas/stack-switching/symmetric-switch.wat @@ -32,12 +32,12 @@ ;; region1 = 160 "" ;; region2 = 28 "" ;; region3 = 106 "" -;; region4 = 153 "" +;; region4 = 206 "" ;; region5 = 214 "" ;; region6 = 13 "" ;; region7 = 82 "" ;; region8 = 55 "" -;; region9 = 211 "" +;; region9 = 26 "" ;; region10 = 118 "" ;; region11 = 255 "" ;; region12 = 231 "" @@ -46,7 +46,7 @@ ;; region15 = 23 "" ;; region16 = 224 "" ;; region17 = 179 "" -;; region18 = 26 "" +;; region18 = 221 "" ;; region19 = 187 "" ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly can_move region0 gv0+8 @@ -99,8 +99,8 @@ ;; @003e brif v32, block7, block3 ;; ;; block3: -;; @003e v33 = load.i64 notrap aligned region4 v30+80 -;; @003e v34 = load.i64 notrap aligned region4 v30+88 +;; @003e v33 = load.i64 notrap aligned region4 v30+88 +;; @003e v34 = load.i64 notrap aligned region4 v30+96 ;; @003e v35 = iconst.i64 40 ;; @003e v36 = iadd v34, v35 ; v35 = 40 ;; @003e v37 = load.i64 notrap aligned region5 v36+8 @@ -127,9 +127,9 @@ ;; @003e trap user22 ;; ;; block6: -;; @003e store.i64 notrap aligned region9 v30, v28+96 -;; @003e v50 = iconst.i64 160 -;; @003e v51 = iadd.i64 v28, v50 ; v50 = 160 +;; @003e store.i64 notrap aligned region9 v30, v28+112 +;; @003e v50 = iconst.i64 168 +;; @003e v51 = iadd.i64 v28, v50 ; v50 = 168 ;; @003e v52 = iconst.i32 1 ;; @003e v53 = stack_addr.i64 ss0 ;; @003e store notrap aligned region10 v52, v51+4 ; v52 = 1 @@ -140,8 +140,8 @@ ;; @003e store notrap aligned region11 v56, v55+32 ; v56 = 3 ;; @003e v57 = iconst.i64 0 ;; @003e v58 = iconst.i64 0 -;; @003e store notrap aligned region4 v57, v30+80 ; v57 = 0 -;; @003e store notrap aligned region4 v58, v30+88 ; v58 = 0 +;; @003e store notrap aligned region4 v57, v30+88 ; v57 = 0 +;; @003e store notrap aligned region4 v58, v30+96 ; v58 = 0 ;; @003e v59 = load.i64 notrap aligned readonly can_move region0 v0+8 ;; @003e v60 = iconst.i64 0 ;; @003e v61 = iadd v55, v60 ; v60 = 0 @@ -166,8 +166,8 @@ ;; @003e brif v77, block9, block8 ;; ;; block8: -;; @003e v78 = iconst.i64 136 -;; @003e v79 = iadd.i64 v15, v78 ; v78 = 136 +;; @003e v78 = iconst.i64 144 +;; @003e v79 = iadd.i64 v15, v78 ; v78 = 144 ;; @003e v80 = load.i64 notrap aligned region5 v79+8 ;; @003e v81 = load.i32 notrap aligned region7 v79 ;; @003e v82 = load.i32 notrap aligned region10 v79+4 @@ -185,8 +185,8 @@ ;; @003e jump block10(v91) ;; ;; block9: -;; @003e v92 = iconst.i64 160 -;; @003e v93 = iadd.i64 v15, v92 ; v92 = 160 +;; @003e v92 = iconst.i64 168 +;; @003e v93 = iadd.i64 v15, v92 ; v92 = 168 ;; @003e v94 = load.i64 notrap aligned region5 v93+8 ;; @003e v95 = load.i32 notrap aligned region7 v93 ;; @003e v96 = load.i32 notrap aligned region10 v93+4 @@ -209,9 +209,9 @@ ;; @003e v107 = iadd.i64 v15, v106 ; v106 = 0 ;; @003e v108 = iconst.i32 1 ;; @003e store notrap aligned region11 v108, v107+32 ; v108 = 1 -;; @003e v109 = load.i64 notrap aligned region9 v15+96 -;; @003e store.i64 notrap aligned region4 v33, v109+80 -;; @003e store.i64 notrap aligned region4 v34, v109+88 +;; @003e v109 = load.i64 notrap aligned region9 v15+112 +;; @003e store.i64 notrap aligned region4 v33, v109+88 +;; @003e store.i64 notrap aligned region4 v34, v109+96 ;; @003e v110 = iconst.i64 2 ;; @003e v111 = load.i64 notrap aligned readonly can_move region0 v0+8 ;; @003e store notrap aligned region3 v110, v111+88 ; v110 = 2 @@ -226,13 +226,13 @@ ;; @003e store notrap aligned region13 v116, v59+64 ;; @003e v117 = load.i64 notrap aligned region6 v113+24 ;; @003e store notrap aligned region14 v117, v59+80 -;; @003e v118 = iconst.i64 112 -;; @003e v119 = iadd.i64 v30, v118 ; v118 = 112 +;; @003e v118 = iconst.i64 120 +;; @003e v119 = iadd.i64 v30, v118 ; v118 = 120 ;; @003e v120 = load.i64 notrap aligned region18 v119 ;; @003e v121 = iconst.i64 -24 ;; @003e v122 = iadd v120, v121 ; v121 = -24 -;; @003e v123 = iconst.i64 112 -;; @003e v124 = iadd v109, v123 ; v123 = 112 +;; @003e v123 = iconst.i64 120 +;; @003e v124 = iadd v109, v123 ; v123 = 120 ;; @003e v125 = load.i64 notrap aligned region18 v124 ;; @003e v126 = iconst.i64 -24 ;; @003e v127 = iadd v125, v126 ; v126 = -24 @@ -260,8 +260,8 @@ ;; @003e brif v142, block11, block12 ;; ;; block11 cold: -;; @003e v143 = iconst.i64 160 -;; @003e v144 = iadd.i64 v28, v143 ; v143 = 160 +;; @003e v143 = iconst.i64 168 +;; @003e v144 = iadd.i64 v28, v143 ; v143 = 168 ;; @003e v145 = load.i64 notrap aligned region5 v144+8 ;; @003e v146 = load.i32 notrap aligned region8 v145 ;; @003e v147 = iconst.i32 0 @@ -276,8 +276,8 @@ ;; @003e trap user12 ;; ;; block12: -;; @003e v150 = iconst.i64 160 -;; @003e v151 = iadd.i64 v28, v150 ; v150 = 160 +;; @003e v150 = iconst.i64 168 +;; @003e v151 = iadd.i64 v28, v150 ; v150 = 168 ;; @003e v152 = load.i64 notrap aligned region5 v151+8 ;; @003e v153 = iconst.i32 0 ;; @003e store notrap aligned region7 v153, v151 ; v153 = 0 @@ -311,9 +311,9 @@ ;; region0 = 123 "" ;; region1 = 160 "" ;; region2 = 28 "" -;; region3 = 211 "" +;; region3 = 26 "" ;; region4 = 106 "" -;; region5 = 153 "" +;; region5 = 206 "" ;; region6 = 255 "" ;; region7 = 231 "" ;; region8 = 243 "" @@ -326,7 +326,7 @@ ;; region15 = 214 "" ;; region16 = 55 "" ;; region17 = 82 "" -;; region18 = 26 "" +;; region18 = 221 "" ;; gv0 = vmctx ;; gv1 = load.i64 notrap aligned readonly can_move region0 gv0+8 ;; gv2 = load.i64 notrap aligned region1 gv1+24 @@ -368,14 +368,14 @@ ;; @004b v22 = iconst.i64 1 ;; @004b v23 = iadd v20, v22 ; v22 = 1 ;; @004b store notrap aligned region2 v23, v15+104 -;; @004b v24 = load.i64 notrap aligned region3 v15+96 +;; @004b v24 = load.i64 notrap aligned region3 v15+112 ;; @004b v25 = load.i64 notrap aligned readonly can_move region0 v0+8 ;; @004b v26 = load.i64 notrap aligned region4 v25+88 ;; @004b v27 = load.i64 notrap aligned region4 v25+96 -;; @004b store notrap aligned region5 v26, v24+80 -;; @004b store notrap aligned region5 v27, v24+88 +;; @004b store notrap aligned region5 v26, v24+88 +;; @004b store notrap aligned region5 v27, v24+96 ;; @004b v28 = iconst.i64 0 -;; @004b store notrap aligned region3 v28, v15+96 ; v28 = 0 +;; @004b store notrap aligned region3 v28, v15+112 ; v28 = 0 ;; @004b v29 = iconst.i64 2 ;; @004b v30 = load.i64 notrap aligned readonly can_move region0 v0+8 ;; @004b store notrap aligned region4 v29, v30+88 ; v29 = 2 @@ -424,8 +424,8 @@ ;; @004b v57 = iconst.i64 1 ;; @004b v58 = iconst.i64 32 ;; @004b v59 = ishl v57, v58 ; v57 = 1, v58 = 32 -;; @004b v60 = iconst.i64 112 -;; @004b v61 = iadd v24, v60 ; v60 = 112 +;; @004b v60 = iconst.i64 120 +;; @004b v61 = iadd v24, v60 ; v60 = 120 ;; @004b v62 = load.i64 notrap aligned region18 v61 ;; @004b v63 = iconst.i64 -24 ;; @004b v64 = iadd v62, v63 ; v63 = -24 @@ -469,16 +469,16 @@ ;; @004b store notrap aligned region8 v85, v35+64 ;; @004b v86 = load.i64 notrap aligned region12 v82+24 ;; @004b store notrap aligned region9 v86, v35+80 -;; @004b v87 = iconst.i64 136 -;; @004b v88 = iadd.i64 v68, v87 ; v87 = 136 +;; @004b v87 = iconst.i64 144 +;; @004b v88 = iadd.i64 v68, v87 ; v87 = 144 ;; @004b v89 = iconst.i32 0 ;; @004b store notrap aligned region17 v89, v88 ; v89 = 0 ;; @004b v90 = iconst.i32 0 ;; @004b store notrap aligned region14 v90, v88+4 ; v90 = 0 ;; @004b v91 = iconst.i64 0 ;; @004b store notrap aligned region15 v91, v88+8 ; v91 = 0 -;; @004b v92 = iconst.i64 160 -;; @004b v93 = iadd.i64 v68, v92 ; v92 = 160 +;; @004b v92 = iconst.i64 168 +;; @004b v93 = iadd.i64 v68, v92 ; v92 = 168 ;; @004b v94 = iconst.i32 0 ;; @004b store notrap aligned region17 v94, v93 ; v94 = 0 ;; @004b v95 = iconst.i32 0 @@ -542,8 +542,8 @@ ;; @004b v125 = iadd.i64 v68, v124 ; v124 = 0 ;; @004b v126 = iconst.i32 4 ;; @004b store notrap aligned region6 v126, v125+32 ; v126 = 4 -;; @004b v127 = iconst.i64 136 -;; @004b v128 = iadd.i64 v68, v127 ; v127 = 136 +;; @004b v127 = iconst.i64 144 +;; @004b v128 = iadd.i64 v68, v127 ; v127 = 144 ;; @004b v129 = load.i64 notrap aligned region15 v128+8 ;; @004b v130 = iconst.i32 0 ;; @004b store notrap aligned region17 v130, v128 ; v130 = 0