-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tracking Issue for panic::update_hook
#92649
Comments
In #92598, I see that proc-macro2 is featured as the real-world motivation for this API. However I don't see how |
Hi @dtolnay, as I understand it, proc-macro2 wants to silence panics inside of a block of code. This is achieved using a custom panic handler that ignores any errors. This panic handler is set using the following code: let null_hook: Box<PanicHook> = Box::new(|_panic_info| { /* ignore */ });
let sanity_check = &*null_hook as *const PanicHook;
let original_hook = panic::take_hook();
panic::set_hook(null_hook);
let works = panic::catch_unwind(proc_macro::Span::call_site).is_ok();
WORKS.store(works as usize + 1, Ordering::Relaxed);
let hopefully_null_hook = panic::take_hook();
panic::set_hook(original_hook);
if sanity_check != &*hopefully_null_hook {
panic!("observed race condition in proc_macro2::inside_proc_macro");
} With panic::update_hook, that code can be simplified to: // Could also use a thread local to silence panics only in this thread
static SILENCE_PANICS: AtomicBool = AtomicBool::new(true);
panic::update_hook(|prev, info| {
if !SILENCE_PANICS.load(Ordering::SeqCst) {
prev(info);
}
});
let works = panic::catch_unwind(proc_macro::Span::call_site).is_ok();
WORKS.store(works as usize + 1, Ordering::Relaxed);
SILENCE_PANICS.store(false, Ordering::SeqCst); It is not ideal because the The only possible race condition is if another thread uses Another alternative that crossed my mind is to make And I was just looking at the tracking issue for |
One use case for this API would be safely inhibiting the default chatty panic hooks in tests that assert that functions should panic. By default, the panic hook prints an error message and an optional backtrace every time a panic happens, irrespective of whether that panic is later caught or not. This is a reasonable design compromise given that it simplifies the implementation and that catching panics is rare, but in tests that exercise panicky code, this results in the emission of hundreds of megabytes of backtraces when As an alternative, I added an Unfortunately, as a code comment in the implementation suggests, this isn't 100% safe in the presence of multi-threaded testing (which is An atomic panic hook replacement function like Alternatively, given that it seems other people are facing the same problem and each coming up with their own solution (see proc-macro2 discussion above), including something like |
Feature gate:
#![feature(panic_update_hook)]
This is a tracking issue for the
panic::update_hook
function.This function allows creating panic hooks that forward the call to the previously set panic hook, without race conditions. It works by taking a closure that receives the old panic hook and the panic info, and it is atomically set as the panic hook by ensuring that during the execution of
panic::update_hook
no other thread can modify the panic hook.This common use case:
Becomes:
Using the old approach is fine if there is some guarantee that there are no other threads trying to change the panic hook. The main goal of this feature is to enable the use case of safely adding panic hooks after the application has been initialized, because the existing functions
panic::set_hook
andpanic::take_hook
are not enough to implement that, consider this case:panic::take_hook()
panic::take_hook()
panic::set_hook()
panic::set_hook()
And the result is that the original panic hook has been lost, as well as the panic hook set by thread A. The resulting panic hook will be the one set by thread B, which forwards to the default panic hook. Using the new
panic::update_hook
function, this race condition is impossible, and the result will be eitherA, B, original
orB, A, original
.Public API
Steps / History
panic::update_hook
#92598Unresolved Questions
panic::set_hook
. An alternative implementation is to take a closure that creates a panic handler, like this (available in commit 8bdf5c3):That approach should be more flexible because it transfers ownership to the closure, but if the outermost closure panics the error message is "panicked while processing panic" which is not nice. This is a consequence of holding the
HOOK_LOCK
while executing the closure. Could be avoided using catch_unwind?The text was updated successfully, but these errors were encountered: