Skip to content

Commit b9eb2be

Browse files
committed
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.
1 parent 31f90f7 commit b9eb2be

File tree

2 files changed

+34
-7
lines changed

2 files changed

+34
-7
lines changed

std/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,9 @@ pub mod alloc;
604604
// Private support modules
605605
mod panicking;
606606

607+
#[unstable(feature = "ice_to_disk", issue = "none")]
608+
pub use panicking::panic_hook_with_disk_dump;
609+
607610
#[path = "../../backtrace/src/lib.rs"]
608611
#[allow(dead_code, unused_attributes, fuzzy_provenance_casts)]
609612
mod backtrace_rs;

std/src/panicking.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,16 @@ where
234234
*hook = Hook::Custom(Box::new(move |info| hook_fn(&prev, info)));
235235
}
236236

237+
/// The default panic handler.
237238
fn default_hook(info: &PanicInfo<'_>) {
239+
panic_hook_with_disk_dump(info, None)
240+
}
241+
242+
#[unstable(feature = "ice_to_disk", issue = "none")]
243+
/// The implementation of the default panic handler.
244+
///
245+
/// It can also write the backtrace to a given `path`. This functionality is used only by `rustc`.
246+
pub fn panic_hook_with_disk_dump(info: &PanicInfo<'_>, path: Option<&crate::path::Path>) {
238247
// If this is a double panic, make sure that we print a backtrace
239248
// for this panic. Otherwise only print it if logging is enabled.
240249
let backtrace = if panic_count::get_count() >= 2 {
@@ -256,7 +265,7 @@ fn default_hook(info: &PanicInfo<'_>) {
256265
let thread = thread_info::current_thread();
257266
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
258267

259-
let write = |err: &mut dyn crate::io::Write| {
268+
let write = |err: &mut dyn crate::io::Write, backtrace: Option<BacktraceStyle>| {
260269
let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
261270

262271
static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
@@ -270,22 +279,37 @@ fn default_hook(info: &PanicInfo<'_>) {
270279
}
271280
Some(BacktraceStyle::Off) => {
272281
if FIRST_PANIC.swap(false, Ordering::SeqCst) {
273-
let _ = writeln!(
274-
err,
275-
"note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace"
276-
);
282+
if let Some(path) = path {
283+
let _ = writeln!(
284+
err,
285+
"note: a backtrace for this error was stored at `{}`",
286+
path.display(),
287+
);
288+
} else {
289+
let _ = writeln!(
290+
err,
291+
"note: run with `RUST_BACKTRACE=1` environment variable to display a \
292+
backtrace"
293+
);
294+
}
277295
}
278296
}
279297
// If backtraces aren't supported, do nothing.
280298
None => {}
281299
}
282300
};
283301

302+
if let Some(path) = path
303+
&& let Ok(mut out) = crate::fs::File::options().create(true).write(true).open(&path)
304+
{
305+
write(&mut out, BacktraceStyle::full());
306+
}
307+
284308
if let Some(local) = set_output_capture(None) {
285-
write(&mut *local.lock().unwrap_or_else(|e| e.into_inner()));
309+
write(&mut *local.lock().unwrap_or_else(|e| e.into_inner()), backtrace);
286310
set_output_capture(Some(local));
287311
} else if let Some(mut out) = panic_output() {
288-
write(&mut out);
312+
write(&mut out, backtrace);
289313
}
290314
}
291315

0 commit comments

Comments
 (0)