Skip to content

Commit 35edcb6

Browse files
committed
update docs for catch_unwind & related funcs
Documentation comments for `catch_unwind` and `thread::join` to indicate new behavioral guarantee when catching a foreign exception.
1 parent 24ed1c1 commit 35edcb6

File tree

3 files changed

+70
-30
lines changed

3 files changed

+70
-30
lines changed

core/src/intrinsics.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -2666,12 +2666,17 @@ extern "rust-intrinsic" {
26662666
///
26672667
/// `catch_fn` must not unwind.
26682668
///
2669-
/// The third argument is a function called if an unwind occurs (both Rust unwinds and foreign
2670-
/// unwinds). This function takes the data pointer and a pointer to the target-specific
2671-
/// exception object that was caught. For more information, see the compiler's source as well as
2672-
/// std's `catch_unwind` implementation.
2669+
/// The third argument is a function called if an unwind occurs (both Rust `panic` and foreign
2670+
/// unwinds). This function takes the data pointer and a pointer to the target- and
2671+
/// runtime-specific exception object that was caught.
26732672
///
2674-
/// The stable version of this intrinsic is `std::panic::catch_unwind`.
2673+
/// Note that in the case of a foreign unwinding operation, the exception object data may not be
2674+
/// safely usable from Rust, and should not be directly exposed via the standard library. To
2675+
/// prevent unsafe access, the library implementation may either abort the process or present an
2676+
/// opaque error type to the user.
2677+
///
2678+
/// For more information, see the compiler's source, as well as the documentation for the stable
2679+
/// version of this intrinsic, `std::panic::catch_unwind`.
26752680
#[rustc_nounwind]
26762681
pub fn catch_unwind(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32;
26772682

std/src/panic.rs

+34-24
Original file line numberDiff line numberDiff line change
@@ -285,45 +285,55 @@ where
285285

286286
/// Invokes a closure, capturing the cause of an unwinding panic if one occurs.
287287
///
288-
/// This function will return `Ok` with the closure's result if the closure
289-
/// does not panic, and will return `Err(cause)` if the closure panics. The
290-
/// `cause` returned is the object with which panic was originally invoked.
288+
/// This function will return `Ok` with the closure's result if the closure does
289+
/// not panic, and will return `Err(cause)` if the closure panics. The `cause`
290+
/// returned is the object with which panic was originally invoked.
291291
///
292-
/// It is currently undefined behavior to unwind from Rust code into foreign
293-
/// code, so this function is particularly useful when Rust is called from
294-
/// another language (normally C). This can run arbitrary Rust code, capturing a
295-
/// panic and allowing a graceful handling of the error.
292+
/// Rust functions that are expected to be called from foreign code that does
293+
/// not support unwinding (such as C compiled with `-fno-exceptions`) should be
294+
/// defined using `extern "C"`, which ensures that if the Rust code panics, it
295+
/// is automatically caught and the process is aborted. If this is the desired
296+
/// behavior, it is not necessary to use `catch_unwind` explicitly. This
297+
/// function should instead be used when more graceful error-handling is needed.
296298
///
297299
/// It is **not** recommended to use this function for a general try/catch
298300
/// mechanism. The [`Result`] type is more appropriate to use for functions that
299301
/// can fail on a regular basis. Additionally, this function is not guaranteed
300302
/// to catch all panics, see the "Notes" section below.
301303
///
302-
/// The closure provided is required to adhere to the [`UnwindSafe`] trait to ensure
303-
/// that all captured variables are safe to cross this boundary. The purpose of
304-
/// this bound is to encode the concept of [exception safety][rfc] in the type
305-
/// system. Most usage of this function should not need to worry about this
306-
/// bound as programs are naturally unwind safe without `unsafe` code. If it
307-
/// becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to quickly
308-
/// assert that the usage here is indeed unwind safe.
304+
/// The closure provided is required to adhere to the [`UnwindSafe`] trait to
305+
/// ensure that all captured variables are safe to cross this boundary. The
306+
/// purpose of this bound is to encode the concept of [exception safety][rfc] in
307+
/// the type system. Most usage of this function should not need to worry about
308+
/// this bound as programs are naturally unwind safe without `unsafe` code. If
309+
/// it becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to
310+
/// quickly assert that the usage here is indeed unwind safe.
309311
///
310312
/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
311313
///
312314
/// # Notes
313315
///
314-
/// Note that this function **might not catch all panics** in Rust. A panic in
315-
/// Rust is not always implemented via unwinding, but can be implemented by
316-
/// aborting the process as well. This function *only* catches unwinding panics,
317-
/// not those that abort the process.
316+
/// This function **might not catch all Rust panics**. A Rust panic is not
317+
/// always implemented via unwinding, but can be implemented by aborting the
318+
/// process as well. This function *only* catches unwinding panics, not those
319+
/// that abort the process.
318320
///
319-
/// Note that if a custom panic hook has been set, it will be invoked before
320-
/// the panic is caught, before unwinding.
321+
/// If a custom panic hook has been set, it will be invoked before the panic is
322+
/// caught, before unwinding.
321323
///
322-
/// Also note that unwinding into Rust code with a foreign exception (e.g.
323-
/// an exception thrown from C++ code) is undefined behavior.
324+
/// Although unwinding into Rust code with a foreign exception (e.g. an
325+
/// exception thrown from C++ code, or a `panic!` in Rust code compiled or
326+
/// linked with a different runtime) via an appropriate ABI (e.g. `"C-unwind"`)
327+
/// is permitted, catching such an exception using this function will have one
328+
/// of two behaviors, and it is unspecified which will occur:
324329
///
325-
/// Finally, be **careful in how you drop the result of this function**.
326-
/// If it is `Err`, it contains the panic payload, and dropping that may in turn panic!
330+
/// * The process aborts, after executing all destructors of `f` and the
331+
/// functions it called.
332+
/// * The function returns a `Result::Err` containing an opaque type.
333+
///
334+
/// Finally, be **careful in how you drop the result of this function**. If it
335+
/// is `Err`, it contains the panic payload, and dropping that may in turn
336+
/// panic!
327337
///
328338
/// # Examples
329339
///

std/src/thread/mod.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,19 @@ impl Builder {
665665
/// println!("{result}");
666666
/// ```
667667
///
668+
/// # Notes
669+
///
670+
/// This function has the same minimal guarantee regarding "foreign" unwinding operations (e.g.
671+
/// an exception thrown from C++ code, or a `panic!` in Rust code compiled or linked with a
672+
/// different runtime) as [`catch_unwind`]; namely, if the thread created with `thread::spawn`
673+
/// unwinds all the way to the root with such an exception, one of two behaviors are possible,
674+
/// and it is unspecified which will occur:
675+
///
676+
/// * The process aborts.
677+
/// * The process does not abort, and [`join`] will return a `Result::Err`
678+
/// containing an opaque type.
679+
///
680+
/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
668681
/// [`channels`]: crate::sync::mpsc
669682
/// [`join`]: JoinHandle::join
670683
/// [`Err`]: crate::result::Result::Err
@@ -1737,7 +1750,7 @@ impl<T> JoinHandle<T> {
17371750
/// operations that happen after `join` returns.
17381751
///
17391752
/// If the associated thread panics, [`Err`] is returned with the parameter given
1740-
/// to [`panic!`].
1753+
/// to [`panic!`] (though see the Notes below).
17411754
///
17421755
/// [`Err`]: crate::result::Result::Err
17431756
/// [atomic memory orderings]: crate::sync::atomic
@@ -1759,6 +1772,18 @@ impl<T> JoinHandle<T> {
17591772
/// }).unwrap();
17601773
/// join_handle.join().expect("Couldn't join on the associated thread");
17611774
/// ```
1775+
///
1776+
/// # Notes
1777+
///
1778+
/// If a "foreign" unwinding operation (e.g. an exception thrown from C++
1779+
/// code, or a `panic!` in Rust code compiled or linked with a different
1780+
/// runtime) unwinds all the way to the thread root, the process may be
1781+
/// aborted; see the Notes on [`thread::spawn`]. If the process is not
1782+
/// aborted, this function will return a `Result::Err` containing an opaque
1783+
/// type.
1784+
///
1785+
/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
1786+
/// [`thread::spawn`]: spawn
17621787
#[stable(feature = "rust1", since = "1.0.0")]
17631788
pub fn join(self) -> Result<T> {
17641789
self.0.join()

0 commit comments

Comments
 (0)