std/
panic.rs

1//! Panic support in the standard library.
2
3#![stable(feature = "std_panic", since = "1.9.0")]
4
5use crate::any::Any;
6use crate::sync::atomic::{AtomicU8, Ordering};
7use crate::sync::{Condvar, Mutex, RwLock};
8use crate::thread::Result;
9use crate::{collections, fmt, panicking};
10
11#[stable(feature = "panic_hooks", since = "1.10.0")]
12#[deprecated(
13    since = "1.82.0",
14    note = "use `PanicHookInfo` instead",
15    suggestion = "std::panic::PanicHookInfo"
16)]
17/// A struct providing information about a panic.
18///
19/// `PanicInfo` has been renamed to [`PanicHookInfo`] to avoid confusion with
20/// [`core::panic::PanicInfo`].
21pub type PanicInfo<'a> = PanicHookInfo<'a>;
22
23/// A struct providing information about a panic.
24///
25/// `PanicHookInfo` structure is passed to a panic hook set by the [`set_hook`] function.
26///
27/// # Examples
28///
29/// ```should_panic
30/// use std::panic;
31///
32/// panic::set_hook(Box::new(|panic_info| {
33///     println!("panic occurred: {panic_info}");
34/// }));
35///
36/// panic!("critical system failure");
37/// ```
38///
39/// [`set_hook`]: ../../std/panic/fn.set_hook.html
40#[stable(feature = "panic_hook_info", since = "1.81.0")]
41#[derive(Debug)]
42pub struct PanicHookInfo<'a> {
43    payload: &'a (dyn Any + Send),
44    location: &'a Location<'a>,
45    can_unwind: bool,
46    force_no_backtrace: bool,
47}
48
49impl<'a> PanicHookInfo<'a> {
50    #[inline]
51    pub(crate) fn new(
52        location: &'a Location<'a>,
53        payload: &'a (dyn Any + Send),
54        can_unwind: bool,
55        force_no_backtrace: bool,
56    ) -> Self {
57        PanicHookInfo { payload, location, can_unwind, force_no_backtrace }
58    }
59
60    /// Returns the payload associated with the panic.
61    ///
62    /// This will commonly, but not always, be a `&'static str` or [`String`].
63    ///
64    /// A invocation of the `panic!()` macro in Rust 2021 or later will always result in a
65    /// panic payload of type `&'static str` or `String`.
66    ///
67    /// Only an invocation of [`panic_any`]
68    /// (or, in Rust 2018 and earlier, `panic!(x)` where `x` is something other than a string)
69    /// can result in a panic payload other than a `&'static str` or `String`.
70    ///
71    /// [`String`]: ../../std/string/struct.String.html
72    ///
73    /// # Examples
74    ///
75    /// ```should_panic
76    /// use std::panic;
77    ///
78    /// panic::set_hook(Box::new(|panic_info| {
79    ///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
80    ///         println!("panic occurred: {s:?}");
81    ///     } else if let Some(s) = panic_info.payload().downcast_ref::<String>() {
82    ///         println!("panic occurred: {s:?}");
83    ///     } else {
84    ///         println!("panic occurred");
85    ///     }
86    /// }));
87    ///
88    /// panic!("Normal panic");
89    /// ```
90    #[must_use]
91    #[inline]
92    #[stable(feature = "panic_hooks", since = "1.10.0")]
93    pub fn payload(&self) -> &(dyn Any + Send) {
94        self.payload
95    }
96
97    /// Returns the payload associated with the panic, if it is a string.
98    ///
99    /// This returns the payload if it is of type `&'static str` or `String`.
100    ///
101    /// A invocation of the `panic!()` macro in Rust 2021 or later will always result in a
102    /// panic payload where `payload_as_str` returns `Some`.
103    ///
104    /// Only an invocation of [`panic_any`]
105    /// (or, in Rust 2018 and earlier, `panic!(x)` where `x` is something other than a string)
106    /// can result in a panic payload where `payload_as_str` returns `None`.
107    ///
108    /// # Example
109    ///
110    /// ```should_panic
111    /// #![feature(panic_payload_as_str)]
112    ///
113    /// std::panic::set_hook(Box::new(|panic_info| {
114    ///     if let Some(s) = panic_info.payload_as_str() {
115    ///         println!("panic occurred: {s:?}");
116    ///     } else {
117    ///         println!("panic occurred");
118    ///     }
119    /// }));
120    ///
121    /// panic!("Normal panic");
122    /// ```
123    #[must_use]
124    #[inline]
125    #[unstable(feature = "panic_payload_as_str", issue = "125175")]
126    pub fn payload_as_str(&self) -> Option<&str> {
127        if let Some(s) = self.payload.downcast_ref::<&str>() {
128            Some(s)
129        } else if let Some(s) = self.payload.downcast_ref::<String>() {
130            Some(s)
131        } else {
132            None
133        }
134    }
135
136    /// Returns information about the location from which the panic originated,
137    /// if available.
138    ///
139    /// This method will currently always return [`Some`], but this may change
140    /// in future versions.
141    ///
142    /// # Examples
143    ///
144    /// ```should_panic
145    /// use std::panic;
146    ///
147    /// panic::set_hook(Box::new(|panic_info| {
148    ///     if let Some(location) = panic_info.location() {
149    ///         println!("panic occurred in file '{}' at line {}",
150    ///             location.file(),
151    ///             location.line(),
152    ///         );
153    ///     } else {
154    ///         println!("panic occurred but can't get location information...");
155    ///     }
156    /// }));
157    ///
158    /// panic!("Normal panic");
159    /// ```
160    #[must_use]
161    #[inline]
162    #[stable(feature = "panic_hooks", since = "1.10.0")]
163    pub fn location(&self) -> Option<&Location<'_>> {
164        // NOTE: If this is changed to sometimes return None,
165        // deal with that case in std::panicking::default_hook and core::panicking::panic_fmt.
166        Some(&self.location)
167    }
168
169    /// Returns whether the panic handler is allowed to unwind the stack from
170    /// the point where the panic occurred.
171    ///
172    /// This is true for most kinds of panics with the exception of panics
173    /// caused by trying to unwind out of a `Drop` implementation or a function
174    /// whose ABI does not support unwinding.
175    ///
176    /// It is safe for a panic handler to unwind even when this function returns
177    /// false, however this will simply cause the panic handler to be called
178    /// again.
179    #[must_use]
180    #[inline]
181    #[unstable(feature = "panic_can_unwind", issue = "92988")]
182    pub fn can_unwind(&self) -> bool {
183        self.can_unwind
184    }
185
186    #[unstable(
187        feature = "panic_internals",
188        reason = "internal details of the implementation of the `panic!` and related macros",
189        issue = "none"
190    )]
191    #[doc(hidden)]
192    #[inline]
193    pub fn force_no_backtrace(&self) -> bool {
194        self.force_no_backtrace
195    }
196}
197
198#[stable(feature = "panic_hook_display", since = "1.26.0")]
199impl fmt::Display for PanicHookInfo<'_> {
200    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
201        formatter.write_str("panicked at ")?;
202        self.location.fmt(formatter)?;
203        if let Some(payload) = self.payload_as_str() {
204            formatter.write_str(":\n")?;
205            formatter.write_str(payload)?;
206        }
207        Ok(())
208    }
209}
210
211#[doc(hidden)]
212#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
213#[allow_internal_unstable(libstd_sys_internals, const_format_args, panic_internals, rt)]
214#[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")]
215#[rustc_macro_transparency = "semitransparent"]
216pub macro panic_2015 {
217    () => ({
218        $crate::rt::begin_panic("explicit panic")
219    }),
220    ($msg:expr $(,)?) => ({
221        $crate::rt::begin_panic($msg);
222    }),
223    // Special-case the single-argument case for const_panic.
224    ("{}", $arg:expr $(,)?) => ({
225        $crate::rt::panic_display(&$arg);
226    }),
227    ($fmt:expr, $($arg:tt)+) => ({
228        // Semicolon to prevent temporaries inside the formatting machinery from
229        // being considered alive in the caller after the panic_fmt call.
230        $crate::rt::panic_fmt($crate::const_format_args!($fmt, $($arg)+));
231    }),
232}
233
234#[stable(feature = "panic_hooks", since = "1.10.0")]
235pub use core::panic::Location;
236#[doc(hidden)]
237#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
238pub use core::panic::panic_2021;
239#[stable(feature = "catch_unwind", since = "1.9.0")]
240pub use core::panic::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe};
241
242#[unstable(feature = "panic_update_hook", issue = "92649")]
243pub use crate::panicking::update_hook;
244#[stable(feature = "panic_hooks", since = "1.10.0")]
245pub use crate::panicking::{set_hook, take_hook};
246
247/// Panics the current thread with the given message as the panic payload.
248///
249/// The message can be of any (`Any + Send`) type, not just strings.
250///
251/// The message is wrapped in a `Box<'static + Any + Send>`, which can be
252/// accessed later using [`PanicHookInfo::payload`].
253///
254/// See the [`panic!`] macro for more information about panicking.
255#[stable(feature = "panic_any", since = "1.51.0")]
256#[inline]
257#[track_caller]
258#[cfg_attr(not(test), rustc_diagnostic_item = "panic_any")]
259pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
260    crate::panicking::begin_panic(msg);
261}
262
263#[stable(feature = "catch_unwind", since = "1.9.0")]
264impl<T: ?Sized> UnwindSafe for Mutex<T> {}
265#[stable(feature = "catch_unwind", since = "1.9.0")]
266impl<T: ?Sized> UnwindSafe for RwLock<T> {}
267#[stable(feature = "catch_unwind", since = "1.9.0")]
268impl UnwindSafe for Condvar {}
269
270#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")]
271impl<T: ?Sized> RefUnwindSafe for Mutex<T> {}
272#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")]
273impl<T: ?Sized> RefUnwindSafe for RwLock<T> {}
274#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")]
275impl RefUnwindSafe for Condvar {}
276
277// https://github.com/rust-lang/rust/issues/62301
278#[stable(feature = "hashbrown", since = "1.36.0")]
279impl<K, V, S> UnwindSafe for collections::HashMap<K, V, S>
280where
281    K: UnwindSafe,
282    V: UnwindSafe,
283    S: UnwindSafe,
284{
285}
286
287#[unstable(feature = "abort_unwind", issue = "130338")]
288pub use core::panic::abort_unwind;
289
290/// Invokes a closure, capturing the cause of an unwinding panic if one occurs.
291///
292/// This function will return `Ok` with the closure's result if the closure does
293/// not panic, and will return `Err(cause)` if the closure panics. The `cause`
294/// returned is the object with which panic was originally invoked.
295///
296/// Rust functions that are expected to be called from foreign code that does
297/// not support unwinding (such as C compiled with `-fno-exceptions`) should be
298/// defined using `extern "C"`, which ensures that if the Rust code panics, it
299/// is automatically caught and the process is aborted. If this is the desired
300/// behavior, it is not necessary to use `catch_unwind` explicitly. This
301/// function should instead be used when more graceful error-handling is needed.
302///
303/// It is **not** recommended to use this function for a general try/catch
304/// mechanism. The [`Result`] type is more appropriate to use for functions that
305/// can fail on a regular basis. Additionally, this function is not guaranteed
306/// to catch all panics, see the "Notes" section below.
307///
308/// The closure provided is required to adhere to the [`UnwindSafe`] trait to
309/// ensure that all captured variables are safe to cross this boundary. The
310/// purpose of this bound is to encode the concept of [exception safety][rfc] in
311/// the type system. Most usage of this function should not need to worry about
312/// this bound as programs are naturally unwind safe without `unsafe` code. If
313/// it becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to
314/// quickly assert that the usage here is indeed unwind safe.
315///
316/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
317///
318/// # Notes
319///
320/// This function **might not catch all Rust panics**. A Rust panic is not
321/// always implemented via unwinding, but can be implemented by aborting the
322/// process as well. This function *only* catches unwinding panics, not those
323/// that abort the process.
324///
325/// If a custom panic hook has been set, it will be invoked before the panic is
326/// caught, before unwinding.
327///
328/// Although unwinding into Rust code with a foreign exception (e.g. an
329/// exception thrown from C++ code, or a `panic!` in Rust code compiled or
330/// linked with a different runtime) via an appropriate ABI (e.g. `"C-unwind"`)
331/// is permitted, catching such an exception using this function will have one
332/// of two behaviors, and it is unspecified which will occur:
333///
334/// * The process aborts, after executing all destructors of `f` and the
335///   functions it called.
336/// * The function returns a `Result::Err` containing an opaque type.
337///
338/// Finally, be **careful in how you drop the result of this function**. If it
339/// is `Err`, it contains the panic payload, and dropping that may in turn
340/// panic!
341///
342/// # Examples
343///
344/// ```
345/// use std::panic;
346///
347/// let result = panic::catch_unwind(|| {
348///     println!("hello!");
349/// });
350/// assert!(result.is_ok());
351///
352/// let result = panic::catch_unwind(|| {
353///     panic!("oh no!");
354/// });
355/// assert!(result.is_err());
356/// ```
357#[stable(feature = "catch_unwind", since = "1.9.0")]
358pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
359    unsafe { panicking::r#try(f) }
360}
361
362/// Triggers a panic without invoking the panic hook.
363///
364/// This is designed to be used in conjunction with [`catch_unwind`] to, for
365/// example, carry a panic across a layer of C code.
366///
367/// # Notes
368///
369/// Note that panics in Rust are not always implemented via unwinding, but they
370/// may be implemented by aborting the process. If this function is called when
371/// panics are implemented this way then this function will abort the process,
372/// not trigger an unwind.
373///
374/// # Examples
375///
376/// ```should_panic
377/// use std::panic;
378///
379/// let result = panic::catch_unwind(|| {
380///     if 1 != 2 {
381///         panic!("oh no!");
382///     }
383/// });
384///
385/// if let Err(err) = result {
386///     panic::resume_unwind(err);
387/// }
388/// ```
389#[stable(feature = "resume_unwind", since = "1.9.0")]
390pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
391    panicking::rust_panic_without_hook(payload)
392}
393
394/// Makes all future panics abort directly without running the panic hook or unwinding.
395///
396/// There is no way to undo this; the effect lasts until the process exits or
397/// execs (or the equivalent).
398///
399/// # Use after fork
400///
401/// This function is particularly useful for calling after `libc::fork`.  After `fork`, in a
402/// multithreaded program it is (on many platforms) not safe to call the allocator.  It is also
403/// generally highly undesirable for an unwind to unwind past the `fork`, because that results in
404/// the unwind propagating to code that was only ever expecting to run in the parent.
405///
406/// `panic::always_abort()` helps avoid both of these.  It directly avoids any further unwinding,
407/// and if there is a panic, the abort will occur without allocating provided that the arguments to
408/// panic can be formatted without allocating.
409///
410/// Examples
411///
412/// ```no_run
413/// #![feature(panic_always_abort)]
414/// use std::panic;
415///
416/// panic::always_abort();
417///
418/// let _ = panic::catch_unwind(|| {
419///     panic!("inside the catch");
420/// });
421///
422/// // We will have aborted already, due to the panic.
423/// unreachable!();
424/// ```
425#[unstable(feature = "panic_always_abort", issue = "84438")]
426pub fn always_abort() {
427    crate::panicking::panic_count::set_always_abort();
428}
429
430/// The configuration for whether and how the default panic hook will capture
431/// and display the backtrace.
432#[derive(Debug, Copy, Clone, PartialEq, Eq)]
433#[unstable(feature = "panic_backtrace_config", issue = "93346")]
434#[non_exhaustive]
435pub enum BacktraceStyle {
436    /// Prints a terser backtrace which ideally only contains relevant
437    /// information.
438    Short,
439    /// Prints a backtrace with all possible information.
440    Full,
441    /// Disable collecting and displaying backtraces.
442    Off,
443}
444
445impl BacktraceStyle {
446    pub(crate) fn full() -> Option<Self> {
447        if cfg!(feature = "backtrace") { Some(BacktraceStyle::Full) } else { None }
448    }
449
450    fn as_u8(self) -> u8 {
451        match self {
452            BacktraceStyle::Short => 1,
453            BacktraceStyle::Full => 2,
454            BacktraceStyle::Off => 3,
455        }
456    }
457
458    fn from_u8(s: u8) -> Option<Self> {
459        match s {
460            1 => Some(BacktraceStyle::Short),
461            2 => Some(BacktraceStyle::Full),
462            3 => Some(BacktraceStyle::Off),
463            _ => None,
464        }
465    }
466}
467
468// Tracks whether we should/can capture a backtrace, and how we should display
469// that backtrace.
470//
471// Internally stores equivalent of an Option<BacktraceStyle>.
472static SHOULD_CAPTURE: AtomicU8 = AtomicU8::new(0);
473
474/// Configures whether the default panic hook will capture and display a
475/// backtrace.
476///
477/// The default value for this setting may be set by the `RUST_BACKTRACE`
478/// environment variable; see the details in [`get_backtrace_style`].
479#[unstable(feature = "panic_backtrace_config", issue = "93346")]
480pub fn set_backtrace_style(style: BacktraceStyle) {
481    if cfg!(feature = "backtrace") {
482        // If the `backtrace` feature of this crate is enabled, set the backtrace style.
483        SHOULD_CAPTURE.store(style.as_u8(), Ordering::Relaxed);
484    }
485}
486
487/// Checks whether the standard library's panic hook will capture and print a
488/// backtrace.
489///
490/// This function will, if a backtrace style has not been set via
491/// [`set_backtrace_style`], read the environment variable `RUST_BACKTRACE` to
492/// determine a default value for the backtrace formatting:
493///
494/// The first call to `get_backtrace_style` may read the `RUST_BACKTRACE`
495/// environment variable if `set_backtrace_style` has not been called to
496/// override the default value. After a call to `set_backtrace_style` or
497/// `get_backtrace_style`, any changes to `RUST_BACKTRACE` will have no effect.
498///
499/// `RUST_BACKTRACE` is read according to these rules:
500///
501/// * `0` for `BacktraceStyle::Off`
502/// * `full` for `BacktraceStyle::Full`
503/// * `1` for `BacktraceStyle::Short`
504/// * Other values are currently `BacktraceStyle::Short`, but this may change in
505///   the future
506///
507/// Returns `None` if backtraces aren't currently supported.
508#[unstable(feature = "panic_backtrace_config", issue = "93346")]
509pub fn get_backtrace_style() -> Option<BacktraceStyle> {
510    if !cfg!(feature = "backtrace") {
511        // If the `backtrace` feature of this crate isn't enabled quickly return
512        // `Unsupported` so this can be constant propagated all over the place
513        // to optimize away callers.
514        return None;
515    }
516
517    let current = SHOULD_CAPTURE.load(Ordering::Relaxed);
518    if let Some(style) = BacktraceStyle::from_u8(current) {
519        return Some(style);
520    }
521
522    let format = match crate::env::var_os("RUST_BACKTRACE") {
523        Some(x) if &x == "0" => BacktraceStyle::Off,
524        Some(x) if &x == "full" => BacktraceStyle::Full,
525        Some(_) => BacktraceStyle::Short,
526        None if crate::sys::FULL_BACKTRACE_DEFAULT => BacktraceStyle::Full,
527        None => BacktraceStyle::Off,
528    };
529
530    match SHOULD_CAPTURE.compare_exchange(0, format.as_u8(), Ordering::Relaxed, Ordering::Relaxed) {
531        Ok(_) => Some(format),
532        Err(new) => BacktraceStyle::from_u8(new),
533    }
534}
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