Dynamically size sigaltstk in rustc
rustc installs a signal stack that assumes that MINSIGSTKSZ is a constant, unchanging value. Newer hardware undermines that assumption greatly, with register files larger than MINSIGSTKZ. Properly handle this so that it is correct on all supported Linux versions with all CPUs.
This commit is contained in:
parent
71f71a5397
commit
094cb1a9fb
@ -1453,13 +1453,13 @@ extern "C" fn print_stack_trace(_: libc::c_int) {
|
|||||||
/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
|
/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
|
||||||
/// process, print a stack trace and then exit.
|
/// process, print a stack trace and then exit.
|
||||||
pub(super) fn install() {
|
pub(super) fn install() {
|
||||||
|
use std::alloc::{alloc, Layout};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
const ALT_STACK_SIZE: usize = libc::MINSIGSTKSZ + 64 * 1024;
|
let alt_stack_size: usize = min_sigstack_size() + 64 * 1024;
|
||||||
let mut alt_stack: libc::stack_t = std::mem::zeroed();
|
let mut alt_stack: libc::stack_t = std::mem::zeroed();
|
||||||
alt_stack.ss_sp =
|
alt_stack.ss_sp = alloc(Layout::from_size_align(alt_stack_size, 1).unwrap()).cast();
|
||||||
std::alloc::alloc(std::alloc::Layout::from_size_align(ALT_STACK_SIZE, 1).unwrap())
|
alt_stack.ss_size = alt_stack_size;
|
||||||
as *mut libc::c_void;
|
|
||||||
alt_stack.ss_size = ALT_STACK_SIZE;
|
|
||||||
libc::sigaltstack(&alt_stack, std::ptr::null_mut());
|
libc::sigaltstack(&alt_stack, std::ptr::null_mut());
|
||||||
|
|
||||||
let mut sa: libc::sigaction = std::mem::zeroed();
|
let mut sa: libc::sigaction = std::mem::zeroed();
|
||||||
@ -1469,6 +1469,23 @@ pub(super) fn install() {
|
|||||||
libc::sigaction(libc::SIGSEGV, &sa, std::ptr::null_mut());
|
libc::sigaction(libc::SIGSEGV, &sa, std::ptr::null_mut());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Modern kernels on modern hardware can have dynamic signal stack sizes.
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
|
fn min_sigstack_size() -> usize {
|
||||||
|
const AT_MINSIGSTKSZ: core::ffi::c_ulong = 51;
|
||||||
|
let dynamic_sigstksz = unsafe { libc::getauxval(AT_MINSIGSTKSZ) };
|
||||||
|
// If getauxval couldn't find the entry, it returns 0,
|
||||||
|
// so take the higher of the "constant" and auxval.
|
||||||
|
// This transparently supports older kernels which don't provide AT_MINSIGSTKSZ
|
||||||
|
libc::MINSIGSTKSZ.max(dynamic_sigstksz as _)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Not all OS support hardware where this is needed.
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||||
|
fn min_sigstack_size() -> usize {
|
||||||
|
libc::MINSIGSTKSZ
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))]
|
#[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))]
|
||||||
|
Loading…
Reference in New Issue
Block a user