From a0a8e02e663fd62705630616f06b45a0bd3e5b6c Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 16 Feb 2025 22:16:31 +0100 Subject: [PATCH] Install more signal stack trace handlers --- .../rustc_driver_impl/src/signal_handler.rs | 50 +++++++++++++++---- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_driver_impl/src/signal_handler.rs b/compiler/rustc_driver_impl/src/signal_handler.rs index 08b7d937661f..e7bc57c9749b 100644 --- a/compiler/rustc_driver_impl/src/signal_handler.rs +++ b/compiler/rustc_driver_impl/src/signal_handler.rs @@ -6,6 +6,15 @@ use std::{fmt, mem, ptr, slice}; use rustc_interface::util::{DEFAULT_STACK_SIZE, STACK_SIZE}; +/// Signals that represent that we have a bug, and our prompt termination has +/// been ordered. +#[rustfmt::skip] +const KILL_SIGNALS: [(libc::c_int, &str); 3] = [ + (libc::SIGILL, "SIGILL"), + (libc::SIGBUS, "SIGBUS"), + (libc::SIGSEGV, "SIGSEGV") +]; + unsafe extern "C" { fn backtrace_symbols_fd(buffer: *const *mut libc::c_void, size: libc::c_int, fd: libc::c_int); } @@ -39,8 +48,19 @@ macro raw_errln($tokens:tt) { /// # Safety /// /// Caller must ensure that this function is not re-entered. -unsafe extern "C" fn print_stack_trace(_: libc::c_int) { +unsafe extern "C" fn print_stack_trace(signum: libc::c_int) { const MAX_FRAMES: usize = 256; + + let signame = { + let mut signame = ""; + for sig in KILL_SIGNALS { + if sig.0 == signum { + signame = sig.1; + } + } + signame + }; + let stack = unsafe { // Reserve data segment so we don't have to malloc in a signal handler, which might fail // in incredibly undesirable and unexpected ways due to e.g. the allocator deadlocking @@ -54,7 +74,8 @@ unsafe extern "C" fn print_stack_trace(_: libc::c_int) { }; // Just a stack trace is cryptic. Explain what we're doing. - raw_errln!("error: rustc interrupted by SIGSEGV, printing backtrace\n"); + raw_errln!("error: rustc interrupted by {signame}, printing backtrace\n"); + let mut written = 1; let mut consumed = 0; // Begin elaborating return addrs into symbols and writing them directly to stderr @@ -94,7 +115,7 @@ unsafe extern "C" fn print_stack_trace(_: libc::c_int) { written += rem.len() + 1; let random_depth = || 8 * 16; // chosen by random diceroll (2d20) - if cyclic || stack.len() > random_depth() { + if (cyclic || stack.len() > random_depth()) && signum == libc::SIGSEGV { // technically speculation, but assert it with confidence anyway. // rustc only arrived in this signal handler because bad things happened // and this message is for explaining it's not the programmer's fault @@ -106,17 +127,22 @@ unsafe extern "C" fn print_stack_trace(_: libc::c_int) { written += 1; } raw_errln!("note: we would appreciate a report at https://github.com/rust-lang/rust"); - // get the current stack size WITHOUT blocking and double it - let new_size = STACK_SIZE.get().copied().unwrap_or(DEFAULT_STACK_SIZE) * 2; - raw_errln!("help: you can increase rustc's stack size by setting RUST_MIN_STACK={new_size}"); - written += 2; + written += 1; + if signum == libc::SIGSEGV { + // get the current stack size WITHOUT blocking and double it + let new_size = STACK_SIZE.get().copied().unwrap_or(DEFAULT_STACK_SIZE) * 2; + raw_errln!( + "help: you can increase rustc's stack size by setting RUST_MIN_STACK={new_size}" + ); + written += 1; + } if written > 24 { - // We probably just scrolled the earlier "we got SIGSEGV" message off the terminal - raw_errln!("note: backtrace dumped due to SIGSEGV! resuming signal"); + // We probably just scrolled the earlier "interrupted by {signame}" message off the terminal + raw_errln!("note: backtrace dumped due to {signame}! resuming signal"); }; } -/// When SIGSEGV is delivered to the process, print a stack trace and then exit. +/// When one of the KILL signals is delivered to the process, print a stack trace and then exit. pub(super) fn install() { unsafe { let alt_stack_size: usize = min_sigstack_size() + 64 * 1024; @@ -129,7 +155,9 @@ pub(super) fn install() { sa.sa_sigaction = print_stack_trace as libc::sighandler_t; sa.sa_flags = libc::SA_NODEFER | libc::SA_RESETHAND | libc::SA_ONSTACK; libc::sigemptyset(&mut sa.sa_mask); - libc::sigaction(libc::SIGSEGV, &sa, ptr::null_mut()); + for (signum, _signame) in KILL_SIGNALS { + libc::sigaction(signum, &sa, ptr::null_mut()); + } } }