diff options
Diffstat (limited to 'src/libstd/sys/unix/stack_overflow.rs')
| -rw-r--r-- | src/libstd/sys/unix/stack_overflow.rs | 81 |
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 { |
