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