1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
//! 标准库中的 Panic 支持。
#![stable(feature = "std_panic", since = "1.9.0")]
use crate::any::Any;
use crate::collections;
use crate::panicking;
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sync::{Mutex, RwLock};
use crate::thread::Result;
#[doc(hidden)]
#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
#[allow_internal_unstable(libstd_sys_internals, const_format_args, core_panic, rt)]
#[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")]
#[rustc_macro_transparency = "semitransparent"]
pub macro panic_2015 {
() => ({
$crate::rt::begin_panic("explicit panic")
}),
($msg:expr $(,)?) => ({
$crate::rt::begin_panic($msg);
}),
// 特殊情况下 const_panic 的单个参数情况。
("{}", $arg:expr $(,)?) => ({
$crate::rt::panic_display(&$arg);
}),
($fmt:expr, $($arg:tt)+) => ({
// 分号,以防止在 panic_fmt 调用后调用者认为格式化机器内的临时对象还活着。
//
$crate::rt::panic_fmt($crate::const_format_args!($fmt, $($arg)+));
}),
}
#[doc(hidden)]
#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
pub use core::panic::panic_2021;
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub use crate::panicking::{set_hook, take_hook};
#[unstable(feature = "panic_update_hook", issue = "92649")]
pub use crate::panicking::update_hook;
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub use core::panic::{Location, PanicInfo};
#[stable(feature = "catch_unwind", since = "1.9.0")]
pub use core::panic::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe};
/// 使用给定的消息作为 panic 有效载荷,使当前线程 panic。
///
/// 该消息可以是任何 (`Any + Send`) 类型,而不仅仅是字符串。
///
/// 该消息包装在一个 `Box<'static + Any + Send>` 中,以后可以使用 [`PanicInfo::payload`] 访问它。
///
///
/// 有关 panic 的更多信息,请参见 [`panic!`] 宏。
#[stable(feature = "panic_any", since = "1.51.0")]
#[inline]
#[track_caller]
pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
crate::panicking::begin_panic(msg);
}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: ?Sized> UnwindSafe for Mutex<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: ?Sized> UnwindSafe for RwLock<T> {}
#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")]
impl<T: ?Sized> RefUnwindSafe for Mutex<T> {}
#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")]
impl<T: ?Sized> RefUnwindSafe for RwLock<T> {}
// https://github.com/rust-lang/rust/issues/62301
#[stable(feature = "hashbrown", since = "1.36.0")]
impl<K, V, S> UnwindSafe for collections::HashMap<K, V, S>
where
K: UnwindSafe,
V: UnwindSafe,
S: UnwindSafe,
{
}
/// 调用一个闭包,如果发生,则捕获展开 panic 的原因。
///
/// 如果闭包不是 panic,则此函数将返回 `Ok`,并返回闭包的结果; 如果闭包 panics,则此函数将返回 `Err(cause)`。
/// 返回的 `cause` 是最初调用 panic 的对象。
///
/// unwind 当前从 Rust 代码转换为外来代码是未定义的行为,因此当从另一种语言 (通常为 C) 调用 Rust 时,此函数特别有用。
/// 这可以运行任意的 Rust 代码,捕获 panic 并允许对错误进行适当的处理。
///
/// 不建议将此函数用于一般的 try/catch 机制。[`Result`] 类型更适合用于经常失败的函数。
/// 此外,不能保证此函数可以捕获所有 panics,请参见下面的 "Notes" 部分。
///
/// 提供的闭包必须遵守 [`UnwindSafe`] trait,以确保所有捕获的变量都可以安全越过此边界。
/// 此绑定的目的是在类型系统中对 [异常安全][rfc] 的概念进行编码。
/// 此函数的大多数用法都不必担心此绑定,因为没有 `unsafe` 代码的程序自然是 unwind 安全的。
/// 如果出现问题,可以使用 [`AssertUnwindSafe`] 包装器结构体快速断言此处的使用确实是 unwind 安全的。
///
/// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md
///
/// # Notes
///
/// 请注意,此函数**可能无法捕获 Rust 中的所有 panics**。Rust 中的 panic 并不总是通过展开来实现,但是也可以通过中止进程来实现。
///
/// 该函数 *仅* 捕获展开 panics,而不是那些中止进程的 panics。
///
/// 请注意,如果已设置自定义 panic 钩子,它将在 panic 被捕获之前调用,在展开之前。
///
/// 另请注意,使用外部异常 (例如,展开为 Rust 代码)
/// 从 C++ 代码引发的异常) 是未定义的行为。
///
/// # Examples
///
/// ```
/// use std::panic;
///
/// let result = panic::catch_unwind(|| {
/// println!("hello!");
/// });
/// assert!(result.is_ok());
///
/// let result = panic::catch_unwind(|| {
/// panic!("oh no!");
/// });
/// assert!(result.is_err());
/// ```
///
///
///
///
///
///
///
///
///
///
#[stable(feature = "catch_unwind", since = "1.9.0")]
pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
unsafe { panicking::r#try(f) }
}
/// 在不调用 panic 钩子的情况下触发 panic。
///
/// 它被设计为与 [`catch_unwind`] 结合使用,例如,跨 C 代码层携带 panic。
///
/// # Notes
///
/// 请注意,Rust 中的 panics 并不总是通过展开来实现,但是可以通过中止进程来实现。
/// 如果以这种方式实现 panics 时调用了此函数,则此函数将中止进程,而不触发 unwind。
///
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// let result = panic::catch_unwind(|| {
/// panic!("oh no!");
/// });
///
/// if let Err(err) = result {
/// panic::resume_unwind(err);
/// }
/// ```
///
///
#[stable(feature = "resume_unwind", since = "1.9.0")]
pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
panicking::rust_panic_without_hook(payload)
}
/// 使所有未来的 panic 直接中止,而不运行 panic 钩子或展开。
///
/// 没有办法撤销这个; 效果持续到进程退出或执行 (或等效)。
///
/// # fork 后使用
///
/// 这个函数在 `libc::fork` 之后调用特别有用。在 `fork` 之后,在多线程程序中 (在许多平台上) 调用分配器是不安全的。
/// `fork` 之后的 unwind 到 unwind 通常也是非常不可取的,因为这会导致 unwind 传播到只希望在父级中运行的代码。
///
///
/// `panic::always_abort()` 有助于避免这两种情况。
/// 它直接避免了任何进一步的展开,如果存在 panic,则无需分配即可中止中止,前提是 panic 的参数可以在不分配的情况下进行格式化。
///
/// Examples
///
/// ```no_run
/// #![feature(panic_always_abort)]
/// use std::panic;
///
/// panic::always_abort();
///
/// let _ = panic::catch_unwind(|| {
/// panic!("inside the catch");
/// });
///
/// // 由于 panic,我们已经中止了。
/// unreachable!();
/// ```
///
///
///
#[unstable(feature = "panic_always_abort", issue = "84438")]
pub fn always_abort() {
crate::panicking::panic_count::set_always_abort();
}
/// 默认 panic 钩子,是否以及如何捕获和显示回溯的配置。
///
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[unstable(feature = "panic_backtrace_config", issue = "93346")]
#[non_exhaustive]
pub enum BacktraceStyle {
/// 打印一个简洁的回溯,理想情况下只包含相关信息。
///
Short,
/// 打印包含所有可能信息的回溯。
Full,
/// 禁用收集和显示回溯。
Off,
}
impl BacktraceStyle {
pub(crate) fn full() -> Option<Self> {
if cfg!(feature = "backtrace") { Some(BacktraceStyle::Full) } else { None }
}
fn as_usize(self) -> usize {
match self {
BacktraceStyle::Short => 1,
BacktraceStyle::Full => 2,
BacktraceStyle::Off => 3,
}
}
fn from_usize(s: usize) -> Option<Self> {
Some(match s {
0 => return None,
1 => BacktraceStyle::Short,
2 => BacktraceStyle::Full,
3 => BacktraceStyle::Off,
_ => unreachable!(),
})
}
}
// 跟踪我们是否应该或能够捕获回溯,以及我们应该如何显示回溯。
//
//
// 内部存储相当于 Option<BacktraceStyle>。
static SHOULD_CAPTURE: AtomicUsize = AtomicUsize::new(0);
/// 配置默认的 panic 钩子,是否将捕获并显示回溯。
///
/// 此设置的默认值可以由 `RUST_BACKTRACE` 环境变量设置; 请参见 [`get_backtrace_style`] 中的详细信息。
///
///
#[unstable(feature = "panic_backtrace_config", issue = "93346")]
pub fn set_backtrace_style(style: BacktraceStyle) {
if !cfg!(feature = "backtrace") {
// 如果此 crate 的 `backtrace` 特性没有被启用,请跳过设置。
return;
}
SHOULD_CAPTURE.store(style.as_usize(), Ordering::Release);
}
/// 检查标准库的 panic 钩子是否会捕获并打印回溯。
///
/// 如果没有通过 [`set_backtrace_style`] 设置回溯样式,此函数将读取环境变量 `RUST_BACKTRACE` 以确定回溯格式的默认值:
///
///
/// 如果没有调用 `set_backtrace_style` 来覆盖默认值,则对 `get_backtrace_style` 的第一个调用可能会读取 `RUST_BACKTRACE` 环境变量。
/// 调用 `set_backtrace_style` 或 `get_backtrace_style` 后,对 `RUST_BACKTRACE` 的任何更改都将无效。
///
/// `RUST_BACKTRACE` 根据以下规则读取:
///
/// * `0` 代表 `BacktraceStyle::Off`
/// * `full` 代表 `BacktraceStyle::Full`
/// * `1` 代表 `BacktraceStyle::Short`
/// * 其他值目前是 `BacktraceStyle::Short`,但这可能会在未来改变
///
/// 如果当前不支持回溯,则返回 `None`。
///
///
///
///
///
#[unstable(feature = "panic_backtrace_config", issue = "93346")]
pub fn get_backtrace_style() -> Option<BacktraceStyle> {
if !cfg!(feature = "backtrace") {
// 如果未启用此 crate 的 `backtrace` 特性,请快速返回 `Unsupported`,这样就可以在整个地方不断传播,以优化离开的调用者。
//
//
return None;
}
if let Some(style) = BacktraceStyle::from_usize(SHOULD_CAPTURE.load(Ordering::Acquire)) {
return Some(style);
}
let format = crate::env::var_os("RUST_BACKTRACE")
.map(|x| {
if &x == "0" {
BacktraceStyle::Off
} else if &x == "full" {
BacktraceStyle::Full
} else {
BacktraceStyle::Short
}
})
.unwrap_or(if crate::sys::FULL_BACKTRACE_DEFAULT {
BacktraceStyle::Full
} else {
BacktraceStyle::Off
});
set_backtrace_style(format);
Some(format)
}
#[cfg(test)]
mod tests;