Should `Backtrace` be RefUnwindSafe?

I'm using the soon-to-be stable std::backtrace::Backtrace in one of my libraries, and noticed that it's currently !RefUnwindSafe. This is ultimately because this gadget contains an UnsafeCell<...> and has unsafe impl Sync but not impl RefUnwindSafe. I'm wondering whether this was perhaps an oversight, and whether we should have Backtrace: RefUnwindSafe after all.

I imagine that it not being RefUnwindSafe makes it very useless, since its very purpose is to report errors.

It probably should, as LazilyResolvedCapture uses interior mutability for a performance optimization that should be invisible to an user. Panics shouldn't cause issues with it, as there is no actual state.

Edit: Created a pull request - Implement RefUnwindSafe for Backtrace by xfix · Pull Request #100455 · rust-lang/rust · GitHub.

1 Like

Thanks!

While we're here, I'm wondering why std::io::Error is !UnwindSafe and !RefUnwindSafe -- it likewise doesn't have any visible mutable state, right? Would it be breaking to have std::io::Error: UnwindSafe + RefUnwindSafe in a future release?

It can wrap any arbitrary error value including one not unwind safe.

1 Like

Ah, right, of course. My mistake!

Sync => RefUnwindSafe, conceptually, and ditto for Send and UnwindSafe [1]. So yeah, if we have the former but not the latter it's a code smell.


  1. fn my_catch_unwind<R, F : FnOnce()> (
       f: F,
    ) -> Result<(), Box<dyn Any + Send>>
    where
       F : Send,
    {
       ::std::thread::scope(|scope| {
           scope.spawn(f).join()
       })
    }
    
    ↩︎
1 Like