From b9eb2be3dfb9f698f6df27101d651985c4bd2bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 3 Mar 2023 22:25:18 +0000 Subject: [PATCH] On nightly, dump ICE backtraces to disk Implement rust-lang/compiler-team#578. When an ICE is encountered on nightly releases, the new rustc panic handler will also write the contents of the backtrace to disk. If any `delay_span_bug`s are encountered, their backtrace is also added to the file. The platform and rustc version will also be collected. --- std/src/lib.rs | 3 +++ std/src/panicking.rs | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/std/src/lib.rs b/std/src/lib.rs index d287397aa..5bf66850f 100644 --- a/std/src/lib.rs +++ b/std/src/lib.rs @@ -604,6 +604,9 @@ pub mod alloc; // Private support modules mod panicking; +#[unstable(feature = "ice_to_disk", issue = "none")] +pub use panicking::panic_hook_with_disk_dump; + #[path = "../../backtrace/src/lib.rs"] #[allow(dead_code, unused_attributes, fuzzy_provenance_casts)] mod backtrace_rs; diff --git a/std/src/panicking.rs b/std/src/panicking.rs index a6a370409..0e90d618a 100644 --- a/std/src/panicking.rs +++ b/std/src/panicking.rs @@ -234,7 +234,16 @@ where *hook = Hook::Custom(Box::new(move |info| hook_fn(&prev, info))); } +/// The default panic handler. fn default_hook(info: &PanicInfo<'_>) { + panic_hook_with_disk_dump(info, None) +} + +#[unstable(feature = "ice_to_disk", issue = "none")] +/// The implementation of the default panic handler. +/// +/// It can also write the backtrace to a given `path`. This functionality is used only by `rustc`. +pub fn panic_hook_with_disk_dump(info: &PanicInfo<'_>, path: Option<&crate::path::Path>) { // If this is a double panic, make sure that we print a backtrace // for this panic. Otherwise only print it if logging is enabled. let backtrace = if panic_count::get_count() >= 2 { @@ -256,7 +265,7 @@ fn default_hook(info: &PanicInfo<'_>) { let thread = thread_info::current_thread(); let name = thread.as_ref().and_then(|t| t.name()).unwrap_or(""); - let write = |err: &mut dyn crate::io::Write| { + let write = |err: &mut dyn crate::io::Write, backtrace: Option| { let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}"); static FIRST_PANIC: AtomicBool = AtomicBool::new(true); @@ -270,10 +279,19 @@ fn default_hook(info: &PanicInfo<'_>) { } Some(BacktraceStyle::Off) => { if FIRST_PANIC.swap(false, Ordering::SeqCst) { - let _ = writeln!( - err, - "note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace" - ); + if let Some(path) = path { + let _ = writeln!( + err, + "note: a backtrace for this error was stored at `{}`", + path.display(), + ); + } else { + let _ = writeln!( + err, + "note: run with `RUST_BACKTRACE=1` environment variable to display a \ + backtrace" + ); + } } } // If backtraces aren't supported, do nothing. @@ -281,11 +299,17 @@ fn default_hook(info: &PanicInfo<'_>) { } }; + if let Some(path) = path + && let Ok(mut out) = crate::fs::File::options().create(true).write(true).open(&path) + { + write(&mut out, BacktraceStyle::full()); + } + if let Some(local) = set_output_capture(None) { - write(&mut *local.lock().unwrap_or_else(|e| e.into_inner())); + write(&mut *local.lock().unwrap_or_else(|e| e.into_inner()), backtrace); set_output_capture(Some(local)); } else if let Some(mut out) = panic_output() { - write(&mut out); + write(&mut out, backtrace); } }