I am implementing a wrapper of a C library which takes callbacks and the callbacks will be implemented in Rust. Given that panicking in Rust when calling from C is undefined behavior, I want to catch any potential Rust panics before they get into C.
I have been reading about std::panic::catch_unwind
. The wrapper is performance sensitive and I would prefer to avoid using types like Mutex
. I would like to hold my result in an Option<i32>
and set this to Some(value)
in the case where there is no panic. None
will indicate that the function did not execute successfully and thus, a panic must have occurred.
Is Option<i32>
unwind safe? If not, under what conditions would there be a problem? Can I wrap it in std::panic::AssertUnwindSafe
?
Here is an example where I used AssertUnwindSafe
to wrap the entire closure.
use std::panic::{self, AssertUnwindSafe};
fn random_function_that_might_panic(a: i32) -> i32 {
if a == 42 {
panic!("did you forget a towel?");
}
a * 2
}
fn do_not_panic(a: i32) {
let mut result = None;
let unwind_state = panic::catch_unwind(AssertUnwindSafe(|| {
result = Some(random_function_that_might_panic(a)); // get result, but this could panic
}));
match unwind_state {
Ok(()) => {
match result {
Some(value) => {
println!("Result: {:?}", value);
}
None => {
// this should never happen...
println!("No result but no panic?");
}
}
}
Err(e) => {
println!("caught panic: {:?}", e);
}
}
}
fn main() {
do_not_panic(1);
do_not_panic(2);
do_not_panic(3);
do_not_panic(42);
}
(See the above on the playground.)
I could not figure out how to wrap just Option<i32>
in AssertUnwindSafe
, so here I wrapped the whole closure. How would I wrap just the Option<i32>
?