emk / abort_on_panic-rs

Rust library to intercept panic! from unsafe locations and abort the process (for use with C FFI callbacks)
Creative Commons Zero v1.0 Universal
2 stars 2 forks source link

Process is aborted even if panic isn't from within the abort_on_panic block #2

Open dgrunwald opened 8 years ago

dgrunwald commented 8 years ago
struct S;
impl Drop for S {
    fn drop(&mut self) {
        abort_on_panic! {
            // do nothing
       }
   }
}

fn main() {
    let s = S;
    panic!("Error!")
}
emk commented 8 years ago

Yeah, sadly, there's no obvious way to fix this unless new APIs have been added to Rust since I last looked. But thank you for the report.

In general, abort_on_panic! is mostly used inside Rust routines called from C, or at the very top of a Rust thread.

dgrunwald commented 8 years ago

I'm now using something like this:

struct AbortOnDrop<'a>(pub &'a str);

impl <'a> Drop for AbortOnDrop<'a> {
    fn drop(&mut self) {
        use std::io::Write;
        let _ = writeln!(&mut io::stderr(), "Cannot unwind out of {}", self.0);
        unsafe { libc::abort() }
    }
}

pub fn abort_on_panic<F, T>(location: &str, f: F) -> T
    where F: FnOnce() -> T
{
    let guard = AbortOnDrop(location);
    let ret = f();
    mem::forget(guard);
    ret
}

But that's a pretty major API change. Using a closure seems to be the only way though, in all other cases the user code could bypass the mem::forget call.

emk commented 8 years ago

Interesting. I need to think about that design for a bit. I don't really want to change the API, but maybe I could provide both or find another solution here.

emk commented 8 years ago

In light of the new support for panic = 'abort' in Rust, I'm not sure what the best way to handle more complicated use cases of this crate might be. I'm tempted to leave it as a very simple crate with a limited API for people who need to abort even when the global policy is panic = 'abort'. But I'm open to other suggestions.

If anybody would like to discuss this topic, please comment on this issue.

neachdainn commented 5 years ago

This crate is not entirely obsolete. I have a wrapper around a C library and, because the goal is to provide a safe API, I do not want to require my users deal with the UB of panics crossing the FFI boundary. Also, as a library, I don't have control over panic = 'abort'. This means that I need to do something that is both relatively sane and well-defined if the callback panics - abort.

The solution to this issue is to create a function modeled after catch_unwind but doesn't have the unfortunate exception-safe requirement. This serves as a drop-in replacement for catch_unwind but removes the exception-safe requirement by aborting.

pub fn abort_unwind<F: FnOnce() -> R, R>(f: F) -> R {
    struct Guard;
    impl Drop for Guard {
        fn drop(&mut self) {
            if std::thread::panicking() {
                std::process::abort();
             }
         }
    }

    let _guard = Guard;
    f()
}