]>
Commit | Line | Data |
---|---|---|
9cc50fc6 SL |
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 | ||
54a0048b | 13 | #![stable(feature = "std_panic", since = "1.9.0")] |
9cc50fc6 SL |
14 | |
15 | use any::Any; | |
16 | use boxed::Box; | |
17 | use cell::UnsafeCell; | |
18 | use ops::{Deref, DerefMut}; | |
19 | use ptr::{Unique, Shared}; | |
20 | use rc::Rc; | |
21 | use sync::{Arc, Mutex, RwLock}; | |
22 | use sys_common::unwind; | |
23 | use thread::Result; | |
24 | ||
54a0048b SL |
25 | #[unstable(feature = "panic_handler", issue = "30449")] |
26 | pub use panicking::{take_hook, set_hook, PanicInfo, Location}; | |
27 | ||
28 | /// | |
29 | #[rustc_deprecated(since = "1.9.0", reason = "renamed to set_hook")] | |
30 | #[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")] | |
31 | pub fn set_handler<F>(handler: F) where F: Fn(&PanicInfo) + 'static + Sync + Send { | |
32 | set_hook(Box::new(handler)) | |
33 | } | |
34 | ||
35 | /// | |
36 | #[rustc_deprecated(since = "1.9.0", reason = "renamed to take_hook")] | |
37 | #[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")] | |
38 | pub fn take_handler() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> { | |
39 | take_hook() | |
40 | } | |
9cc50fc6 SL |
41 | |
42 | /// A marker trait which represents "panic safe" types in Rust. | |
43 | /// | |
44 | /// This trait is implemented by default for many types and behaves similarly in | |
45 | /// terms of inference of implementation to the `Send` and `Sync` traits. The | |
46 | /// purpose of this trait is to encode what types are safe to cross a `recover` | |
47 | /// boundary with no fear of panic safety. | |
48 | /// | |
49 | /// ## What is panic safety? | |
50 | /// | |
51 | /// In Rust a function can "return" early if it either panics or calls a | |
52 | /// function which transitively panics. This sort of control flow is not always | |
53 | /// anticipated, and has the possibility of causing subtle bugs through a | |
54 | /// combination of two cricial components: | |
55 | /// | |
56 | /// 1. A data structure is in a temporarily invalid state when the thread | |
57 | /// panics. | |
58 | /// 2. This broken invariant is then later observed. | |
59 | /// | |
60 | /// Typically in Rust, it is difficult to perform step (2) because catching a | |
61 | /// panic involves either spawning a thread (which in turns makes it difficult | |
62 | /// to later witness broken invariants) or using the `recover` function in this | |
63 | /// module. Additionally, even if an invariant is witnessed, it typically isn't a | |
64 | /// problem in Rust because there's no uninitialized values (like in C or C++). | |
65 | /// | |
66 | /// It is possible, however, for **logical** invariants to be broken in Rust, | |
67 | /// which can end up causing behavioral bugs. Another key aspect of panic safety | |
68 | /// in Rust is that, in the absence of `unsafe` code, a panic cannot lead to | |
69 | /// memory unsafety. | |
70 | /// | |
71 | /// That was a bit of a whirlwind tour of panic safety, but for more information | |
72 | /// about panic safety and how it applies to Rust, see an [associated RFC][rfc]. | |
73 | /// | |
74 | /// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md | |
75 | /// | |
76 | /// ## What is `RecoverSafe`? | |
77 | /// | |
78 | /// Now that we've got an idea of what panic safety is in Rust, it's also | |
79 | /// important to understand what this trait represents. As mentioned above, one | |
80 | /// way to witness broken invariants is through the `recover` function in this | |
81 | /// module as it allows catching a panic and then re-using the environment of | |
82 | /// the closure. | |
83 | /// | |
84 | /// Simply put, a type `T` implements `RecoverSafe` if it cannot easily allow | |
85 | /// witnessing a broken invariant through the use of `recover` (catching a | |
86 | /// panic). This trait is a marker trait, so it is automatically implemented for | |
87 | /// many types, and it is also structurally composed (e.g. a struct is recover | |
88 | /// safe if all of its components are recover safe). | |
89 | /// | |
90 | /// Note, however, that this is not an unsafe trait, so there is not a succinct | |
91 | /// contract that this trait is providing. Instead it is intended as more of a | |
92 | /// "speed bump" to alert users of `recover` that broken invariants may be | |
93 | /// witnessed and may need to be accounted for. | |
94 | /// | |
54a0048b | 95 | /// ## Who implements `UnwindSafe`? |
9cc50fc6 SL |
96 | /// |
97 | /// Types such as `&mut T` and `&RefCell<T>` are examples which are **not** | |
98 | /// recover safe. The general idea is that any mutable state which can be shared | |
99 | /// across `recover` is not recover safe by default. This is because it is very | |
100 | /// easy to witness a broken invariant outside of `recover` as the data is | |
7453a54e | 101 | /// simply accessed as usual. |
9cc50fc6 SL |
102 | /// |
103 | /// Types like `&Mutex<T>`, however, are recover safe because they implement | |
104 | /// poisoning by default. They still allow witnessing a broken invariant, but | |
105 | /// they already provide their own "speed bumps" to do so. | |
106 | /// | |
54a0048b | 107 | /// ## When should `UnwindSafe` be used? |
9cc50fc6 SL |
108 | /// |
109 | /// Is not intended that most types or functions need to worry about this trait. | |
110 | /// It is only used as a bound on the `recover` function and as mentioned above, | |
111 | /// the lack of `unsafe` means it is mostly an advisory. The `AssertRecoverSafe` | |
112 | /// wrapper struct in this module can be used to force this trait to be | |
113 | /// implemented for any closed over variables passed to the `recover` function | |
114 | ||
54a0048b | 115 | #[stable(feature = "catch_unwind", since = "1.9.0")] |
9cc50fc6 SL |
116 | #[rustc_on_unimplemented = "the type {Self} may not be safely transferred \ |
117 | across a recover boundary"] | |
54a0048b SL |
118 | pub trait UnwindSafe {} |
119 | ||
120 | /// Deprecated, renamed to UnwindSafe | |
121 | #[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")] | |
122 | #[rustc_deprecated(reason = "renamed to `UnwindSafe`", since = "1.9.0")] | |
9cc50fc6 | 123 | pub trait RecoverSafe {} |
54a0048b SL |
124 | #[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")] |
125 | #[allow(deprecated)] | |
126 | impl<T: UnwindSafe> RecoverSafe for T {} | |
9cc50fc6 SL |
127 | |
128 | /// A marker trait representing types where a shared reference is considered | |
129 | /// recover safe. | |
130 | /// | |
131 | /// This trait is namely not implemented by `UnsafeCell`, the root of all | |
132 | /// interior mutability. | |
133 | /// | |
134 | /// This is a "helper marker trait" used to provide impl blocks for the | |
54a0048b SL |
135 | /// `UnwindSafe` trait, for more information see that documentation. |
136 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
9cc50fc6 SL |
137 | #[rustc_on_unimplemented = "the type {Self} contains interior mutability \ |
138 | and a reference may not be safely transferrable \ | |
139 | across a recover boundary"] | |
54a0048b | 140 | pub trait RefUnwindSafe {} |
9cc50fc6 SL |
141 | |
142 | /// A simple wrapper around a type to assert that it is panic safe. | |
143 | /// | |
144 | /// When using `recover` it may be the case that some of the closed over | |
145 | /// variables are not panic safe. For example if `&mut T` is captured the | |
146 | /// compiler will generate a warning indicating that it is not panic safe. It | |
147 | /// may not be the case, however, that this is actually a problem due to the | |
148 | /// specific usage of `recover` if panic safety is specifically taken into | |
149 | /// account. This wrapper struct is useful for a quick and lightweight | |
150 | /// annotation that a variable is indeed panic safe. | |
151 | /// | |
152 | /// # Examples | |
153 | /// | |
54a0048b SL |
154 | /// One way to use `AssertUnwindSafe` is to assert that the entire closure |
155 | /// itself is recover safe, bypassing all checks for all variables: | |
9cc50fc6 | 156 | /// |
54a0048b SL |
157 | /// ``` |
158 | /// use std::panic::{self, AssertUnwindSafe}; | |
9cc50fc6 SL |
159 | /// |
160 | /// let mut variable = 4; | |
161 | /// | |
162 | /// // This code will not compile because the closure captures `&mut variable` | |
163 | /// // which is not considered panic safe by default. | |
164 | /// | |
54a0048b | 165 | /// // panic::catch_unwind(|| { |
9cc50fc6 SL |
166 | /// // variable += 3; |
167 | /// // }); | |
168 | /// | |
54a0048b SL |
169 | /// // This, however, will compile due to the `AssertUnwindSafe` wrapper |
170 | /// let result = panic::catch_unwind(AssertUnwindSafe(|| { | |
171 | /// variable += 3; | |
172 | /// })); | |
173 | /// // ... | |
174 | /// ``` | |
175 | /// | |
176 | /// Wrapping the entire closure amounts to a blanket assertion that all captured | |
177 | /// variables are unwind safe. This has the downside that if new captures are | |
178 | /// added in the future, they will also be considered unwind safe. Therefore, | |
179 | /// you may prefer to just wrap individual captures, as shown below. This is | |
180 | /// more annotation, but it ensures that if a new capture is added which is not | |
181 | /// unwind safe, you will get a compilation error at that time, which will | |
182 | /// allow you to consider whether that new capture in fact represent a bug or | |
183 | /// not. | |
184 | /// | |
185 | /// ``` | |
186 | /// use std::panic::{self, AssertUnwindSafe}; | |
187 | /// | |
188 | /// let mut variable = 4; | |
189 | /// let other_capture = 3; | |
190 | /// | |
9cc50fc6 | 191 | /// let result = { |
54a0048b SL |
192 | /// let mut wrapper = AssertUnwindSafe(&mut variable); |
193 | /// panic::catch_unwind(move || { | |
194 | /// **wrapper += other_capture; | |
9cc50fc6 SL |
195 | /// }) |
196 | /// }; | |
197 | /// // ... | |
198 | /// ``` | |
54a0048b SL |
199 | #[stable(feature = "catch_unwind", since = "1.9.0")] |
200 | pub struct AssertUnwindSafe<T>( | |
201 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
202 | pub T | |
203 | ); | |
9cc50fc6 | 204 | |
54a0048b SL |
205 | /// Deprecated, renamed to `AssertUnwindSafe` |
206 | #[unstable(feature = "recover", issue = "27719")] | |
207 | #[rustc_deprecated(reason = "renamed to `AssertUnwindSafe`", since = "1.9.0")] | |
208 | pub struct AssertRecoverSafe<T>(pub T); | |
209 | ||
210 | // Implementations of the `UnwindSafe` trait: | |
9cc50fc6 | 211 | // |
54a0048b SL |
212 | // * By default everything is unwind safe |
213 | // * pointers T contains mutability of some form are not unwind safe | |
9cc50fc6 | 214 | // * Unique, an owning pointer, lifts an implementation |
54a0048b SL |
215 | // * Types like Mutex/RwLock which are explicilty poisoned are unwind safe |
216 | // * Our custom AssertUnwindSafe wrapper is indeed unwind safe | |
217 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
218 | impl UnwindSafe for .. {} | |
219 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
220 | impl<'a, T: ?Sized> !UnwindSafe for &'a mut T {} | |
221 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
222 | impl<'a, T: RefUnwindSafe + ?Sized> UnwindSafe for &'a T {} | |
223 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
224 | impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {} | |
225 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
226 | impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {} | |
227 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
228 | impl<T: UnwindSafe> UnwindSafe for Unique<T> {} | |
229 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
230 | impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Shared<T> {} | |
231 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
232 | impl<T: ?Sized> UnwindSafe for Mutex<T> {} | |
233 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
234 | impl<T: ?Sized> UnwindSafe for RwLock<T> {} | |
235 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
236 | impl<T> UnwindSafe for AssertUnwindSafe<T> {} | |
237 | #[unstable(feature = "recover", issue = "27719")] | |
238 | #[allow(deprecated)] | |
239 | impl<T> UnwindSafe for AssertRecoverSafe<T> {} | |
9cc50fc6 SL |
240 | |
241 | // not covered via the Shared impl above b/c the inner contents use | |
242 | // Cell/AtomicUsize, but the usage here is recover safe so we can lift the | |
243 | // impl up one level to Arc/Rc itself | |
54a0048b SL |
244 | #[stable(feature = "catch_unwind", since = "1.9.0")] |
245 | impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Rc<T> {} | |
246 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
247 | impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Arc<T> {} | |
9cc50fc6 SL |
248 | |
249 | // Pretty simple implementations for the `RefRecoverSafe` marker trait, | |
250 | // basically just saying that this is a marker trait and `UnsafeCell` is the | |
251 | // only thing which doesn't implement it (which then transitively applies to | |
252 | // everything else). | |
54a0048b SL |
253 | #[stable(feature = "catch_unwind", since = "1.9.0")] |
254 | impl RefUnwindSafe for .. {} | |
255 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
256 | impl<T: ?Sized> !RefUnwindSafe for UnsafeCell<T> {} | |
257 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
258 | impl<T> RefUnwindSafe for AssertUnwindSafe<T> {} | |
259 | #[unstable(feature = "recover", issue = "27719")] | |
260 | #[allow(deprecated)] | |
261 | impl<T> RefUnwindSafe for AssertRecoverSafe<T> {} | |
262 | ||
263 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
264 | impl<T> Deref for AssertUnwindSafe<T> { | |
265 | type Target = T; | |
9cc50fc6 | 266 | |
54a0048b SL |
267 | fn deref(&self) -> &T { |
268 | &self.0 | |
269 | } | |
270 | } | |
271 | ||
272 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
273 | impl<T> DerefMut for AssertUnwindSafe<T> { | |
274 | fn deref_mut(&mut self) -> &mut T { | |
275 | &mut self.0 | |
276 | } | |
277 | } | |
278 | ||
279 | #[stable(feature = "catch_unwind", since = "1.9.0")] | |
280 | impl<R, F: FnOnce() -> R> FnOnce<()> for AssertUnwindSafe<F> { | |
281 | type Output = R; | |
282 | ||
283 | extern "rust-call" fn call_once(self, _args: ()) -> R { | |
284 | (self.0)() | |
285 | } | |
286 | } | |
287 | ||
288 | #[allow(deprecated)] | |
9cc50fc6 SL |
289 | impl<T> AssertRecoverSafe<T> { |
290 | /// Creates a new `AssertRecoverSafe` wrapper around the provided type. | |
291 | #[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")] | |
54a0048b SL |
292 | #[rustc_deprecated(reason = "the type's field is now public, construct it directly", |
293 | since = "1.9.0")] | |
9cc50fc6 SL |
294 | pub fn new(t: T) -> AssertRecoverSafe<T> { |
295 | AssertRecoverSafe(t) | |
296 | } | |
7453a54e SL |
297 | |
298 | /// Consumes the `AssertRecoverSafe`, returning the wrapped value. | |
299 | #[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")] | |
54a0048b SL |
300 | #[rustc_deprecated(reason = "the type's field is now public, access it directly", |
301 | since = "1.9.0")] | |
7453a54e SL |
302 | pub fn into_inner(self) -> T { |
303 | self.0 | |
304 | } | |
9cc50fc6 SL |
305 | } |
306 | ||
54a0048b SL |
307 | #[unstable(feature = "recover", issue = "27719")] |
308 | #[allow(deprecated)] | |
9cc50fc6 SL |
309 | impl<T> Deref for AssertRecoverSafe<T> { |
310 | type Target = T; | |
311 | ||
312 | fn deref(&self) -> &T { | |
313 | &self.0 | |
314 | } | |
315 | } | |
316 | ||
54a0048b SL |
317 | #[unstable(feature = "recover", issue = "27719")] |
318 | #[allow(deprecated)] | |
9cc50fc6 SL |
319 | impl<T> DerefMut for AssertRecoverSafe<T> { |
320 | fn deref_mut(&mut self) -> &mut T { | |
321 | &mut self.0 | |
322 | } | |
323 | } | |
324 | ||
54a0048b SL |
325 | #[unstable(feature = "recover", issue = "27719")] |
326 | #[allow(deprecated)] | |
327 | impl<R, F: FnOnce() -> R> FnOnce<()> for AssertRecoverSafe<F> { | |
328 | type Output = R; | |
329 | ||
330 | extern "rust-call" fn call_once(self, _args: ()) -> R { | |
331 | (self.0)() | |
332 | } | |
333 | } | |
334 | ||
335 | /// Invokes a closure, capturing the cause of an unwinding panic if one occurs. | |
9cc50fc6 SL |
336 | /// |
337 | /// This function will return `Ok` with the closure's result if the closure | |
338 | /// does not panic, and will return `Err(cause)` if the closure panics. The | |
339 | /// `cause` returned is the object with which panic was originally invoked. | |
340 | /// | |
341 | /// It is currently undefined behavior to unwind from Rust code into foreign | |
342 | /// code, so this function is particularly useful when Rust is called from | |
343 | /// another language (normally C). This can run arbitrary Rust code, capturing a | |
344 | /// panic and allowing a graceful handling of the error. | |
345 | /// | |
346 | /// It is **not** recommended to use this function for a general try/catch | |
347 | /// mechanism. The `Result` type is more appropriate to use for functions that | |
54a0048b SL |
348 | /// can fail on a regular basis. Additionally, this function is not guaranteed |
349 | /// to catch all panics, see the "Notes" sectino below. | |
350 | /// | |
351 | /// The closure provided is required to adhere to the `UnwindSafe` to ensure | |
352 | /// that all captured variables are safe to cross this boundary. The purpose of | |
353 | /// this bound is to encode the concept of [exception safety][rfc] in the type | |
354 | /// system. Most usage of this function should not need to worry about this | |
355 | /// bound as programs are naturally panic safe without `unsafe` code. If it | |
356 | /// becomes a problem the associated `AssertUnwindSafe` wrapper type in this | |
9cc50fc6 SL |
357 | /// module can be used to quickly assert that the usage here is indeed exception |
358 | /// safe. | |
359 | /// | |
360 | /// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md | |
361 | /// | |
54a0048b SL |
362 | /// # Notes |
363 | /// | |
364 | /// Note that this function **may not catch all panics** in Rust. A panic in | |
365 | /// Rust is not always implemented via unwinding, but can be implemented by | |
366 | /// aborting the process as well. This function *only* catches unwinding panics, | |
367 | /// not those that abort the process. | |
368 | /// | |
9cc50fc6 SL |
369 | /// # Examples |
370 | /// | |
371 | /// ``` | |
9cc50fc6 SL |
372 | /// use std::panic; |
373 | /// | |
54a0048b | 374 | /// let result = panic::catch_unwind(|| { |
9cc50fc6 SL |
375 | /// println!("hello!"); |
376 | /// }); | |
377 | /// assert!(result.is_ok()); | |
378 | /// | |
54a0048b | 379 | /// let result = panic::catch_unwind(|| { |
9cc50fc6 SL |
380 | /// panic!("oh no!"); |
381 | /// }); | |
382 | /// assert!(result.is_err()); | |
383 | /// ``` | |
54a0048b SL |
384 | #[stable(feature = "catch_unwind", since = "1.9.0")] |
385 | pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> { | |
9cc50fc6 SL |
386 | let mut result = None; |
387 | unsafe { | |
388 | let result = &mut result; | |
54a0048b | 389 | unwind::try(move || *result = Some(f()))? |
9cc50fc6 SL |
390 | } |
391 | Ok(result.unwrap()) | |
392 | } | |
393 | ||
54a0048b SL |
394 | /// Deprecated, renamed to `catch_unwind` |
395 | #[unstable(feature = "recover", reason = "awaiting feedback", issue = "27719")] | |
396 | #[rustc_deprecated(reason = "renamed to `catch_unwind`", since = "1.9.0")] | |
397 | pub fn recover<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> { | |
398 | catch_unwind(f) | |
399 | } | |
400 | ||
9cc50fc6 SL |
401 | /// Triggers a panic without invoking the panic handler. |
402 | /// | |
54a0048b SL |
403 | /// This is designed to be used in conjunction with `catch_unwind` to, for |
404 | /// example, carry a panic across a layer of C code. | |
405 | /// | |
406 | /// # Notes | |
407 | /// | |
408 | /// Note that panics in Rust are not always implemented via unwinding, but they | |
409 | /// may be implemented by aborting the process. If this function is called when | |
410 | /// panics are implemented this way then this function will abort the process, | |
411 | /// not trigger an unwind. | |
9cc50fc6 SL |
412 | /// |
413 | /// # Examples | |
414 | /// | |
415 | /// ```should_panic | |
9cc50fc6 SL |
416 | /// use std::panic; |
417 | /// | |
54a0048b | 418 | /// let result = panic::catch_unwind(|| { |
9cc50fc6 SL |
419 | /// panic!("oh no!"); |
420 | /// }); | |
421 | /// | |
422 | /// if let Err(err) = result { | |
54a0048b | 423 | /// panic::resume_unwind(err); |
9cc50fc6 SL |
424 | /// } |
425 | /// ``` | |
54a0048b SL |
426 | #[stable(feature = "resume_unwind", since = "1.9.0")] |
427 | pub fn resume_unwind(payload: Box<Any + Send>) -> ! { | |
428 | unwind::rust_panic(payload) | |
429 | } | |
430 | ||
431 | /// Deprecated, use resume_unwind instead | |
9cc50fc6 | 432 | #[unstable(feature = "panic_propagate", reason = "awaiting feedback", issue = "30752")] |
54a0048b | 433 | #[rustc_deprecated(reason = "renamed to `resume_unwind`", since = "1.9.0")] |
9cc50fc6 | 434 | pub fn propagate(payload: Box<Any + Send>) -> ! { |
54a0048b | 435 | resume_unwind(payload) |
9cc50fc6 | 436 | } |