Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 370cab2

Browse files
author
KaiJewson
committedSep 11, 2021
Add std::panic::drop_unwind
1 parent 13db844 commit 370cab2

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed
 

‎library/std/src/panic.rs

+66
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

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

138+
/// Invokes a closure, dropping the cause of an unwinding panic if one occurs.
139+
///
140+
/// Unlike [`catch_unwind`], this function does not return the payload that the
141+
/// closure panicked with if it panics. Instead, the payload is dropped in such
142+
/// a way that avoids propagating panics the payload causes when it is dropped.
143+
/// As such, unlike [`catch_unwind`], you can safely ignore and drop the result
144+
/// of this function without potentially causing the outer function to unwind.
145+
///
146+
/// It is currently undefined behavior to unwind from Rust code into foreign
147+
/// code, so this function is particularly useful when Rust is called from
148+
/// another language (normally C). This can run arbitrary Rust code, capturing a
149+
/// panic and allowing a graceful handling of the error.
150+
///
151+
/// The closure provided is required to adhere to the [`UnwindSafe`] trait to ensure
152+
/// that all captured variables are safe to cross this boundary. The purpose of
153+
/// this bound is to encode the concept of [exception safety][rfc] in the type
154+
/// system. Most usage of this function should not need to worry about this
155+
/// bound as programs are naturally unwind safe without `unsafe` code. If it
156+
/// becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to quickly
157+
/// assert that the usage here is indeed unwind safe.
158+
///
159+
/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
160+
///
161+
/// # Notes
162+
///
163+
/// Note that this function **may not catch all panics** in Rust. A panic in
164+
/// Rust is not always implemented via unwinding, but can be implemented by
165+
/// aborting the process as well. This function *only* catches unwinding panics,
166+
/// not those that abort the process.
167+
///
168+
/// Also note that unwinding into Rust code with a foreign exception (e.g.
169+
/// an exception thrown from C++ code) is undefined behavior.
170+
///
171+
/// # Examples
172+
///
173+
/// ```
174+
/// #![feature(drop_unwind)]
175+
///
176+
/// use std::panic;
177+
///
178+
/// let _ = panic::drop_unwind(|| {
179+
/// panic!("oh no!");
180+
/// });
181+
/// println!("hello!");
182+
/// ```
183+
#[unstable(feature = "drop_unwind", issue = "none")]
184+
pub fn drop_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> core::result::Result<R, ()> {
185+
struct AbortOnDrop;
186+
impl Drop for AbortOnDrop {
187+
fn drop(&mut self) {
188+
crate::process::abort();
189+
}
190+
}
191+
192+
let abort_on_drop = AbortOnDrop;
193+
let res = catch_unwind(f).map_err(drop);
194+
mem::forget(abort_on_drop);
195+
res
196+
}
197+
132198
/// Triggers a panic without invoking the panic hook.
133199
///
134200
/// This is designed to be used in conjunction with [`catch_unwind`] to, for

0 commit comments

Comments
 (0)
Failed to load comments.