about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libgreen/context.rs4
-rw-r--r--src/libnative/lib.rs2
-rw-r--r--src/libnative/task.rs2
-rw-r--r--src/librustrt/stack.rs37
-rw-r--r--src/librustrt/thread.rs2
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("<main>"));
     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_os_managed_stack_bounds(stack_lo: uint, _stack_hi: uint) {
+    record_sp_limit(stack_lo + RED_ZONE);
+}
+
 #[inline(always)]
-pub unsafe fn record_stack_bounds_green(stack_lo: uint, stack_hi: uint) {
+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<proc()> = mem::transmute(main);
         (*f)();
         mem::transmute(0 as imp::rust_thread_return)