From 660a3486fc6da2c3599a167d73d849178f98bc17 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sat, 27 Sep 2025 13:37:29 +0200 Subject: [PATCH] Skip stack overflow handler for panic=immediate-abort std installs guard pages and a signal handler to ensure that stackoverflows 1) terminate abruptly and 2) print an nice message. Even for panic=immediate-abort, 1) is desirable, we don't want silent data corruption there. But 2) is completely unnecessary, as users deliberately *don't* want nice messages, they want minimum binary size. Therefore, skip the entire guard signal handler setup, which saves a lot of bytes. I tested this with a hello world binary using fat LTO, build-std, panic=immediate-abort, opt-level=s, strip=debuginfo. `size` reports significant savings: ``` text data bss dec hex filename 15252 1032 104 16388 4004 tiny-before 6881 964 48 7893 1ed5 tiny-after2 ``` `nm -U` goes from 71 to 56, getting rid of a bunch of stack overflow related symbols. The disk size goes from `31k` to `24k`. The impact on the error message is minimal, as the message was already missing. before: ``` fish: Job 1, './tiny-so-before' terminated by signal SIGABRT (Abort) ``` after: ``` fish: Job 1, './tiny-so-after' terminated by signal SIGSEGV (Address boundary error) ``` --- library/std/src/sys/pal/unix/stack_overflow.rs | 12 +++++++++++- library/std/src/sys/pal/windows/mod.rs | 3 ++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 0d2100d66bc09..08a3cee64bab2 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -148,6 +148,13 @@ mod imp { let mut guard_page_range = unsafe { install_main_guard() }; + // Even for panic=immediate-abort, installing the guard pages is important for soundness. + // That said, we do not care about giving nice stackoverflow messages via our custom + // signal handler, just exit early and let the user enjoy the segfault. + if cfg!(panic = "immediate-abort") { + return; + } + // SAFETY: assuming all platforms define struct sigaction as "zero-initializable" let mut action: sigaction = unsafe { mem::zeroed() }; for &signal in &[SIGSEGV, SIGBUS] { @@ -179,6 +186,9 @@ mod imp { /// Must be called only once #[forbid(unsafe_op_in_unsafe_fn)] pub unsafe fn cleanup() { + if cfg!(panic = "immediate-abort") { + return; + } // FIXME: I probably cause more bugs than I'm worth! // see https://github.com/rust-lang/rust/issues/111272 unsafe { drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed)) }; @@ -230,7 +240,7 @@ mod imp { /// Mutates the alternate signal stack #[forbid(unsafe_op_in_unsafe_fn)] pub unsafe fn make_handler(main_thread: bool, thread_name: Option>) -> Handler { - if !NEED_ALTSTACK.load(Ordering::Acquire) { + if cfg!(panic = "immediate-abort") || !NEED_ALTSTACK.load(Ordering::Acquire) { return Handler::null(); } diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 3357946b8f71d..b7578b01584bf 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -22,7 +22,8 @@ pub mod os; pub mod pipe; pub mod time; cfg_select! { - not(target_vendor = "uwp") => { + // We don't care about printing nice error messages for panic=immediate-abort + all(not(target_vendor = "uwp"), not(panic = "immediate-abort")) => { pub mod stack_overflow; } _ => {