From f556bd18a7461d383e8f7485b42866933dc9cb89 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Fri, 19 Mar 2021 12:50:38 -0700 Subject: [PATCH] Set the thread stack guarantee for fibers on Windows. This commit fixes the Windows implementation of fibers in Wasmtime to reserve enough staack space for Rust to handle any stack overflow exceptions. --- crates/fiber/src/windows.rs | 8 ++++++++ tests/host_segfault.rs | 26 ++++++++++++++------------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/crates/fiber/src/windows.rs b/crates/fiber/src/windows.rs index e61f11d8d3..be35ae4e15 100644 --- a/crates/fiber/src/windows.rs +++ b/crates/fiber/src/windows.rs @@ -5,6 +5,7 @@ use std::ptr; use winapi::shared::minwindef::*; use winapi::shared::winerror::ERROR_NOT_SUPPORTED; use winapi::um::fibersapi::*; +use winapi::um::processthreadsapi::SetThreadStackGuarantee; use winapi::um::winbase::*; #[derive(Debug)] @@ -49,6 +50,13 @@ unsafe extern "system" fn fiber_start(data: LPVOID) where F: FnOnce(A, &super::Suspend) -> C, { + // Set the stack guarantee to be consistent with what Rust expects for threads + // This value is taken from: + // https://github.com/rust-lang/rust/blob/0d97f7a96877a96015d70ece41ad08bb7af12377/library/std/src/sys/windows/stack_overflow.rs + if SetThreadStackGuarantee(&mut 0x5000) == 0 { + panic!("failed to set fiber stack guarantee"); + } + let state = data.cast::(); let func = Box::from_raw((*state).initial_closure.get().cast::()); (*state).initial_closure.set(ptr::null_mut()); diff --git a/tests/host_segfault.rs b/tests/host_segfault.rs index 5efa1d6f83..e725ff4303 100644 --- a/tests/host_segfault.rs +++ b/tests/host_segfault.rs @@ -29,13 +29,20 @@ fn segfault() -> ! { } } -fn overrun_the_stack() -> usize { - let mut a = [0u8; 1024]; - if a.as_mut_ptr() as usize == 1 { - return 1; - } else { - return a.as_mut_ptr() as usize + overrun_the_stack(); +fn allocate_stack_space() -> ! { + let _a = [0u8; 1024]; + + for _ in 0..100000 { + allocate_stack_space(); } + + unreachable!() +} + +fn overrun_the_stack() -> ! { + println!("{}", CONFIRM); + io::stdout().flush().unwrap(); + allocate_stack_space(); } fn run_future(future: F) -> F::Output { @@ -104,8 +111,6 @@ fn main() { let store = Store::new(&engine); let module = Module::new(&engine, "(module)").unwrap(); let _instance = Instance::new(&store, &module, &[]).unwrap(); - println!("{}", CONFIRM); - io::stdout().flush().unwrap(); overrun_the_stack(); }, true, @@ -118,6 +123,7 @@ fn main() { let module = Module::new(&engine, r#"(import "" "" (func)) (start 0)"#).unwrap(); let segfault = Func::wrap(&store, || segfault()); Instance::new(&store, &module, &[segfault.into()]).unwrap(); + unreachable!(); }, false, ), @@ -130,8 +136,6 @@ fn main() { let store = Store::new(&engine); let f = Func::wrap0_async(&store, (), |_, _| { Box::new(async { - print!("{}", CONFIRM); - io::stdout().flush().unwrap(); overrun_the_stack(); }) }); @@ -150,8 +154,6 @@ fn main() { let store = Store::new(&engine); let f = Func::wrap0_async(&store, (), |_, _| { Box::new(async { - println!("{}", CONFIRM); - io::stdout().flush().unwrap(); overrun_the_stack(); }) });