diff options
| author | joboet <jonasboettiger@icloud.com> | 2024-01-11 20:10:25 +0100 |
|---|---|---|
| committer | joboet <jonasboettiger@icloud.com> | 2024-01-11 20:10:25 +0100 |
| commit | 99128b7e45f8b95d962da2e6ea584767f0c85455 (patch) | |
| tree | 20874cb2d8526a427342c32a45bc63a21022499c /library/std/src/sys/unix/stack_overflow.rs | |
| parent | 062e7c6a951c1e4f33c0a6f6761755949cde15ec (diff) | |
| download | rust-99128b7e45f8b95d962da2e6ea584767f0c85455.tar.gz rust-99128b7e45f8b95d962da2e6ea584767f0c85455.zip | |
std: begin moving platform support modules into `pal`
Diffstat (limited to 'library/std/src/sys/unix/stack_overflow.rs')
| -rw-r--r-- | library/std/src/sys/unix/stack_overflow.rs | 223 |
1 files changed, 0 insertions, 223 deletions
diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs deleted file mode 100644 index 3dbab4cc486..00000000000 --- a/library/std/src/sys/unix/stack_overflow.rs +++ /dev/null @@ -1,223 +0,0 @@ -#![cfg_attr(test, allow(dead_code))] - -use self::imp::{drop_handler, make_handler}; - -pub use self::imp::cleanup; -pub use self::imp::init; - -pub struct Handler { - data: *mut libc::c_void, -} - -impl Handler { - pub unsafe fn new() -> Handler { - make_handler() - } - - fn null() -> Handler { - Handler { data: crate::ptr::null_mut() } - } -} - -impl Drop for Handler { - fn drop(&mut self) { - unsafe { - drop_handler(self.data); - } - } -} - -#[cfg(any( - target_os = "linux", - target_os = "macos", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "hurd", - target_os = "solaris", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd" -))] -mod imp { - use super::Handler; - use crate::io; - use crate::mem; - use crate::ptr; - use crate::thread; - - use libc::MAP_FAILED; - #[cfg(not(all(target_os = "linux", target_env = "gnu")))] - use libc::{mmap as mmap64, munmap}; - #[cfg(all(target_os = "linux", target_env = "gnu"))] - use libc::{mmap64, munmap}; - use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL}; - use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE}; - use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV}; - - use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering}; - use crate::sys::unix::os::page_size; - use crate::sys_common::thread_info; - - // 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. 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. - // - // 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 "C" fn signal_handler( - signum: libc::c_int, - info: *mut libc::siginfo_t, - _data: *mut libc::c_void, - ) { - let guard = thread_info::stack_guard().unwrap_or(0..0); - let addr = (*info).si_addr() as usize; - - // If the faulting address is within the guard page, then we print a - // message saying so and abort. - if guard.start <= addr && addr < guard.end { - rtprintpanic!( - "\nthread '{}' has overflowed its stack\n", - thread::current().name().unwrap_or("<unknown>") - ); - 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. - } - } - - static MAIN_ALTSTACK: AtomicPtr<libc::c_void> = AtomicPtr::new(ptr::null_mut()); - static NEED_ALTSTACK: AtomicBool = AtomicBool::new(false); - - pub unsafe fn init() { - let mut action: sigaction = mem::zeroed(); - for &signal in &[SIGSEGV, SIGBUS] { - sigaction(signal, ptr::null_mut(), &mut action); - // Configure our signal handler if one is not already set. - if action.sa_sigaction == SIG_DFL { - action.sa_flags = SA_SIGINFO | SA_ONSTACK; - action.sa_sigaction = signal_handler as sighandler_t; - sigaction(signal, &action, ptr::null_mut()); - NEED_ALTSTACK.store(true, Ordering::Relaxed); - } - } - - let handler = make_handler(); - MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed); - mem::forget(handler); - } - - pub unsafe fn cleanup() { - drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed)); - } - - unsafe fn get_stackp() -> *mut libc::c_void { - // OpenBSD requires this flag for stack mapping - // otherwise the said mapping will fail as a no-op on most systems - // and has a different meaning on FreeBSD - #[cfg(any( - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "dragonfly", - ))] - let flags = MAP_PRIVATE | MAP_ANON | libc::MAP_STACK; - #[cfg(not(any( - target_os = "openbsd", - target_os = "netbsd", - target_os = "linux", - target_os = "dragonfly", - )))] - let flags = MAP_PRIVATE | MAP_ANON; - let stackp = - mmap64(ptr::null_mut(), SIGSTKSZ + page_size(), PROT_READ | PROT_WRITE, flags, -1, 0); - if stackp == MAP_FAILED { - panic!("failed to allocate an alternative stack: {}", io::Error::last_os_error()); - } - let guard_result = libc::mprotect(stackp, page_size(), PROT_NONE); - if guard_result != 0 { - panic!("failed to set up alternative stack guard page: {}", io::Error::last_os_error()); - } - stackp.add(page_size()) - } - - unsafe fn get_stack() -> libc::stack_t { - libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ } - } - - pub unsafe fn make_handler() -> Handler { - if !NEED_ALTSTACK.load(Ordering::Relaxed) { - return Handler::null(); - } - let mut stack = mem::zeroed(); - sigaltstack(ptr::null(), &mut stack); - // Configure alternate signal stack, if one is not already set. - if stack.ss_flags & SS_DISABLE != 0 { - stack = get_stack(); - sigaltstack(&stack, ptr::null_mut()); - Handler { data: stack.ss_sp as *mut libc::c_void } - } else { - Handler::null() - } - } - - pub unsafe fn drop_handler(data: *mut libc::c_void) { - if !data.is_null() { - let stack = libc::stack_t { - ss_sp: ptr::null_mut(), - ss_flags: SS_DISABLE, - // Workaround for bug in macOS implementation of sigaltstack - // UNIX2003 which returns ENOMEM when disabling a stack while - // passing ss_size smaller than MINSIGSTKSZ. According to POSIX - // both ss_sp and ss_size should be ignored in this case. - ss_size: SIGSTKSZ, - }; - sigaltstack(&stack, ptr::null_mut()); - // We know from `get_stackp` that the alternate stack we installed is part of a mapping - // that started one page earlier, so walk back a page and unmap from there. - munmap(data.sub(page_size()), SIGSTKSZ + page_size()); - } - } -} - -#[cfg(not(any( - target_os = "linux", - target_os = "macos", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "hurd", - target_os = "solaris", - target_os = "illumos", - target_os = "netbsd", - target_os = "openbsd", -)))] -mod imp { - pub unsafe fn init() {} - - pub unsafe fn cleanup() {} - - pub unsafe fn make_handler() -> super::Handler { - super::Handler::null() - } - - pub unsafe fn drop_handler(_data: *mut libc::c_void) {} -} |
