about summary refs log tree commit diff
path: root/src/libstd/sys/unix/stack_overflow.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/sys/unix/stack_overflow.rs')
-rw-r--r--src/libstd/sys/unix/stack_overflow.rs81
1 files changed, 50 insertions, 31 deletions
diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs
index fc49f4257be..a868abbb731 100644
--- a/src/libstd/sys/unix/stack_overflow.rs
+++ b/src/libstd/sys/unix/stack_overflow.rs
@@ -7,6 +7,7 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
+
 #![cfg_attr(test, allow(dead_code))]
 
 use libc;
@@ -38,6 +39,7 @@ impl Drop for Handler {
           target_os = "bitrig",
           target_os = "dragonfly",
           target_os = "freebsd",
+          target_os = "solaris",
           all(target_os = "netbsd", not(target_vendor = "rumprun")),
           target_os = "openbsd"))]
 mod imp {
@@ -82,16 +84,19 @@ mod imp {
     // were originally supposed to do.
     //
     // This handler currently exists purely to print an informative message
-    // whenever a thread overflows its stack. When run the handler always
-    // un-registers itself after running and then returns (to allow the original
-    // signal to be delivered again). By returning we're ensuring that segfaults
-    // do indeed look like segfaults.
+    // whenever a thread overflows its stack. We then abort to exit and
+    // indicate a crash, but to avoid a misleading SIGSEGV that might lead
+    // users to believe that unsafe code has accessed an invalid pointer; the
+    // SIGSEGV encountered when overflowing the stack is expected and
+    // well-defined.
     //
-    // Returning from this kind of signal handler is technically not defined to
-    // work when reading the POSIX spec strictly, but in practice it turns out
-    // many large systems and all implementations allow returning from a signal
-    // handler to work. For a more detailed explanation see the comments on
-    // #26458.
+    // If this is not a stack overflow, the handler un-registers itself and
+    // then returns (to allow the original signal to be delivered again).
+    // Returning from this kind of signal handler is technically not defined
+    // to work when reading the POSIX spec strictly, but in practice it turns
+    // out many large systems and all implementations allow returning from a
+    // signal handler to work. For a more detailed explanation see the
+    // comments on #26458.
     unsafe extern fn signal_handler(signum: libc::c_int,
                                     info: *mut libc::siginfo_t,
                                     _data: *mut libc::c_void) {
@@ -101,17 +106,18 @@ mod imp {
         let addr = siginfo_si_addr(info);
 
         // If the faulting address is within the guard page, then we print a
-        // message saying so.
+        // message saying so and abort.
         if guard != 0 && guard - PAGE_SIZE <= addr && addr < guard {
             report_overflow();
+            rtabort!("stack overflow");
+        } else {
+            // Unregister ourselves by reverting back to the default behavior.
+            let mut action: sigaction = mem::zeroed();
+            action.sa_sigaction = SIG_DFL;
+            sigaction(signum, &action, ptr::null_mut());
+
+            // See comment above for why this function returns.
         }
-
-        // Unregister ourselves by reverting back to the default behavior.
-        let mut action: sigaction = mem::zeroed();
-        action.sa_sigaction = SIG_DFL;
-        sigaction(signum, &action, ptr::null_mut());
-
-        // See comment above for why this function returns.
     }
 
     static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();
@@ -134,26 +140,38 @@ mod imp {
         Handler { _data: MAIN_ALTSTACK };
     }
 
-    pub unsafe fn make_handler() -> Handler {
-        let alt_stack = mmap(ptr::null_mut(),
-                             SIGSTKSZ,
-                             PROT_READ | PROT_WRITE,
-                             MAP_PRIVATE | MAP_ANON,
-                             -1,
-                             0);
-        if alt_stack == MAP_FAILED {
+    unsafe fn get_stackp() -> *mut libc::c_void {
+        let stackp = mmap(ptr::null_mut(),
+                          SIGSTKSZ,
+                          PROT_READ | PROT_WRITE,
+                          MAP_PRIVATE | MAP_ANON,
+                          -1,
+                          0);
+        if stackp == MAP_FAILED {
             panic!("failed to allocate an alternative stack");
         }
+        stackp
+    }
 
-        let mut stack: libc::stack_t = mem::zeroed();
+    #[cfg(any(target_os = "linux",
+              target_os = "macos",
+              target_os = "bitrig",
+              target_os = "netbsd",
+              target_os = "openbsd"))]
+    unsafe fn get_stack() -> libc::stack_t {
+        libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ }
+    }
 
-        stack.ss_sp = alt_stack;
-        stack.ss_flags = 0;
-        stack.ss_size = SIGSTKSZ;
+    #[cfg(any(target_os = "freebsd",
+              target_os = "dragonfly"))]
+    unsafe fn get_stack() -> libc::stack_t {
+        libc::stack_t { ss_sp: get_stackp() as *mut i8, ss_flags: 0, ss_size: SIGSTKSZ }
+    }
 
+    pub unsafe fn make_handler() -> Handler {
+        let stack = get_stack();
         sigaltstack(&stack, ptr::null_mut());
-
-        Handler { _data: alt_stack }
+        Handler { _data: stack.ss_sp as *mut libc::c_void }
     }
 
     pub unsafe fn drop_handler(handler: &mut Handler) {
@@ -166,6 +184,7 @@ mod imp {
               target_os = "bitrig",
               target_os = "dragonfly",
               target_os = "freebsd",
+              target_os = "solaris",
               all(target_os = "netbsd", not(target_vendor = "rumprun")),
               target_os = "openbsd")))]
 mod imp {