Skip to content

Commit 8ef3ce8

Browse files
committed
Change panic::update_hook to simplify usage
And to remove possibility of panics while changing the panic handler, because that resulted in a double panic.
1 parent 8bdf5c3 commit 8ef3ce8

File tree

5 files changed

+71
-54
lines changed

5 files changed

+71
-54
lines changed

library/alloc/tests/slice.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -1783,12 +1783,10 @@ 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-
panic::update_hook(|prev| {
1787-
Box::new(move |info| {
1788-
if !SILENCE_PANIC.with(|s| s.get()) {
1789-
prev(info);
1790-
}
1791-
})
1786+
panic::update_hook(move |prev, info| {
1787+
if !SILENCE_PANIC.with(|s| s.get()) {
1788+
prev(info);
1789+
}
17921790
});
17931791

17941792
let mut rng = thread_rng();

library/proc_macro/src/bridge/client.rs

+8-10
Original file line numberDiff line numberDiff line change
@@ -310,16 +310,14 @@ 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-
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-
})
313+
panic::update_hook(move |prev, info| {
314+
let show = BridgeState::with(|state| match state {
315+
BridgeState::NotConnected => true,
316+
BridgeState::Connected(_) | BridgeState::InUse => force_show_panics,
317+
});
318+
if show {
319+
prev(info)
320+
}
323321
});
324322
});
325323

library/std/src/panicking.rs

+23-22
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ enum Hook {
7676
Custom(*mut (dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send)),
7777
}
7878

79+
impl Hook {
80+
fn custom(f: impl Fn(&PanicInfo<'_>) + 'static + Sync + Send) -> Self {
81+
Self::Custom(Box::into_raw(Box::new(f)))
82+
}
83+
}
84+
7985
static HOOK_LOCK: StaticRWLock = StaticRWLock::new();
8086
static mut HOOK: Hook = Hook::Default;
8187

@@ -180,7 +186,8 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
180186
}
181187
}
182188

183-
/// Atomic combination of [`take_hook`] + [`set_hook`].
189+
/// Atomic combination of [`take_hook`] and [`set_hook`]. Use this to replace the panic handler with
190+
/// a new panic handler that does something and then executes the old handler.
184191
///
185192
/// [`take_hook`]: ./fn.take_hook.html
186193
/// [`set_hook`]: ./fn.set_hook.html
@@ -189,16 +196,6 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
189196
///
190197
/// Panics if called from a panicking thread.
191198
///
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-
///
202199
/// # Examples
203200
///
204201
/// The following will print the custom message, and then the normal output of panic.
@@ -207,21 +204,26 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
207204
/// #![feature(panic_update_hook)]
208205
/// use std::panic;
209206
///
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-
/// })
207+
/// // Equivalent to
208+
/// // let prev = panic::take_hook();
209+
/// // panic::set_hook(move |info| {
210+
/// // println!("...");
211+
/// // prev(info);
212+
/// // );
213+
/// panic::update_hook(move |prev, info| {
214+
/// println!("Print custom message and execute panic handler as usual");
215+
/// prev(info);
215216
/// });
216217
///
217218
/// panic!("Custom and then normal");
218219
/// ```
219220
#[unstable(feature = "panic_update_hook", issue = "92649")]
220221
pub fn update_hook<F>(hook_fn: F)
221222
where
222-
F: FnOnce(
223-
Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>,
224-
) -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>,
223+
F: Fn(&(dyn Fn(&PanicInfo<'_>) + Send + Sync + 'static), &PanicInfo<'_>)
224+
+ Sync
225+
+ Send
226+
+ 'static,
225227
{
226228
if thread::panicking() {
227229
panic!("cannot modify the panic hook from a panicking thread");
@@ -232,13 +234,12 @@ where
232234
let old_hook = HOOK;
233235
HOOK = Hook::Default;
234236

235-
let hook_for_fn = match old_hook {
237+
let prev = match old_hook {
236238
Hook::Default => Box::new(default_hook),
237239
Hook::Custom(ptr) => Box::from_raw(ptr),
238240
};
239241

240-
let hook = hook_fn(hook_for_fn);
241-
HOOK = Hook::Custom(Box::into_raw(hook));
242+
HOOK = Hook::custom(move |info| hook_fn(&prev, info));
242243
drop(guard);
243244
}
244245
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// run-pass
2+
// needs-unwind
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::sync::atomic::{AtomicUsize, Ordering};
11+
use std::panic;
12+
use std::thread;
13+
14+
static A: AtomicUsize = AtomicUsize::new(0);
15+
static B: AtomicUsize = AtomicUsize::new(0);
16+
static C: AtomicUsize = AtomicUsize::new(0);
17+
18+
fn main() {
19+
panic::set_hook(Box::new(|_| { A.fetch_add(1, Ordering::SeqCst); }));
20+
panic::update_hook(|prev, info| {
21+
B.fetch_add(1, Ordering::SeqCst);
22+
prev(info);
23+
});
24+
panic::update_hook(|prev, info| {
25+
C.fetch_add(1, Ordering::SeqCst);
26+
prev(info);
27+
});
28+
29+
let _ = thread::spawn(|| {
30+
panic!();
31+
}).join();
32+
33+
assert_eq!(1, A.load(Ordering::SeqCst));
34+
assert_eq!(1, B.load(Ordering::SeqCst));
35+
assert_eq!(1, C.load(Ordering::SeqCst));
36+
}

src/test/ui/panics/panic-while-updating-hook.rs

-16
This file was deleted.

0 commit comments

Comments
 (0)