Skip to content

Commit 2f7ffb5

Browse files
authored
feat: support guided panic info with backtrace (#2097)
* feat: support guided panic info with backtrace * chore: changeset * feat: wording * chore: clippy * chore: lint
1 parent ec01685 commit 2f7ffb5

File tree

3 files changed

+59
-17
lines changed

3 files changed

+59
-17
lines changed

.changeset/slow-trains-melt.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@rspack/binding": patch
3+
---
4+
5+
feat: support guided panic info with backtrace

crates/rspack_error/src/catch_unwind.rs

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::{
2+
cell::RefCell,
23
future::Future,
34
pin::Pin,
45
task::{Context, Poll},
@@ -42,33 +43,65 @@ pub mod PanicStrategy {
4243

4344
#[inline]
4445
fn panic_hook_handler<S: PanicStrategy::S, R>(f: impl FnOnce() -> R) -> R {
45-
let prev_hook = if S::is_suppressed() {
46-
let prev = Some(std::panic::take_hook());
47-
std::panic::set_hook(Box::new(|_| {}));
48-
prev
49-
} else {
50-
None
51-
};
46+
PANIC_HOOK.with(|hook| {
47+
if !S::is_suppressed() {
48+
*hook.borrow_mut() = Some(std::panic::take_hook());
49+
}
50+
});
51+
std::panic::set_hook(Box::new(move |info| {
52+
PANIC_HOOK.with(|hook| {
53+
if let Some(hook) = &*hook.borrow() {
54+
hook(info);
55+
}
56+
});
57+
PANIC_INFO_AND_BACKTRACE.with(|bt| {
58+
*bt.borrow_mut() = Some((
59+
info.to_string(),
60+
std::backtrace::Backtrace::force_capture().to_string(),
61+
));
62+
});
63+
}));
5264
let result = f();
53-
if let Some(prev_hook) = prev_hook {
54-
std::panic::set_hook(prev_hook);
55-
}
65+
PANIC_HOOK.with(|hook| {
66+
if let Some(hook) = hook.borrow_mut().take() {
67+
std::panic::set_hook(hook);
68+
}
69+
});
5670

5771
result
5872
}
5973

74+
type PanicHook = Box<dyn Fn(&std::panic::PanicInfo<'_>) + 'static + Sync + Send>;
75+
76+
thread_local! {
77+
static PANIC_INFO_AND_BACKTRACE: RefCell<Option<(String, String)>> = RefCell::new(None);
78+
static PANIC_HOOK: RefCell<Option<PanicHook>> = RefCell::new(None);
79+
}
80+
6081
pub fn catch_unwind<S: PanicStrategy::S, R>(f: impl FnOnce() -> R) -> Result<R> {
6182
match panic_hook_handler::<S, _>(move || {
6283
std::panic::catch_unwind(std::panic::AssertUnwindSafe(f))
6384
}) {
6485
Ok(res) => Ok(res),
65-
Err(cause) => match cause.downcast_ref::<&'static str>() {
66-
None => match cause.downcast_ref::<String>() {
67-
None => Err(internal_error!("Unknown panic message")),
68-
Some(message) => Err(internal_error!("{message}")),
69-
},
70-
Some(message) => Err(internal_error!("{message}")),
71-
},
86+
Err(cause) => {
87+
let (info, backtrace) = PANIC_INFO_AND_BACKTRACE
88+
.with(|b| b.borrow_mut().take())
89+
.unwrap_or_default();
90+
91+
match cause.downcast_ref::<&'static str>() {
92+
None => match cause.downcast_ref::<String>() {
93+
None => Err(internal_error!(
94+
"Unknown fatal error.\nRaw: {info}\n{GENERIC_FATAL_MESSAGE}\n\n{backtrace}"
95+
)),
96+
Some(message) => Err(internal_error!(
97+
"{message}.\nRaw: {info}\n{GENERIC_FATAL_MESSAGE}\n\n{backtrace}"
98+
)),
99+
},
100+
Some(message) => Err(internal_error!(
101+
"{message}.\nRaw: {info}\n{GENERIC_FATAL_MESSAGE}\n\n{backtrace}"
102+
)),
103+
}
104+
}
72105
}
73106
}
74107

@@ -95,3 +128,6 @@ impl<F: Future + Send + 'static> Future for CatchUnwindFuture<F> {
95128
}
96129
}
97130
}
131+
132+
const GENERIC_FATAL_MESSAGE: &str =
133+
"This is not expected, please file an issue at https://github.com/web-infra-dev/rspack/issues.";

crates/rspack_error/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![feature(let_chains)]
12
#![feature(anonymous_lifetime_in_impl_trait)]
23

34
mod catch_unwind;

0 commit comments

Comments
 (0)