about summary refs log tree commit diff
path: root/src/libstd/sys/unix/stack_overflow.rs
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-07-27 13:41:35 -0700
committerAlex Crichton <alex@alexcrichton.com>2015-08-10 16:35:44 -0700
commit7a3fdfbf674a08b7f6fd32c9124e52924a2f9a1c (patch)
tree5553605e8d9ac7fc23cfec8f689f6c923e78abdd /src/libstd/sys/unix/stack_overflow.rs
parentd03456183e85fe7bd465bbe7c8f67885a2528444 (diff)
downloadrust-7a3fdfbf674a08b7f6fd32c9124e52924a2f9a1c.tar.gz
rust-7a3fdfbf674a08b7f6fd32c9124e52924a2f9a1c.zip
Remove morestack support
This commit removes all morestack support from the compiler which entails:

* Segmented stacks are no longer emitted in codegen.
* We no longer build or distribute libmorestack.a
* The `stack_exhausted` lang item is no longer required

The only current use of the segmented stack support in LLVM is to detect stack
overflow. This is no longer really required, however, because we already have
guard pages for all threads and registered signal handlers watching for a
segfault on those pages (to print out a stack overflow message). Additionally,
major platforms (aka Windows) already don't use morestack.

This means that Rust is by default less likely to catch stack overflows because
if a function takes up more than one page of stack space it won't hit the guard
page. This is what the purpose of morestack was (to catch this case), but it's
better served with stack probes which have more cross platform support and no
runtime support necessary. Until LLVM supports this for all platform it looks
like morestack isn't really buying us much.

cc #16012 (still need stack probes)
Closes #26458 (a drive-by fix to help diagnostics on stack overflow)
Diffstat (limited to 'src/libstd/sys/unix/stack_overflow.rs')
-rw-r--r--src/libstd/sys/unix/stack_overflow.rs72
1 files changed, 33 insertions, 39 deletions
diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs
index ed4e50735a6..4e4cf2b0ed1 100644
--- a/src/libstd/sys/unix/stack_overflow.rs
+++ b/src/libstd/sys/unix/stack_overflow.rs
@@ -40,25 +40,17 @@ impl Drop for Handler {
           target_os = "netbsd",
           target_os = "openbsd"))]
 mod imp {
-    use sys_common::stack;
-
     use super::Handler;
     use rt::util::report_overflow;
     use mem;
     use ptr;
-    use intrinsics;
     use sys::c::{siginfo, sigaction, SIGBUS, SIG_DFL,
                  SA_SIGINFO, SA_ONSTACK, sigaltstack,
-                 SIGSTKSZ, sighandler_t, raise};
+                 SIGSTKSZ, sighandler_t};
     use libc;
     use libc::funcs::posix88::mman::{mmap, munmap};
-    use libc::funcs::posix01::signal::signal;
-    use libc::consts::os::posix88::{SIGSEGV,
-                                    PROT_READ,
-                                    PROT_WRITE,
-                                    MAP_PRIVATE,
-                                    MAP_ANON,
-                                    MAP_FAILED};
+    use libc::{SIGSEGV, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON};
+    use libc::MAP_FAILED;
 
     use sys_common::thread_info;
 
@@ -66,46 +58,48 @@ mod imp {
     // This is initialized in init() and only read from after
     static mut PAGE_SIZE: usize = 0;
 
-    #[no_stack_check]
+    // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
+    // (unmapped pages) at the end of every thread's stack, so if a thread ends
+    // up running into the guard page it'll trigger this handler. We want to
+    // detect these cases and print out a helpful error saying that the stack
+    // has overflowed. All other signals, however, should go back to what they
+    // 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.
+    //
+    // 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 siginfo,
-                                     _data: *mut libc::c_void) {
-
-        // We can not return from a SIGSEGV or SIGBUS signal.
-        // See: https://www.gnu.org/software/libc/manual/html_node/Handler-Returns.html
-
-        unsafe fn term(signum: libc::c_int) -> ! {
-            use core::mem::transmute;
-
-            signal(signum, transmute(SIG_DFL));
-            raise(signum);
-            intrinsics::abort();
-        }
-
-        // We're calling into functions with stack checks
-        stack::record_sp_limit(0);
-
+                                    info: *mut siginfo,
+                                    _data: *mut libc::c_void) {
         let guard = thread_info::stack_guard().unwrap_or(0);
         let addr = (*info).si_addr as usize;
 
-        if guard == 0 || addr < guard - PAGE_SIZE || addr >= guard {
-            term(signum);
+        // If the faulting address is within the guard page, then we print a
+        // message saying so.
+        if guard != 0 && guard - PAGE_SIZE <= addr && addr < guard {
+            report_overflow();
         }
 
-        report_overflow();
+        // 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());
 
-        intrinsics::abort()
+        // See comment above for why this function returns.
     }
 
     static mut MAIN_ALTSTACK: *mut libc::c_void = 0 as *mut libc::c_void;
 
     pub unsafe fn init() {
-        let psize = libc::sysconf(libc::consts::os::sysconf::_SC_PAGESIZE);
-        if psize == -1 {
-            panic!("failed to get page size");
-        }
-
-        PAGE_SIZE = psize as usize;
+        PAGE_SIZE = ::sys::os::page_size();
 
         let mut action: sigaction = mem::zeroed();
         action.sa_flags = SA_SIGINFO | SA_ONSTACK;