core/panic/
unwind_safe.rs

1use crate::async_iter::AsyncIterator;
2use crate::cell::UnsafeCell;
3use crate::fmt;
4use crate::future::Future;
5use crate::ops::{Deref, DerefMut};
6use crate::pin::Pin;
7use crate::ptr::{NonNull, Unique};
8use crate::task::{Context, Poll};
9
10/// A marker trait which represents "panic safe" types in Rust.
11///
12/// This trait is implemented by default for many types and behaves similarly in
13/// terms of inference of implementation to the [`Send`] and [`Sync`] traits. The
14/// purpose of this trait is to encode what types are safe to cross a [`catch_unwind`]
15/// boundary with no fear of unwind safety.
16///
17/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
18///
19/// ## What is unwind safety?
20///
21/// In Rust a function can "return" early if it either panics or calls a
22/// function which transitively panics. This sort of control flow is not always
23/// anticipated, and has the possibility of causing subtle bugs through a
24/// combination of two critical components:
25///
26/// 1. A data structure is in a temporarily invalid state when the thread
27///    panics.
28/// 2. This broken invariant is then later observed.
29///
30/// Typically in Rust, it is difficult to perform step (2) because catching a
31/// panic involves either spawning a thread (which in turn makes it difficult
32/// to later witness broken invariants) or using the `catch_unwind` function in this
33/// module. Additionally, even if an invariant is witnessed, it typically isn't a
34/// problem in Rust because there are no uninitialized values (like in C or C++).
35///
36/// It is possible, however, for **logical** invariants to be broken in Rust,
37/// which can end up causing behavioral bugs. Another key aspect of unwind safety
38/// in Rust is that, in the absence of `unsafe` code, a panic cannot lead to
39/// memory unsafety.
40///
41/// That was a bit of a whirlwind tour of unwind safety, but for more information
42/// about unwind safety and how it applies to Rust, see an [associated RFC][rfc].
43///
44/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
45///
46/// ## What is `UnwindSafe`?
47///
48/// Now that we've got an idea of what unwind safety is in Rust, it's also
49/// important to understand what this trait represents. As mentioned above, one
50/// way to witness broken invariants is through the `catch_unwind` function in this
51/// module as it allows catching a panic and then re-using the environment of
52/// the closure.
53///
54/// Simply put, a type `T` implements `UnwindSafe` if it cannot easily allow
55/// witnessing a broken invariant through the use of `catch_unwind` (catching a
56/// panic). This trait is an auto trait, so it is automatically implemented for
57/// many types, and it is also structurally composed (e.g., a struct is unwind
58/// safe if all of its components are unwind safe).
59///
60/// Note, however, that this is not an unsafe trait, so there is not a succinct
61/// contract that this trait is providing. Instead it is intended as more of a
62/// "speed bump" to alert users of `catch_unwind` that broken invariants may be
63/// witnessed and may need to be accounted for.
64///
65/// ## Who implements `UnwindSafe`?
66///
67/// Types such as `&mut T` and `&RefCell<T>` are examples which are **not**
68/// unwind safe. The general idea is that any mutable state which can be shared
69/// across `catch_unwind` is not unwind safe by default. This is because it is very
70/// easy to witness a broken invariant outside of `catch_unwind` as the data is
71/// simply accessed as usual.
72///
73/// Types like `&Mutex<T>`, however, are unwind safe because they implement
74/// poisoning by default. They still allow witnessing a broken invariant, but
75/// they already provide their own "speed bumps" to do so.
76///
77/// ## When should `UnwindSafe` be used?
78///
79/// It is not intended that most types or functions need to worry about this trait.
80/// It is only used as a bound on the `catch_unwind` function and as mentioned
81/// above, the lack of `unsafe` means it is mostly an advisory. The
82/// [`AssertUnwindSafe`] wrapper struct can be used to force this trait to be
83/// implemented for any closed over variables passed to `catch_unwind`.
84#[stable(feature = "catch_unwind", since = "1.9.0")]
85#[rustc_diagnostic_item = "unwind_safe_trait"]
86#[diagnostic::on_unimplemented(
87    message = "the type `{Self}` may not be safely transferred across an unwind boundary",
88    label = "`{Self}` may not be safely transferred across an unwind boundary"
89)]
90pub auto trait UnwindSafe {}
91
92/// A marker trait representing types where a shared reference is considered
93/// unwind safe.
94///
95/// This trait is namely not implemented by [`UnsafeCell`], the root of all
96/// interior mutability.
97///
98/// This is a "helper marker trait" used to provide impl blocks for the
99/// [`UnwindSafe`] trait, for more information see that documentation.
100#[stable(feature = "catch_unwind", since = "1.9.0")]
101#[rustc_diagnostic_item = "ref_unwind_safe_trait"]
102#[diagnostic::on_unimplemented(
103    message = "the type `{Self}` may contain interior mutability and a reference may not be safely \
104               transferrable across a catch_unwind boundary",
105    label = "`{Self}` may contain interior mutability and a reference may not be safely \
106             transferrable across a catch_unwind boundary"
107)]
108pub auto trait RefUnwindSafe {}
109
110/// A simple wrapper around a type to assert that it is unwind safe.
111///
112/// When using [`catch_unwind`] it may be the case that some of the closed over
113/// variables are not unwind safe. For example if `&mut T` is captured the
114/// compiler will generate a warning indicating that it is not unwind safe. It
115/// might not be the case, however, that this is actually a problem due to the
116/// specific usage of [`catch_unwind`] if unwind safety is specifically taken into
117/// account. This wrapper struct is useful for a quick and lightweight
118/// annotation that a variable is indeed unwind safe.
119///
120/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
121///
122/// # Examples
123///
124/// One way to use `AssertUnwindSafe` is to assert that the entire closure
125/// itself is unwind safe, bypassing all checks for all variables:
126///
127/// ```
128/// use std::panic::{self, AssertUnwindSafe};
129///
130/// let mut variable = 4;
131///
132/// // This code will not compile because the closure captures `&mut variable`
133/// // which is not considered unwind safe by default.
134///
135/// // panic::catch_unwind(|| {
136/// //     variable += 3;
137/// // });
138///
139/// // This, however, will compile due to the `AssertUnwindSafe` wrapper
140/// let result = panic::catch_unwind(AssertUnwindSafe(|| {
141///     variable += 3;
142/// }));
143/// // ...
144/// ```
145///
146/// Wrapping the entire closure amounts to a blanket assertion that all captured
147/// variables are unwind safe. This has the downside that if new captures are
148/// added in the future, they will also be considered unwind safe. Therefore,
149/// you may prefer to just wrap individual captures, as shown below. This is
150/// more annotation, but it ensures that if a new capture is added which is not
151/// unwind safe, you will get a compilation error at that time, which will
152/// allow you to consider whether that new capture in fact represent a bug or
153/// not.
154///
155/// ```
156/// use std::panic::{self, AssertUnwindSafe};
157///
158/// let mut variable = 4;
159/// let other_capture = 3;
160///
161/// let result = {
162///     let mut wrapper = AssertUnwindSafe(&mut variable);
163///     panic::catch_unwind(move || {
164///         **wrapper += other_capture;
165///     })
166/// };
167/// // ...
168/// ```
169#[stable(feature = "catch_unwind", since = "1.9.0")]
170pub struct AssertUnwindSafe<T>(#[stable(feature = "catch_unwind", since = "1.9.0")] pub T);
171
172// Implementations of the `UnwindSafe` trait:
173//
174// * By default everything is unwind safe
175// * pointers T contains mutability of some form are not unwind safe
176// * Unique, an owning pointer, lifts an implementation
177// * Types like Mutex/RwLock which are explicitly poisoned are unwind safe
178// * Our custom AssertUnwindSafe wrapper is indeed unwind safe
179
180#[stable(feature = "catch_unwind", since = "1.9.0")]
181impl<T: ?Sized> !UnwindSafe for &mut T {}
182#[stable(feature = "catch_unwind", since = "1.9.0")]
183impl<T: RefUnwindSafe + ?Sized> UnwindSafe for &T {}
184#[stable(feature = "catch_unwind", since = "1.9.0")]
185impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {}
186#[stable(feature = "catch_unwind", since = "1.9.0")]
187impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {}
188#[unstable(feature = "ptr_internals", issue = "none")]
189impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {}
190#[stable(feature = "nonnull", since = "1.25.0")]
191impl<T: RefUnwindSafe + ?Sized> UnwindSafe for NonNull<T> {}
192#[stable(feature = "catch_unwind", since = "1.9.0")]
193impl<T> UnwindSafe for AssertUnwindSafe<T> {}
194
195// Pretty simple implementations for the `RefUnwindSafe` marker trait,
196// basically just saying that `UnsafeCell` is the
197// only thing which doesn't implement it (which then transitively applies to
198// everything else).
199#[stable(feature = "catch_unwind", since = "1.9.0")]
200impl<T: ?Sized> !RefUnwindSafe for UnsafeCell<T> {}
201#[stable(feature = "catch_unwind", since = "1.9.0")]
202impl<T> RefUnwindSafe for AssertUnwindSafe<T> {}
203
204#[cfg(target_has_atomic_load_store = "ptr")]
205#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
206impl RefUnwindSafe for crate::sync::atomic::AtomicIsize {}
207#[cfg(target_has_atomic_load_store = "8")]
208#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
209impl RefUnwindSafe for crate::sync::atomic::AtomicI8 {}
210#[cfg(target_has_atomic_load_store = "16")]
211#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
212impl RefUnwindSafe for crate::sync::atomic::AtomicI16 {}
213#[cfg(target_has_atomic_load_store = "32")]
214#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
215impl RefUnwindSafe for crate::sync::atomic::AtomicI32 {}
216#[cfg(target_has_atomic_load_store = "64")]
217#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
218impl RefUnwindSafe for crate::sync::atomic::AtomicI64 {}
219#[cfg(target_has_atomic_load_store = "128")]
220#[unstable(feature = "integer_atomics", issue = "99069")]
221impl RefUnwindSafe for crate::sync::atomic::AtomicI128 {}
222
223#[cfg(target_has_atomic_load_store = "ptr")]
224#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
225impl RefUnwindSafe for crate::sync::atomic::AtomicUsize {}
226#[cfg(target_has_atomic_load_store = "8")]
227#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
228impl RefUnwindSafe for crate::sync::atomic::AtomicU8 {}
229#[cfg(target_has_atomic_load_store = "16")]
230#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
231impl RefUnwindSafe for crate::sync::atomic::AtomicU16 {}
232#[cfg(target_has_atomic_load_store = "32")]
233#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
234impl RefUnwindSafe for crate::sync::atomic::AtomicU32 {}
235#[cfg(target_has_atomic_load_store = "64")]
236#[stable(feature = "integer_atomics_stable", since = "1.34.0")]
237impl RefUnwindSafe for crate::sync::atomic::AtomicU64 {}
238#[cfg(target_has_atomic_load_store = "128")]
239#[unstable(feature = "integer_atomics", issue = "99069")]
240impl RefUnwindSafe for crate::sync::atomic::AtomicU128 {}
241
242#[cfg(target_has_atomic_load_store = "8")]
243#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
244impl RefUnwindSafe for crate::sync::atomic::AtomicBool {}
245
246#[cfg(target_has_atomic_load_store = "ptr")]
247#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
248impl<T> RefUnwindSafe for crate::sync::atomic::AtomicPtr<T> {}
249
250#[stable(feature = "catch_unwind", since = "1.9.0")]
251impl<T> Deref for AssertUnwindSafe<T> {
252    type Target = T;
253
254    fn deref(&self) -> &T {
255        &self.0
256    }
257}
258
259#[stable(feature = "catch_unwind", since = "1.9.0")]
260impl<T> DerefMut for AssertUnwindSafe<T> {
261    fn deref_mut(&mut self) -> &mut T {
262        &mut self.0
263    }
264}
265
266#[stable(feature = "catch_unwind", since = "1.9.0")]
267impl<R, F: FnOnce() -> R> FnOnce<()> for AssertUnwindSafe<F> {
268    type Output = R;
269
270    #[inline]
271    extern "rust-call" fn call_once(self, _args: ()) -> R {
272        (self.0)()
273    }
274}
275
276#[stable(feature = "std_debug", since = "1.16.0")]
277impl<T: fmt::Debug> fmt::Debug for AssertUnwindSafe<T> {
278    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
279        f.debug_tuple("AssertUnwindSafe").field(&self.0).finish()
280    }
281}
282
283#[stable(feature = "assertunwindsafe_default", since = "1.62.0")]
284impl<T: Default> Default for AssertUnwindSafe<T> {
285    fn default() -> Self {
286        Self(Default::default())
287    }
288}
289
290#[stable(feature = "futures_api", since = "1.36.0")]
291impl<F: Future> Future for AssertUnwindSafe<F> {
292    type Output = F::Output;
293
294    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
295        // SAFETY: pin projection. AssertUnwindSafe follows structural pinning.
296        let pinned_field = unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) };
297        F::poll(pinned_field, cx)
298    }
299}
300
301#[unstable(feature = "async_iterator", issue = "79024")]
302impl<S: AsyncIterator> AsyncIterator for AssertUnwindSafe<S> {
303    type Item = S::Item;
304
305    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> {
306        // SAFETY: pin projection. AssertUnwindSafe follows structural pinning.
307        unsafe { self.map_unchecked_mut(|x| &mut x.0) }.poll_next(cx)
308    }
309
310    fn size_hint(&self) -> (usize, Option<usize>) {
311        self.0.size_hint()
312    }
313}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy