about summary refs log tree commit diff
path: root/compiler/rustc_driver_impl
diff options
context:
space:
mode:
authorJubilee Young <workingjubilee@gmail.com>2023-07-10 01:45:31 -0700
committerJubilee Young <workingjubilee@gmail.com>2023-07-10 12:05:16 -0700
commit094cb1a9fbb6b2c9b6094cd6424139f70f8912cc (patch)
tree46769cc5b814c702243ff94cb9d2df0d6ad89d20 /compiler/rustc_driver_impl
parent71f71a5397c42fec01f5c1045c638d961fa9f7ca (diff)
downloadrust-094cb1a9fbb6b2c9b6094cd6424139f70f8912cc.tar.gz
rust-094cb1a9fbb6b2c9b6094cd6424139f70f8912cc.zip
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.
Diffstat (limited to 'compiler/rustc_driver_impl')
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs27
1 files changed, 22 insertions, 5 deletions
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 9352fe3147e..2e26ce111f0 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -1453,13 +1453,13 @@ mod signal_handler {
     /// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
     /// process, print a stack trace and then exit.
     pub(super) fn install() {
+        use std::alloc::{alloc, Layout};
+
         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();
-            alt_stack.ss_sp =
-                std::alloc::alloc(std::alloc::Layout::from_size_align(ALT_STACK_SIZE, 1).unwrap())
-                    as *mut libc::c_void;
-            alt_stack.ss_size = ALT_STACK_SIZE;
+            alt_stack.ss_sp = alloc(Layout::from_size_align(alt_stack_size, 1).unwrap()).cast();
+            alt_stack.ss_size = alt_stack_size;
             libc::sigaltstack(&alt_stack, std::ptr::null_mut());
 
             let mut sa: libc::sigaction = std::mem::zeroed();
@@ -1469,6 +1469,23 @@ mod signal_handler {
             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"))))]