From 881bfb1a180a1b545daa9da1539ec4c8ebda7ed1 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Tue, 5 Aug 2014 20:53:42 -0700 Subject: [PATCH] Renamed `record_stack_bounds` for clarity. For a good measure, implemented target_record_stack_bounds for 32-bit Windows as well. --- src/libgreen/context.rs | 4 ++-- src/libnative/lib.rs | 2 +- src/libnative/task.rs | 2 +- src/librustrt/stack.rs | 37 ++++++++++++++++++++++++------------- src/librustrt/thread.rs | 2 +- 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/libgreen/context.rs b/src/libgreen/context.rs index d681e53af42..b63758cdcc5 100644 --- a/src/libgreen/context.rs +++ b/src/libgreen/context.rs @@ -105,11 +105,11 @@ impl Context { // invalid for the current task. Lucky for us `rust_swap_registers` // is a C function so we don't have to worry about that! match in_context.stack_bounds { - Some((lo, hi)) => stack::record_stack_bounds_green(lo, hi), + Some((lo, hi)) => stack::record_rust_managed_stack_bounds(lo, hi), // If we're going back to one of the original contexts or // something that's possibly not a "normal task", then reset // the stack limit to 0 to make morestack never fail - None => stack::record_stack_bounds_green(0, uint::MAX), + None => stack::record_rust_managed_stack_bounds(0, uint::MAX), } rust_swap_registers(out_regs, in_regs) } diff --git a/src/libnative/lib.rs b/src/libnative/lib.rs index d358aa6b645..c7b89b6cb91 100644 --- a/src/libnative/lib.rs +++ b/src/libnative/lib.rs @@ -137,7 +137,7 @@ pub fn start(argc: int, argv: *const *const u8, main: proc()) -> int { task.name = Some(str::Slice("
")); drop(task.run(|| { unsafe { - rt::stack::record_stack_bounds(my_stack_bottom, my_stack_top); + rt::stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top); } exit_code = Some(run(main.take_unwrap())); }).destroy()); diff --git a/src/libnative/task.rs b/src/libnative/task.rs index c72d6c24a7c..55806caaf13 100644 --- a/src/libnative/task.rs +++ b/src/libnative/task.rs @@ -84,7 +84,7 @@ pub fn spawn_opts(opts: TaskOpts, f: proc():Send) { let addr = &something_around_the_top_of_the_stack as *const int; let my_stack = addr as uint; unsafe { - stack::record_stack_bounds(my_stack - stack + 1024, my_stack); + stack::record_os_managed_stack_bounds(my_stack - stack + 1024, my_stack); } let mut ops = ops; ops.stack_bounds = (my_stack - stack + 1024, my_stack); diff --git a/src/librustrt/stack.rs b/src/librustrt/stack.rs index a79f453cf1e..c941107d7e8 100644 --- a/src/librustrt/stack.rs +++ b/src/librustrt/stack.rs @@ -124,8 +124,23 @@ extern fn stack_exhausted() { } } +// Windows maintains a record of upper and lower stack bounds in the Thread Information +// Block (TIB), and some syscalls do check that addresses which are supposed to be in +// the stack, indeed lie between these two values. +// (See https://github.com/rust-lang/rust/issues/3445#issuecomment-26114839) +// +// When using Rust-managed stacks (libgreen), we must maintain these values accordingly. +// For OS-managed stacks (libnative), we let the OS manage them for us. +// +// On all other platforms both variants behave identically. + #[inline(always)] -pub unsafe fn record_stack_bounds_green(stack_lo: uint, stack_hi: uint) { +pub unsafe fn record_os_managed_stack_bounds(stack_lo: uint, _stack_hi: uint) { + record_sp_limit(stack_lo + RED_ZONE); +} + +#[inline(always)] +pub unsafe fn record_rust_managed_stack_bounds(stack_lo: uint, stack_hi: uint) { // When the old runtime had segmented stacks, it used a calculation that was // "limit + RED_ZONE + FUDGE". The red zone was for things like dynamic // symbol resolution, llvm function calls, etc. In theory this red zone @@ -138,27 +153,23 @@ pub unsafe fn record_stack_bounds_green(stack_lo: uint, stack_hi: uint) { return target_record_stack_bounds(stack_lo, stack_hi); - #[cfg(not(windows))] #[cfg(not(target_arch = "x86_64"))] #[inline(always)] + #[cfg(not(windows))] #[inline(always)] unsafe fn target_record_stack_bounds(_stack_lo: uint, _stack_hi: uint) {} + + #[cfg(windows, target_arch = "x86")] #[inline(always)] + unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) { + // stack range is at TIB: %fs:0x04 (top) and %fs:0x08 (bottom) + asm!("mov $0, %fs:0x04" :: "r"(stack_hi) :: "volatile"); + asm!("mov $0, %fs:0x08" :: "r"(stack_lo) :: "volatile"); + } #[cfg(windows, target_arch = "x86_64")] #[inline(always)] unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) { - // Windows compiles C functions which may check the stack bounds. This - // means that if we want to perform valid FFI on windows, then we need - // to ensure that the stack bounds are what they truly are for this - // task. More info can be found at: - // https://github.com/rust-lang/rust/issues/3445#issuecomment-26114839 - // // stack range is at TIB: %gs:0x08 (top) and %gs:0x10 (bottom) asm!("mov $0, %gs:0x08" :: "r"(stack_hi) :: "volatile"); asm!("mov $0, %gs:0x10" :: "r"(stack_lo) :: "volatile"); } } -#[inline(always)] -pub unsafe fn record_stack_bounds(stack_lo: uint, _stack_hi: uint) { - record_sp_limit(stack_lo + RED_ZONE); -} - /// Records the current limit of the stack as specified by `end`. /// /// This is stored in an OS-dependent location, likely inside of the thread diff --git a/src/librustrt/thread.rs b/src/librustrt/thread.rs index 7bc991cf72f..43364466dbe 100644 --- a/src/librustrt/thread.rs +++ b/src/librustrt/thread.rs @@ -44,7 +44,7 @@ static DEFAULT_STACK_SIZE: uint = 1024 * 1024; #[no_split_stack] extern fn thread_start(main: *mut libc::c_void) -> imp::rust_thread_return { unsafe { - stack::record_stack_bounds(0, uint::MAX); + stack::record_os_managed_stack_bounds(0, uint::MAX); let f: Box = mem::transmute(main); (*f)(); mem::transmute(0 as imp::rust_thread_return)