|
| 1 | +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
| 2 | +// file at the top-level directory of this distribution and at |
| 3 | +// http://rust-lang.org/COPYRIGHT. |
| 4 | +// |
| 5 | +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| 6 | +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| 7 | +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| 8 | +// option. This file may not be copied, modified, or distributed |
| 9 | +// except according to those terms. |
| 10 | + |
| 11 | +//! Panic support in the standard library |
| 12 | +
|
| 13 | +#![unstable(feature = "std_panic", reason = "awaiting feedback", |
| 14 | + issue = "27719")] |
| 15 | + |
| 16 | +use cell::UnsafeCell; |
| 17 | +use ops::{Deref, DerefMut}; |
| 18 | +use ptr::{Unique, Shared}; |
| 19 | +use rc::Rc; |
| 20 | +use sync::{Arc, Mutex, RwLock}; |
| 21 | +use sys_common::unwind; |
| 22 | +use thread::Result; |
| 23 | + |
| 24 | +/// A marker trait which represents "panic safe" types in Rust. |
| 25 | +/// |
| 26 | +/// This trait is implemented by default for many types and behaves similarly in |
| 27 | +/// terms of inference of implementation to the `Send` and `Sync` traits. The |
| 28 | +/// purpose of this trait is to encode what types are safe to cross a `recover` |
| 29 | +/// boundary with no fear of panic safety. |
| 30 | +/// |
| 31 | +/// ## What is panic safety? |
| 32 | +/// |
| 33 | +/// In Rust a function can "return" early if it either panics or calls a |
| 34 | +/// function which transitively panics. This sort of control flow is not always |
| 35 | +/// anticipated, and has the possibility of causing subtle bugs through a |
| 36 | +/// combination of two cricial components: |
| 37 | +/// |
| 38 | +/// 1. A data structure is in a temporarily invalid state when the thread |
| 39 | +/// panics. |
| 40 | +/// 2. This broken invariant is then later observed. |
| 41 | +/// |
| 42 | +/// Typically in Rust it is difficult to perform step (2) because catching a |
| 43 | +/// panic involves either spawning a thread (which in turns makes it difficult |
| 44 | +/// to later witness broken invariants) or using the `recover` function in this |
| 45 | +/// module. Additionally, even if an invariant is witness, it typically isn't a |
| 46 | +/// problem in Rust because there's no uninitialized values (like in C or C++). |
| 47 | +/// |
| 48 | +/// It is possible, however, for **logical** invariants to be broken in Rust, |
| 49 | +/// which can end up causing behavioral bugs. Another key aspect of panic safety |
| 50 | +/// in Rust is that in the absence of `unsafe` code, a panic cannot lead to |
| 51 | +/// memory unsafety. |
| 52 | +/// |
| 53 | +/// That was a bit of a whirlwind tour of panic safety, but for more information |
| 54 | +/// about panic safety and how it applies to Rust, see an [associated RFC][rfc]. |
| 55 | +/// |
| 56 | +/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md |
| 57 | +/// |
| 58 | +/// ## What is `RecoverSafe`? |
| 59 | +/// |
| 60 | +/// Now that we've got an idea of what panic safety is in Rust, it's also |
| 61 | +/// important to understand that this trait represents. As mentioned above, one |
| 62 | +/// way to witness broken invariants is through the `recover` function in this |
| 63 | +/// module as it allows catching a panic and then re-using the environment of |
| 64 | +/// the closure. |
| 65 | +/// |
| 66 | +/// Simply but, a type `T` implements `RecoverSafe` if it cannot easily allow |
| 67 | +/// witnessing a broken invariant through the use of `recover` (catching a |
| 68 | +/// panic). This trait is a marker trait, so it is automatically implemented for |
| 69 | +/// many types, and it is also structurally composed (e.g. a struct is recover |
| 70 | +/// safe if all of its components are recover safe). |
| 71 | +/// |
| 72 | +/// Note, however, that this is not an unsafe trait, so there is not a succinct |
| 73 | +/// contract that this trait is providing. Instead it is intended as more of a |
| 74 | +/// "speed bump" to alert users of `recover` that broken invariants may be |
| 75 | +/// witnessed and may need to be accounted for. |
| 76 | +/// |
| 77 | +/// ## Who implements `RecoverSafe`? |
| 78 | +/// |
| 79 | +/// Types such as `&mut T` and `&RefCell<T>` are examples which are **not** |
| 80 | +/// recover safe. The general idea is that any mutable state which can be shared |
| 81 | +/// across `recover` is not recover safe by default. This is because it is very |
| 82 | +/// easy to witness a broken invariant outside of `recover` as the data is |
| 83 | +/// simply accesed as usual. |
| 84 | +/// |
| 85 | +/// Types like `&Mutex<T>`, however, are recover safe because they implement |
| 86 | +/// poisoning by default. They still allow witnessing a broken invariant, but |
| 87 | +/// they already provide their own "speed bumps" to do so. |
| 88 | +/// |
| 89 | +/// ## When should `RecoverSafe` be used? |
| 90 | +/// |
| 91 | +/// Is not intended that most types or functions need to worry about this trait. |
| 92 | +/// It is only used as a bound on the `recover` function and as mentioned above, |
| 93 | +/// the lack of `unsafe` means it is mostly an advisory. The `AssertRecoverSafe` |
| 94 | +/// wrapper struct in this module can be used to force this trait to be |
| 95 | +/// implemented for any closed over variables passed to the `recover` function |
| 96 | +/// (more on this below). |
| 97 | +#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")] |
| 98 | +#[rustc_on_unimplemented = "the type {Self} may not be safely transferred \ |
| 99 | + across a recover boundary"] |
| 100 | +pub trait RecoverSafe {} |
| 101 | + |
| 102 | +/// A marker trait representing types which do not contain an `UnsafeCell` by |
| 103 | +/// value internally. |
| 104 | +/// |
| 105 | +/// This is a "helper marker trait" used to provide impl blocks for the |
| 106 | +/// `RecoverSafe` trait, for more information see that documentation. |
| 107 | +#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")] |
| 108 | +#[rustc_on_unimplemented = "the type {Self} contains interior mutability \ |
| 109 | + and a reference may not be safely transferrable \ |
| 110 | + across a recover boundary"] |
| 111 | +pub trait NoUnsafeCell {} |
| 112 | + |
| 113 | +/// A simple wrapper around a type to assert that it is panic safe. |
| 114 | +/// |
| 115 | +/// When using `recover` it may be the case that some of the closed over |
| 116 | +/// variables are not panic safe. For example if `&mut T` is captured the |
| 117 | +/// compiler will generate a warning indicating that it is not panic safe. It |
| 118 | +/// may not be the case, however, that this is actually a problem due to the |
| 119 | +/// specific usage of `recover` if panic safety is specifically taken into |
| 120 | +/// account. This wrapper struct is useful for a quick and lightweight |
| 121 | +/// annotation that a variable is indeed panic safe. |
| 122 | +/// |
| 123 | +/// # Examples |
| 124 | +/// |
| 125 | +/// ``` |
| 126 | +/// #![feature(recover, std_panic)] |
| 127 | +/// |
| 128 | +/// use std::panic::{self, AssertRecoverSafe}; |
| 129 | +/// |
| 130 | +/// let mut variable = 4; |
| 131 | +/// |
| 132 | +/// // This code will not compile becuause the closure captures `&mut variable` |
| 133 | +/// // which is not considered panic safe by default. |
| 134 | +/// |
| 135 | +/// // panic::recover(|| { |
| 136 | +/// // variable += 3; |
| 137 | +/// // }); |
| 138 | +/// |
| 139 | +/// // This, however, will compile due to the `AssertRecoverSafe` wrapper |
| 140 | +/// let result = { |
| 141 | +/// let mut wrapper = AssertRecoverSafe::new(&mut variable); |
| 142 | +/// panic::recover(move || { |
| 143 | +/// **wrapper += 3; |
| 144 | +/// }) |
| 145 | +/// }; |
| 146 | +/// // ... |
| 147 | +/// ``` |
| 148 | +#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")] |
| 149 | +pub struct AssertRecoverSafe<T>(T); |
| 150 | + |
| 151 | +// Implementations of the `RecoverSafe` trait: |
| 152 | +// |
| 153 | +// * By default everything is recover safe |
| 154 | +// * pointers T contains mutability of some form are not recover safe |
| 155 | +// * Unique, an owning pointer, lifts an implementation |
| 156 | +// * Types like Mutex/RwLock which are explicilty poisoned are recover safe |
| 157 | +// * Our custom AssertRecoverSafe wrapper is indeed recover safe |
| 158 | +impl RecoverSafe for .. {} |
| 159 | +impl<'a, T: ?Sized> !RecoverSafe for &'a mut T {} |
| 160 | +impl<'a, T: NoUnsafeCell + ?Sized> RecoverSafe for &'a T {} |
| 161 | +impl<T: NoUnsafeCell + ?Sized> RecoverSafe for *const T {} |
| 162 | +impl<T: NoUnsafeCell + ?Sized> RecoverSafe for *mut T {} |
| 163 | +impl<T: RecoverSafe> RecoverSafe for Unique<T> {} |
| 164 | +impl<T: NoUnsafeCell + ?Sized> RecoverSafe for Shared<T> {} |
| 165 | +impl<T: ?Sized> RecoverSafe for Mutex<T> {} |
| 166 | +impl<T: ?Sized> RecoverSafe for RwLock<T> {} |
| 167 | +impl<T> RecoverSafe for AssertRecoverSafe<T> {} |
| 168 | + |
| 169 | +// not covered via the Shared impl above b/c the inner contents use |
| 170 | +// Cell/AtomicUsize, but the usage here is recover safe so we can lift the |
| 171 | +// impl up one level to Arc/Rc itself |
| 172 | +impl<T: NoUnsafeCell + ?Sized> RecoverSafe for Rc<T> {} |
| 173 | +impl<T: NoUnsafeCell + ?Sized> RecoverSafe for Arc<T> {} |
| 174 | + |
| 175 | +// Pretty simple implementations for the `NoUnsafeCell` marker trait, basically |
| 176 | +// just saying that this is a marker trait and `UnsafeCell` is the only thing |
| 177 | +// which doesn't implement it (which then transitively applies to everything |
| 178 | +// else. |
| 179 | +impl NoUnsafeCell for .. {} |
| 180 | +impl<T: ?Sized> !NoUnsafeCell for UnsafeCell<T> {} |
| 181 | + |
| 182 | +impl<T> AssertRecoverSafe<T> { |
| 183 | + /// Creates a new `AssertRecoverSafe` wrapper around the provided type. |
| 184 | + #[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")] |
| 185 | + pub fn new(t: T) -> AssertRecoverSafe<T> { |
| 186 | + AssertRecoverSafe(t) |
| 187 | + } |
| 188 | +} |
| 189 | + |
| 190 | +impl<T> Deref for AssertRecoverSafe<T> { |
| 191 | + type Target = T; |
| 192 | + |
| 193 | + fn deref(&self) -> &T { |
| 194 | + &self.0 |
| 195 | + } |
| 196 | +} |
| 197 | + |
| 198 | +impl<T> DerefMut for AssertRecoverSafe<T> { |
| 199 | + fn deref_mut(&mut self) -> &mut T { |
| 200 | + &mut self.0 |
| 201 | + } |
| 202 | +} |
| 203 | + |
| 204 | +/// Invokes a closure, capturing the cause of panic if one occurs. |
| 205 | +/// |
| 206 | +/// This function will return `Ok` with the closure's result if the closure |
| 207 | +/// does not panic, and will return `Err(cause)` if the closure panics. The |
| 208 | +/// `cause` returned is the object with which panic was originally invoked. |
| 209 | +/// |
| 210 | +/// It is currently undefined behavior to unwind from Rust code into foreign |
| 211 | +/// code, so this function is particularly useful when Rust is called from |
| 212 | +/// another language (normally C). This can run arbitrary Rust code, capturing a |
| 213 | +/// panic and allowing a graceful handling of the error. |
| 214 | +/// |
| 215 | +/// It is **not** recommended to use this function for a general try/catch |
| 216 | +/// mechanism. The `Result` type is more appropriate to use for functions that |
| 217 | +/// can fail on a regular basis. |
| 218 | +/// |
| 219 | +/// The closure provided is required to adhere to the `RecoverSafe` to ensure |
| 220 | +/// that all captured variables are safe to cross this recover boundary. The |
| 221 | +/// purpose of this bound is to encode the concept of [exception safety][rfc] in |
| 222 | +/// the type system. Most usage of this function should not need to worry about |
| 223 | +/// this bound as programs are naturally panic safe without `unsafe` code. If it |
| 224 | +/// becomes a problem the associated `AssertRecoverSafe` wrapper type in this |
| 225 | +/// module can be used to quickly assert that the usage here is indeed exception |
| 226 | +/// safe. |
| 227 | +/// |
| 228 | +/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md |
| 229 | +/// |
| 230 | +/// # Examples |
| 231 | +/// |
| 232 | +/// ``` |
| 233 | +/// #![feature(recover, std_panic)] |
| 234 | +/// |
| 235 | +/// use std::panic; |
| 236 | +/// |
| 237 | +/// let result = panic::recover(|| { |
| 238 | +/// println!("hello!"); |
| 239 | +/// }); |
| 240 | +/// assert!(result.is_ok()); |
| 241 | +/// |
| 242 | +/// let result = panic::recover(|| { |
| 243 | +/// panic!("oh no!"); |
| 244 | +/// }); |
| 245 | +/// assert!(result.is_err()); |
| 246 | +/// ``` |
| 247 | +#[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")] |
| 248 | +pub fn recover<F: FnOnce() -> R + RecoverSafe, R>(f: F) -> Result<R> { |
| 249 | + let mut result = None; |
| 250 | + unsafe { |
| 251 | + let result = &mut result; |
| 252 | + try!(unwind::try(move || *result = Some(f()))) |
| 253 | + } |
| 254 | + Ok(result.unwrap()) |
| 255 | +} |
0 commit comments