1 | //! Panic support in the standard library. |
2 | |
3 | #![stable (feature = "std_panic" , since = "1.9.0" )] |
4 | |
5 | use crate::any::Any; |
6 | use crate::collections; |
7 | use crate::panicking; |
8 | use crate::sync::atomic::{AtomicU8, Ordering}; |
9 | use crate::sync::{Condvar, Mutex, RwLock}; |
10 | use crate::thread::Result; |
11 | |
12 | #[doc (hidden)] |
13 | #[unstable (feature = "edition_panic" , issue = "none" , reason = "use panic!() instead" )] |
14 | #[allow_internal_unstable (libstd_sys_internals, const_format_args, panic_internals, rt)] |
15 | #[cfg_attr (not(test), rustc_diagnostic_item = "std_panic_2015_macro" )] |
16 | #[rustc_macro_transparency = "semitransparent" ] |
17 | pub macro panic_2015 { |
18 | () => ({ |
19 | $crate::rt::begin_panic("explicit panic" ) |
20 | }), |
21 | ($msg:expr $(,)?) => ({ |
22 | $crate::rt::begin_panic($msg); |
23 | }), |
24 | // Special-case the single-argument case for const_panic. |
25 | ("{}" , $arg:expr $(,)?) => ({ |
26 | $crate::rt::panic_display(&$arg); |
27 | }), |
28 | ($fmt:expr, $($arg:tt)+) => ({ |
29 | // Semicolon to prevent temporaries inside the formatting machinery from |
30 | // being considered alive in the caller after the panic_fmt call. |
31 | $crate::rt::panic_fmt($crate::const_format_args!($fmt, $($arg)+)); |
32 | }), |
33 | } |
34 | |
35 | #[doc (hidden)] |
36 | #[unstable (feature = "edition_panic" , issue = "none" , reason = "use panic!() instead" )] |
37 | pub use core::panic::panic_2021; |
38 | |
39 | #[stable (feature = "panic_hooks" , since = "1.10.0" )] |
40 | pub use crate::panicking::{set_hook, take_hook}; |
41 | |
42 | #[unstable (feature = "panic_update_hook" , issue = "92649" )] |
43 | pub use crate::panicking::update_hook; |
44 | |
45 | #[stable (feature = "panic_hooks" , since = "1.10.0" )] |
46 | pub use core::panic::{Location, PanicInfo}; |
47 | |
48 | #[stable (feature = "catch_unwind" , since = "1.9.0" )] |
49 | pub use core::panic::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe}; |
50 | |
51 | /// Panic the current thread with the given message as the panic payload. |
52 | /// |
53 | /// The message can be of any (`Any + Send`) type, not just strings. |
54 | /// |
55 | /// The message is wrapped in a `Box<'static + Any + Send>`, which can be |
56 | /// accessed later using [`PanicInfo::payload`]. |
57 | /// |
58 | /// See the [`panic!`] macro for more information about panicking. |
59 | #[stable (feature = "panic_any" , since = "1.51.0" )] |
60 | #[inline ] |
61 | #[track_caller ] |
62 | pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! { |
63 | crate::panicking::begin_panic(msg); |
64 | } |
65 | |
66 | #[stable (feature = "catch_unwind" , since = "1.9.0" )] |
67 | impl<T: ?Sized> UnwindSafe for Mutex<T> {} |
68 | #[stable (feature = "catch_unwind" , since = "1.9.0" )] |
69 | impl<T: ?Sized> UnwindSafe for RwLock<T> {} |
70 | #[stable (feature = "catch_unwind" , since = "1.9.0" )] |
71 | impl UnwindSafe for Condvar {} |
72 | |
73 | #[stable (feature = "unwind_safe_lock_refs" , since = "1.12.0" )] |
74 | impl<T: ?Sized> RefUnwindSafe for Mutex<T> {} |
75 | #[stable (feature = "unwind_safe_lock_refs" , since = "1.12.0" )] |
76 | impl<T: ?Sized> RefUnwindSafe for RwLock<T> {} |
77 | #[stable (feature = "unwind_safe_lock_refs" , since = "1.12.0" )] |
78 | impl RefUnwindSafe for Condvar {} |
79 | |
80 | // https://github.com/rust-lang/rust/issues/62301 |
81 | #[stable (feature = "hashbrown" , since = "1.36.0" )] |
82 | impl<K, V, S> UnwindSafe for collections::HashMap<K, V, S> |
83 | where |
84 | K: UnwindSafe, |
85 | V: UnwindSafe, |
86 | S: UnwindSafe, |
87 | { |
88 | } |
89 | |
90 | /// Invokes a closure, capturing the cause of an unwinding panic if one occurs. |
91 | /// |
92 | /// This function will return `Ok` with the closure's result if the closure |
93 | /// does not panic, and will return `Err(cause)` if the closure panics. The |
94 | /// `cause` returned is the object with which panic was originally invoked. |
95 | /// |
96 | /// It is currently undefined behavior to unwind from Rust code into foreign |
97 | /// code, so this function is particularly useful when Rust is called from |
98 | /// another language (normally C). This can run arbitrary Rust code, capturing a |
99 | /// panic and allowing a graceful handling of the error. |
100 | /// |
101 | /// It is **not** recommended to use this function for a general try/catch |
102 | /// mechanism. The [`Result`] type is more appropriate to use for functions that |
103 | /// can fail on a regular basis. Additionally, this function is not guaranteed |
104 | /// to catch all panics, see the "Notes" section below. |
105 | /// |
106 | /// The closure provided is required to adhere to the [`UnwindSafe`] trait to ensure |
107 | /// that all captured variables are safe to cross this boundary. The purpose of |
108 | /// this bound is to encode the concept of [exception safety][rfc] in the type |
109 | /// system. Most usage of this function should not need to worry about this |
110 | /// bound as programs are naturally unwind safe without `unsafe` code. If it |
111 | /// becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to quickly |
112 | /// assert that the usage here is indeed unwind safe. |
113 | /// |
114 | /// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md |
115 | /// |
116 | /// # Notes |
117 | /// |
118 | /// Note that this function **might not catch all panics** in Rust. A panic in |
119 | /// Rust is not always implemented via unwinding, but can be implemented by |
120 | /// aborting the process as well. This function *only* catches unwinding panics, |
121 | /// not those that abort the process. |
122 | /// |
123 | /// Note that if a custom panic hook has been set, it will be invoked before |
124 | /// the panic is caught, before unwinding. |
125 | /// |
126 | /// Also note that unwinding into Rust code with a foreign exception (e.g. |
127 | /// an exception thrown from C++ code) is undefined behavior. |
128 | /// |
129 | /// Finally, be **careful in how you drop the result of this function**. |
130 | /// If it is `Err`, it contains the panic payload, and dropping that may in turn panic! |
131 | /// |
132 | /// # Examples |
133 | /// |
134 | /// ``` |
135 | /// use std::panic; |
136 | /// |
137 | /// let result = panic::catch_unwind(|| { |
138 | /// println!("hello!" ); |
139 | /// }); |
140 | /// assert!(result.is_ok()); |
141 | /// |
142 | /// let result = panic::catch_unwind(|| { |
143 | /// panic!("oh no!" ); |
144 | /// }); |
145 | /// assert!(result.is_err()); |
146 | /// ``` |
147 | #[stable (feature = "catch_unwind" , since = "1.9.0" )] |
148 | pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> { |
149 | unsafe { panicking::r#try(f) } |
150 | } |
151 | |
152 | /// Triggers a panic without invoking the panic hook. |
153 | /// |
154 | /// This is designed to be used in conjunction with [`catch_unwind`] to, for |
155 | /// example, carry a panic across a layer of C code. |
156 | /// |
157 | /// # Notes |
158 | /// |
159 | /// Note that panics in Rust are not always implemented via unwinding, but they |
160 | /// may be implemented by aborting the process. If this function is called when |
161 | /// panics are implemented this way then this function will abort the process, |
162 | /// not trigger an unwind. |
163 | /// |
164 | /// # Examples |
165 | /// |
166 | /// ```should_panic |
167 | /// use std::panic; |
168 | /// |
169 | /// let result = panic::catch_unwind(|| { |
170 | /// panic!("oh no!" ); |
171 | /// }); |
172 | /// |
173 | /// if let Err(err) = result { |
174 | /// panic::resume_unwind(err); |
175 | /// } |
176 | /// ``` |
177 | #[stable (feature = "resume_unwind" , since = "1.9.0" )] |
178 | pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! { |
179 | panicking::rust_panic_without_hook(payload) |
180 | } |
181 | |
182 | /// Make all future panics abort directly without running the panic hook or unwinding. |
183 | /// |
184 | /// There is no way to undo this; the effect lasts until the process exits or |
185 | /// execs (or the equivalent). |
186 | /// |
187 | /// # Use after fork |
188 | /// |
189 | /// This function is particularly useful for calling after `libc::fork`. After `fork`, in a |
190 | /// multithreaded program it is (on many platforms) not safe to call the allocator. It is also |
191 | /// generally highly undesirable for an unwind to unwind past the `fork`, because that results in |
192 | /// the unwind propagating to code that was only ever expecting to run in the parent. |
193 | /// |
194 | /// `panic::always_abort()` helps avoid both of these. It directly avoids any further unwinding, |
195 | /// and if there is a panic, the abort will occur without allocating provided that the arguments to |
196 | /// panic can be formatted without allocating. |
197 | /// |
198 | /// Examples |
199 | /// |
200 | /// ```no_run |
201 | /// #![feature(panic_always_abort)] |
202 | /// use std::panic; |
203 | /// |
204 | /// panic::always_abort(); |
205 | /// |
206 | /// let _ = panic::catch_unwind(|| { |
207 | /// panic!("inside the catch" ); |
208 | /// }); |
209 | /// |
210 | /// // We will have aborted already, due to the panic. |
211 | /// unreachable!(); |
212 | /// ``` |
213 | #[unstable (feature = "panic_always_abort" , issue = "84438" )] |
214 | pub fn always_abort() { |
215 | crate::panicking::panic_count::set_always_abort(); |
216 | } |
217 | |
218 | /// The configuration for whether and how the default panic hook will capture |
219 | /// and display the backtrace. |
220 | #[derive (Debug, Copy, Clone, PartialEq, Eq)] |
221 | #[unstable (feature = "panic_backtrace_config" , issue = "93346" )] |
222 | #[non_exhaustive ] |
223 | pub enum BacktraceStyle { |
224 | /// Prints a terser backtrace which ideally only contains relevant |
225 | /// information. |
226 | Short, |
227 | /// Prints a backtrace with all possible information. |
228 | Full, |
229 | /// Disable collecting and displaying backtraces. |
230 | Off, |
231 | } |
232 | |
233 | impl BacktraceStyle { |
234 | pub(crate) fn full() -> Option<Self> { |
235 | if cfg!(feature = "backtrace" ) { Some(BacktraceStyle::Full) } else { None } |
236 | } |
237 | |
238 | fn as_u8(self) -> u8 { |
239 | match self { |
240 | BacktraceStyle::Short => 1, |
241 | BacktraceStyle::Full => 2, |
242 | BacktraceStyle::Off => 3, |
243 | } |
244 | } |
245 | |
246 | fn from_u8(s: u8) -> Option<Self> { |
247 | Some(match s { |
248 | 0 => return None, |
249 | 1 => BacktraceStyle::Short, |
250 | 2 => BacktraceStyle::Full, |
251 | 3 => BacktraceStyle::Off, |
252 | _ => unreachable!(), |
253 | }) |
254 | } |
255 | } |
256 | |
257 | // Tracks whether we should/can capture a backtrace, and how we should display |
258 | // that backtrace. |
259 | // |
260 | // Internally stores equivalent of an Option<BacktraceStyle>. |
261 | static SHOULD_CAPTURE: AtomicU8 = AtomicU8::new(0); |
262 | |
263 | /// Configure whether the default panic hook will capture and display a |
264 | /// backtrace. |
265 | /// |
266 | /// The default value for this setting may be set by the `RUST_BACKTRACE` |
267 | /// environment variable; see the details in [`get_backtrace_style`]. |
268 | #[unstable (feature = "panic_backtrace_config" , issue = "93346" )] |
269 | pub fn set_backtrace_style(style: BacktraceStyle) { |
270 | if !cfg!(feature = "backtrace" ) { |
271 | // If the `backtrace` feature of this crate isn't enabled, skip setting. |
272 | return; |
273 | } |
274 | SHOULD_CAPTURE.store(val:style.as_u8(), order:Ordering::Release); |
275 | } |
276 | |
277 | /// Checks whether the standard library's panic hook will capture and print a |
278 | /// backtrace. |
279 | /// |
280 | /// This function will, if a backtrace style has not been set via |
281 | /// [`set_backtrace_style`], read the environment variable `RUST_BACKTRACE` to |
282 | /// determine a default value for the backtrace formatting: |
283 | /// |
284 | /// The first call to `get_backtrace_style` may read the `RUST_BACKTRACE` |
285 | /// environment variable if `set_backtrace_style` has not been called to |
286 | /// override the default value. After a call to `set_backtrace_style` or |
287 | /// `get_backtrace_style`, any changes to `RUST_BACKTRACE` will have no effect. |
288 | /// |
289 | /// `RUST_BACKTRACE` is read according to these rules: |
290 | /// |
291 | /// * `0` for `BacktraceStyle::Off` |
292 | /// * `full` for `BacktraceStyle::Full` |
293 | /// * `1` for `BacktraceStyle::Short` |
294 | /// * Other values are currently `BacktraceStyle::Short`, but this may change in |
295 | /// the future |
296 | /// |
297 | /// Returns `None` if backtraces aren't currently supported. |
298 | #[unstable (feature = "panic_backtrace_config" , issue = "93346" )] |
299 | pub fn get_backtrace_style() -> Option<BacktraceStyle> { |
300 | if !cfg!(feature = "backtrace" ) { |
301 | // If the `backtrace` feature of this crate isn't enabled quickly return |
302 | // `Unsupported` so this can be constant propagated all over the place |
303 | // to optimize away callers. |
304 | return None; |
305 | } |
306 | if let Some(style) = BacktraceStyle::from_u8(SHOULD_CAPTURE.load(Ordering::Acquire)) { |
307 | return Some(style); |
308 | } |
309 | |
310 | let format = crate::env::var_os("RUST_BACKTRACE" ) |
311 | .map(|x| { |
312 | if &x == "0" { |
313 | BacktraceStyle::Off |
314 | } else if &x == "full" { |
315 | BacktraceStyle::Full |
316 | } else { |
317 | BacktraceStyle::Short |
318 | } |
319 | }) |
320 | .unwrap_or(if crate::sys::FULL_BACKTRACE_DEFAULT { |
321 | BacktraceStyle::Full |
322 | } else { |
323 | BacktraceStyle::Off |
324 | }); |
325 | set_backtrace_style(format); |
326 | Some(format) |
327 | } |
328 | |
329 | #[cfg (test)] |
330 | mod tests; |
331 | |