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