about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2023-03-03 22:25:18 +0000
committerEsteban Küber <esteban@kuber.com.ar>2023-07-19 14:10:07 +0000
commit8eb5843a592afbee8ae5352828f8f0b74034b9e0 (patch)
treea8f3bd019a4c355babb7e5b5ae0bc58c0b5007b3 /library/std/src
parent77e24f90f599070af2d8051ef9adad7fe528dd78 (diff)
downloadrust-8eb5843a592afbee8ae5352828f8f0b74034b9e0.tar.gz
rust-8eb5843a592afbee8ae5352828f8f0b74034b9e0.zip
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.
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/lib.rs3
-rw-r--r--library/std/src/panicking.rs38
2 files changed, 34 insertions, 7 deletions
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index d287397aab3..5bf66850f03 100644
--- a/library/std/src/lib.rs
+++ b/library/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/library/std/src/panicking.rs b/library/std/src/panicking.rs
index a6a370409c0..0e90d618ad4 100644
--- a/library/std/src/panicking.rs
+++ b/library/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("<unnamed>");
 
-    let write = |err: &mut dyn crate::io::Write| {
+    let write = |err: &mut dyn crate::io::Write, backtrace: Option<BacktraceStyle>| {
         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);
     }
 }