Skip to content

Commit 8bdf5c3

Browse files
committed
Implement panic::update_hook
1 parent e012a19 commit 8bdf5c3

File tree

7 files changed

+102
-16
lines changed

7 files changed

+102
-16
lines changed

library/alloc/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#![feature(const_trait_impl)]
3939
#![feature(const_str_from_utf8)]
4040
#![feature(nonnull_slice_from_raw_parts)]
41+
#![feature(panic_update_hook)]
4142

4243
use std::collections::hash_map::DefaultHasher;
4344
use std::hash::{Hash, Hasher};

library/alloc/tests/slice.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -1783,12 +1783,13 @@ thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
17831783
#[test]
17841784
#[cfg_attr(target_os = "emscripten", ignore)] // no threads
17851785
fn panic_safe() {
1786-
let prev = panic::take_hook();
1787-
panic::set_hook(Box::new(move |info| {
1788-
if !SILENCE_PANIC.with(|s| s.get()) {
1789-
prev(info);
1790-
}
1791-
}));
1786+
panic::update_hook(|prev| {
1787+
Box::new(move |info| {
1788+
if !SILENCE_PANIC.with(|s| s.get()) {
1789+
prev(info);
1790+
}
1791+
})
1792+
});
17921793

17931794
let mut rng = thread_rng();
17941795

library/proc_macro/src/bridge/client.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -310,16 +310,17 @@ impl Bridge<'_> {
310310
// NB. the server can't do this because it may use a different libstd.
311311
static HIDE_PANICS_DURING_EXPANSION: Once = Once::new();
312312
HIDE_PANICS_DURING_EXPANSION.call_once(|| {
313-
let prev = panic::take_hook();
314-
panic::set_hook(Box::new(move |info| {
315-
let show = BridgeState::with(|state| match state {
316-
BridgeState::NotConnected => true,
317-
BridgeState::Connected(_) | BridgeState::InUse => force_show_panics,
318-
});
319-
if show {
320-
prev(info)
321-
}
322-
}));
313+
panic::update_hook(|prev| {
314+
Box::new(move |info| {
315+
let show = BridgeState::with(|state| match state {
316+
BridgeState::NotConnected => true,
317+
BridgeState::Connected(_) | BridgeState::InUse => force_show_panics,
318+
});
319+
if show {
320+
prev(info)
321+
}
322+
})
323+
});
323324
});
324325

325326
BRIDGE_STATE.with(|state| state.set(BridgeState::Connected(self), f))

library/proc_macro/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#![feature(restricted_std)]
3131
#![feature(rustc_attrs)]
3232
#![feature(min_specialization)]
33+
#![feature(panic_update_hook)]
3334
#![recursion_limit = "256"]
3435

3536
#[unstable(feature = "proc_macro_internals", issue = "27812")]

library/std/src/panic.rs

+3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ pub use core::panic::panic_2021;
3636
#[stable(feature = "panic_hooks", since = "1.10.0")]
3737
pub use crate::panicking::{set_hook, take_hook};
3838

39+
#[unstable(feature = "panic_update_hook", issue = "92649")]
40+
pub use crate::panicking::update_hook;
41+
3942
#[stable(feature = "panic_hooks", since = "1.10.0")]
4043
pub use core::panic::{Location, PanicInfo};
4144

library/std/src/panicking.rs

+63
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,69 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
180180
}
181181
}
182182

183+
/// Atomic combination of [`take_hook`] + [`set_hook`].
184+
///
185+
/// [`take_hook`]: ./fn.take_hook.html
186+
/// [`set_hook`]: ./fn.set_hook.html
187+
///
188+
/// # Panics
189+
///
190+
/// Panics if called from a panicking thread.
191+
///
192+
/// Panics if the provided closure calls any of the functions [`panic::take_hook`],
193+
/// [`panic::set_hook`], or [`panic::update_hook`].
194+
///
195+
/// Note: if the provided closure panics, the panic will not be able to be handled, resulting in a
196+
/// double panic that aborts the process with a generic error message.
197+
///
198+
/// [`panic::take_hook`]: ./fn.take_hook.html
199+
/// [`panic::set_hook`]: ./fn.set_hook.html
200+
/// [`panic::update_hook`]: ./fn.update_hook.html
201+
///
202+
/// # Examples
203+
///
204+
/// The following will print the custom message, and then the normal output of panic.
205+
///
206+
/// ```should_panic
207+
/// #![feature(panic_update_hook)]
208+
/// use std::panic;
209+
///
210+
/// panic::update_hook(|prev| {
211+
/// Box::new(move |panic_info| {
212+
/// println!("Print custom message and execute panic handler as usual");
213+
/// prev(panic_info);
214+
/// })
215+
/// });
216+
///
217+
/// panic!("Custom and then normal");
218+
/// ```
219+
#[unstable(feature = "panic_update_hook", issue = "92649")]
220+
pub fn update_hook<F>(hook_fn: F)
221+
where
222+
F: FnOnce(
223+
Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>,
224+
) -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>,
225+
{
226+
if thread::panicking() {
227+
panic!("cannot modify the panic hook from a panicking thread");
228+
}
229+
230+
unsafe {
231+
let guard = HOOK_LOCK.write();
232+
let old_hook = HOOK;
233+
HOOK = Hook::Default;
234+
235+
let hook_for_fn = match old_hook {
236+
Hook::Default => Box::new(default_hook),
237+
Hook::Custom(ptr) => Box::from_raw(ptr),
238+
};
239+
240+
let hook = hook_fn(hook_for_fn);
241+
HOOK = Hook::Custom(Box::into_raw(hook));
242+
drop(guard);
243+
}
244+
}
245+
183246
fn default_hook(info: &PanicInfo<'_>) {
184247
// If this is a double panic, make sure that we print a backtrace
185248
// for this panic. Otherwise only print it if logging is enabled.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// run-fail
2+
// error-pattern: panicked while processing panic
3+
#![allow(stable_features)]
4+
5+
// ignore-emscripten no threads support
6+
7+
#![feature(std_panic)]
8+
#![feature(panic_update_hook)]
9+
10+
use std::panic;
11+
12+
fn main() {
13+
panic::update_hook(|_prev| {
14+
panic!("inside update_hook");
15+
})
16+
}

0 commit comments

Comments
 (0)