reproducible_panic/
lib.rs1#![allow(clippy::needless_doctest_main)]
35
36#![allow(deprecated)]
38
39use std::panic::PanicInfo as PanicHookInfo;
40
41use std::sync::atomic::{AtomicBool, Ordering};
42use std::io::Write;
43
44pub fn install() {
46 std::panic::set_hook(Box::new(panic_hook));
47}
48
49pub fn panic_hook(info: &PanicHookInfo<'_>) {
55 let backtrace = std::backtrace::Backtrace::capture();
56 let location = info.location();
57 let msg = payload_as_str(info);
58 let current_thread = std::thread::current();
59 let thread_name = current_thread.name().unwrap_or("<unnamed>");
60 let mut stderr = std::io::stderr().lock();
61
62
63 if let Some(location) = location {
64 writeln!(stderr, "\nthread '{thread_name}' panicked at {location}").ok();
65 } else {
66 writeln!(stderr, "\nthread '{thread_name}' panicked").ok();
67 }
68 if let Some(msg) = msg {
69 writeln!(stderr, "{msg}").ok();
70 }
71
72 static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
73
74 match backtrace.status() {
75 std::backtrace::BacktraceStatus::Captured => {
76 if std::env::var_os("RUST_BACKTRACE").is_some_and(|x| x == "full") {
77 writeln!(&mut stderr, "stack backtrace:\n{backtrace:#}").ok();
78 } else {
79 writeln!(&mut stderr, "stack backtrace:\n{backtrace}").ok();
80 }
81 }
82 std::backtrace::BacktraceStatus::Disabled => {
83 if FIRST_PANIC.swap(false, Ordering::Relaxed) {
84 writeln!(
85 &mut stderr,
86 "note: run with `RUST_BACKTRACE=1` environment variable to display a \
87 backtrace"
88 ).ok();
89 if cfg!(miri) {
90 writeln!(
91 &mut stderr,
92 "note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` \
93 for the environment variable to have an effect"
94 ).ok();
95 }
96 }
97 }
98 std::backtrace::BacktraceStatus::Unsupported => (),
99 _ => (),
100 }
101}
102
103pub fn payload_as_str<'a>(info: &'a PanicHookInfo<'a>) -> Option<&'a str> {
104 if let Some(s) = info.payload().downcast_ref::<&str>() {
105 Some(s)
106 } else if let Some(s) = info.payload().downcast_ref::<String>() {
107 Some(s)
108 } else {
109 None
110 }
111}