I have a crate that wraps some sensitive code in std::panic::catch_unwind
and then on panic turns that into a normal error that’s usable by the calling program. This works very well and I wanted to go one step further and silence the panic completely to not even throw up stuff on stderr. But as it turns out I can’t do that without affecting global state. If the calling program uses threads I would be silencing panics throughout the app and that’s not a reasonable thing to do in a crate.
Here’s a simple example of that happening:
use std::panic;
use std::thread;
use std::time;
fn main() {
let child = thread::spawn(|| {
panic::set_hook(Box::new(|_info| {
// do nothing to silence panic
}));
thread::sleep(time::Duration::from_secs(5));
// We've set a hook so this panic should not write anything to stderr
match panic::catch_unwind(|| panic!("test")) {
Ok(_) => println!("No panic"),
Err(_) => println!("Caught thread panic"),
};
});
thread::sleep(time::Duration::from_secs(1));
// Here we haven't set a hook so panic should write to stderr but doesn't
// because the hook is global
match panic::catch_unwind(|| panic!("test")) {
Ok(_) => println!("No panic"),
Err(_) => println!("Caught main panic"),
};
child.join().unwrap();
}
Here it is for silencing panic but if you just want extra stuff to be printed on panic the same applies, it’s not possible to do it without affecting the whole program. Ideally what I would want instead would be something like:
-
std::panic::set_thread_hook
: this sets a hook that’s only applicable to the current thread and if set overrides the global hook. It would be nice if you could also set a flag to say that threads that are spawned from this one copy the same hook. -
std::panic::take_thread_hook
: this removes the per-thread hook from the current thread. Other threads that have been spawned since still have the inherited hook and extra calls would need to be done there
Does this make sense? Is it worth it to write a proper RFC?