Implement panic::update_hook

This commit is contained in:
Badel2 2022-01-05 22:42:21 +01:00
parent e012a191d7
commit 8bdf5c3de6
7 changed files with 102 additions and 16 deletions

View file

@ -38,6 +38,7 @@
#![feature(const_trait_impl)]
#![feature(const_str_from_utf8)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(panic_update_hook)]
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

View file

@ -1783,12 +1783,13 @@ thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
#[test]
#[cfg_attr(target_os = "emscripten", ignore)] // no threads
fn panic_safe() {
let prev = panic::take_hook();
panic::set_hook(Box::new(move |info| {
if !SILENCE_PANIC.with(|s| s.get()) {
prev(info);
}
}));
panic::update_hook(|prev| {
Box::new(move |info| {
if !SILENCE_PANIC.with(|s| s.get()) {
prev(info);
}
})
});
let mut rng = thread_rng();

View file

@ -310,16 +310,17 @@ impl Bridge<'_> {
// NB. the server can't do this because it may use a different libstd.
static HIDE_PANICS_DURING_EXPANSION: Once = Once::new();
HIDE_PANICS_DURING_EXPANSION.call_once(|| {
let prev = panic::take_hook();
panic::set_hook(Box::new(move |info| {
let show = BridgeState::with(|state| match state {
BridgeState::NotConnected => true,
BridgeState::Connected(_) | BridgeState::InUse => force_show_panics,
});
if show {
prev(info)
}
}));
panic::update_hook(|prev| {
Box::new(move |info| {
let show = BridgeState::with(|state| match state {
BridgeState::NotConnected => true,
BridgeState::Connected(_) | BridgeState::InUse => force_show_panics,
});
if show {
prev(info)
}
})
});
});
BRIDGE_STATE.with(|state| state.set(BridgeState::Connected(self), f))

View file

@ -30,6 +30,7 @@
#![feature(restricted_std)]
#![feature(rustc_attrs)]
#![feature(min_specialization)]
#![feature(panic_update_hook)]
#![recursion_limit = "256"]
#[unstable(feature = "proc_macro_internals", issue = "27812")]

View file

@ -36,6 +36,9 @@ pub use core::panic::panic_2021;
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub use crate::panicking::{set_hook, take_hook};
#[unstable(feature = "panic_update_hook", issue = "92649")]
pub use crate::panicking::update_hook;
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub use core::panic::{Location, PanicInfo};

View file

@ -180,6 +180,69 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
}
}
/// Atomic combination of [`take_hook`] + [`set_hook`].
///
/// [`take_hook`]: ./fn.take_hook.html
/// [`set_hook`]: ./fn.set_hook.html
///
/// # Panics
///
/// Panics if called from a panicking thread.
///
/// Panics if the provided closure calls any of the functions [`panic::take_hook`],
/// [`panic::set_hook`], or [`panic::update_hook`].
///
/// Note: if the provided closure panics, the panic will not be able to be handled, resulting in a
/// double panic that aborts the process with a generic error message.
///
/// [`panic::take_hook`]: ./fn.take_hook.html
/// [`panic::set_hook`]: ./fn.set_hook.html
/// [`panic::update_hook`]: ./fn.update_hook.html
///
/// # Examples
///
/// The following will print the custom message, and then the normal output of panic.
///
/// ```should_panic
/// #![feature(panic_update_hook)]
/// use std::panic;
///
/// panic::update_hook(|prev| {
/// Box::new(move |panic_info| {
/// println!("Print custom message and execute panic handler as usual");
/// prev(panic_info);
/// })
/// });
///
/// panic!("Custom and then normal");
/// ```
#[unstable(feature = "panic_update_hook", issue = "92649")]
pub fn update_hook<F>(hook_fn: F)
where
F: FnOnce(
Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>,
) -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>,
{
if thread::panicking() {
panic!("cannot modify the panic hook from a panicking thread");
}
unsafe {
let guard = HOOK_LOCK.write();
let old_hook = HOOK;
HOOK = Hook::Default;
let hook_for_fn = match old_hook {
Hook::Default => Box::new(default_hook),
Hook::Custom(ptr) => Box::from_raw(ptr),
};
let hook = hook_fn(hook_for_fn);
HOOK = Hook::Custom(Box::into_raw(hook));
drop(guard);
}
}
fn default_hook(info: &PanicInfo<'_>) {
// If this is a double panic, make sure that we print a backtrace
// for this panic. Otherwise only print it if logging is enabled.

View file

@ -0,0 +1,16 @@
// run-fail
// error-pattern: panicked while processing panic
#![allow(stable_features)]
// ignore-emscripten no threads support
#![feature(std_panic)]
#![feature(panic_update_hook)]
use std::panic;
fn main() {
panic::update_hook(|_prev| {
panic!("inside update_hook");
})
}