Skip to content

Commit

Permalink
Add std::panic::drop_unwind
Browse files Browse the repository at this point in the history
  • Loading branch information
KaiJewson committed Sep 11, 2021
1 parent 13db844 commit 370cab2
Showing 1 changed file with 66 additions and 0 deletions.
66 changes: 66 additions & 0 deletions library/std/src/panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use crate::any::Any;
use crate::collections;
use crate::mem;
use crate::panicking;
use crate::sync::{Mutex, RwLock};
use crate::thread::Result;
Expand Down Expand Up @@ -106,6 +107,11 @@ where
/// aborting the process as well. This function *only* catches unwinding panics,
/// not those that abort the process.
///
/// This function returns the payload that the closure panicked with. Because the payload
/// is allowed to be any type, it is possible for it to be a type that itself panics when
/// dropped. To make sure that badly-behaved panic payloads like these do not cause bugs,
/// use [`drop_unwind`] instead.
///
/// Also note that unwinding into Rust code with a foreign exception (e.g.
/// an exception thrown from C++ code) is undefined behavior.
///
Expand All @@ -129,6 +135,66 @@ pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
unsafe { panicking::r#try(f) }
}

/// Invokes a closure, dropping the cause of an unwinding panic if one occurs.
///
/// Unlike [`catch_unwind`], this function does not return the payload that the
/// closure panicked with if it panics. Instead, the payload is dropped in such
/// a way that avoids propagating panics the payload causes when it is dropped.
/// As such, unlike [`catch_unwind`], you can safely ignore and drop the result
/// of this function without potentially causing the outer function to unwind.
///
/// It is currently undefined behavior to unwind from Rust code into foreign
/// code, so this function is particularly useful when Rust is called from
/// another language (normally C). This can run arbitrary Rust code, capturing a
/// panic and allowing a graceful handling of the error.
///
/// The closure provided is required to adhere to the [`UnwindSafe`] trait to ensure
/// that all captured variables are safe to cross this boundary. The purpose of
/// this bound is to encode the concept of [exception safety][rfc] in the type
/// system. Most usage of this function should not need to worry about this
/// bound as programs are naturally unwind safe without `unsafe` code. If it
/// becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to quickly
/// assert that the usage here is indeed unwind safe.
///
/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
///
/// # Notes
///
/// Note that this function **may not catch all panics** in Rust. A panic in
/// Rust is not always implemented via unwinding, but can be implemented by
/// aborting the process as well. This function *only* catches unwinding panics,
/// not those that abort the process.
///
/// Also note that unwinding into Rust code with a foreign exception (e.g.
/// an exception thrown from C++ code) is undefined behavior.
///
/// # Examples
///
/// ```
/// #![feature(drop_unwind)]
///
/// use std::panic;
///
/// let _ = panic::drop_unwind(|| {
/// panic!("oh no!");
/// });
/// println!("hello!");
/// ```
#[unstable(feature = "drop_unwind", issue = "none")]
pub fn drop_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> core::result::Result<R, ()> {
struct AbortOnDrop;
impl Drop for AbortOnDrop {
fn drop(&mut self) {
crate::process::abort();
}
}

let abort_on_drop = AbortOnDrop;
let res = catch_unwind(f).map_err(drop);
mem::forget(abort_on_drop);
res
}

/// Triggers a panic without invoking the panic hook.
///
/// This is designed to be used in conjunction with [`catch_unwind`] to, for
Expand Down

0 comments on commit 370cab2

Please sign in to comment.