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
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
//! `panic!` 宏的各个部分以及相关运行时块的实现。
//!
//!
//! 具体来说,该模块包含以下内容的实现:
//!
//! * Panic hooks
//! * 执行 panic 直到完成实际实现
//! * "try" 周围的垫片

#![deny(unsafe_op_in_unsafe_fn)]

use core::panic::{BoxMeUp, Location, PanicInfo};

use crate::any::Any;
use crate::fmt;
use crate::intrinsics;
use crate::mem::{self, ManuallyDrop};
use crate::process;
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sys::stdio::panic_output;
use crate::sys_common::backtrace::{self, RustBacktrace};
use crate::sys_common::rwlock::StaticRWLock;
use crate::sys_common::thread_info;
use crate::thread;

#[cfg(not(test))]
use crate::io::set_output_capture;
// 确保在 std 的真实副本中使用 libtest 配置的 stderr 输出
//
#[cfg(test)]
use realstd::io::set_output_capture;

// 标准库所依赖的 panic 运行时的二进制接口。
//
// 标准库用 `#![needs_panic_runtime]` 标记 (在 RFC 1513 中引入),以表明它需要一些其他用 `#![panic_runtime]` 标记的 crate 才能存在。
// 每个 panic 运行时都旨在实现这些符号 (具有相同的签名),因此我们可以对其进行匹配。
//
// 有一天,编译器可以帮助这些函数 hook 临时看起来不那么特别,但这不是今天!
//
//
//
//
#[allow(improper_ctypes)]
extern "C" {
    fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static);

    /// `payload` 由于 `&mut dyn Trait` 并非 FFI 安全,因此会通过另一层裸指针传递。
    /// `BoxMeUp` 仅在需要时才懒惰地执行分配 (这避免了在使用 "abort" panic 运行时时的分配)。
    ///
    #[unwind(allowed)]
    fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32;
}

/// 如果 FFI 代码捕获到 Rust panic 但不将其抛出,则 panic 运行时将调用此函数。
/// 我们不支持这种情况,因为它与我们的 panic 计数弄混了。
///
#[cfg(not(test))]
#[rustc_std_internal_symbol]
extern "C" fn __rust_drop_panic() -> ! {
    rtabort!("Rust panics must be rethrown");
}

/// 如果 panic 运行时捕获到一个与 X0Rust0Z panic 不对应的异常 object,则该函数由 panic 运行时调用。
///
#[cfg(not(test))]
#[rustc_std_internal_symbol]
extern "C" fn __rust_foreign_exception() -> ! {
    rtabort!("Rust cannot catch foreign exceptions");
}

#[derive(Copy, Clone)]
enum Hook {
    Default,
    Custom(*mut (dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send)),
}

static HOOK_LOCK: StaticRWLock = StaticRWLock::new();
static mut HOOK: Hook = Hook::Default;

/// 注册一个自定义 panic hook,替换以前注册的任何 panic。
///
/// panic hook 在线程 panics 时但在调用 panic 运行时之前被调用。这样,hook 将与终止和展开运行时一起运行。
/// 默认的 hook 将消息显示为标准错误,并在请求时生成回溯,但是可以使用 `set_hook` 和 [`take_hook`] 函数自定义此行为。
///
/// [`take_hook`]: ./fn.take_hook.html
///
/// hook 提供了一个 `PanicInfo` 结构体,该结构体包含有关 panic 的起源的信息,包括传递给 `panic!` 的有效负载和 panic 起源的源代码位置。
///
///
/// panic hook 是一个资源。
///
/// # Panics
///
/// Panics (如果从紧急恐慌线程调用)。
///
/// # Examples
///
/// 以下将打印 "Custom panic hook":
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|_| {
///     println!("Custom panic hook");
/// }));
///
/// panic!("Normal panic");
/// ```
///
///
///
///
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn set_hook(hook: Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>) {
    if thread::panicking() {
        panic!("cannot modify the panic hook from a panicking thread");
    }

    unsafe {
        let guard = HOOK_LOCK.write();
        let old_hook = HOOK;
        HOOK = Hook::Custom(Box::into_raw(hook));
        drop(guard);

        if let Hook::Custom(ptr) = old_hook {
            #[allow(unused_must_use)]
            {
                Box::from_raw(ptr);
            }
        }
    }
}

/// 注销当前的 panic hook,并将其返回。
///
/// *另请参见函数 [`set_hook`]。*
///
/// [`set_hook`]: ./fn.set_hook.html
///
/// 如果未注册自定义 hook,则将返回默认的 hook。
///
/// # Panics
///
/// Panics (如果从紧急恐慌线程调用)。
///
/// # Examples
///
/// 以下将打印 "Normal panic":
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|_| {
///     println!("Custom panic hook");
/// }));
///
/// let _ = panic::take_hook();
///
/// panic!("Normal panic");
/// ```
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
    if thread::panicking() {
        panic!("cannot modify the panic hook from a panicking thread");
    }

    unsafe {
        let guard = HOOK_LOCK.write();
        let hook = HOOK;
        HOOK = Hook::Default;
        drop(guard);

        match hook {
            Hook::Default => Box::new(default_hook),
            Hook::Custom(ptr) => Box::from_raw(ptr),
        }
    }
}

fn default_hook(info: &PanicInfo<'_>) {
    // 如果这是 panic 的两倍,请确保我们为此 panic 打印回溯。
    // 否则,仅在启用日志记录的情况下才打印它。
    let backtrace_env = if panic_count::get_count() >= 2 {
        RustBacktrace::Print(crate::backtrace_rs::PrintFmt::Full)
    } else {
        backtrace::rust_backtrace_env()
    };

    // 当前实现始终返回 `Some`。
    let location = info.location().unwrap();

    let msg = match info.payload().downcast_ref::<&'static str>() {
        Some(s) => *s,
        None => match info.payload().downcast_ref::<String>() {
            Some(s) => &s[..],
            None => "Box<dyn Any>",
        },
    };
    let thread = thread_info::current_thread();
    let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");

    let write = |err: &mut dyn crate::io::Write| {
        let _ = writeln!(err, "thread '{}' panicked at '{}', {}", name, msg, location);

        static FIRST_PANIC: AtomicBool = AtomicBool::new(true);

        match backtrace_env {
            RustBacktrace::Print(format) => drop(backtrace::print(err, format)),
            RustBacktrace::Disabled => {}
            RustBacktrace::RuntimeDisabled => {
                if FIRST_PANIC.swap(false, Ordering::SeqCst) {
                    let _ = writeln!(
                        err,
                        "note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace"
                    );
                }
            }
        }
    };

    if let Some(local) = set_output_capture(None) {
        write(&mut *local.lock().unwrap_or_else(|e| e.into_inner()));
        set_output_capture(Some(local));
    } else if let Some(mut out) = panic_output() {
        write(&mut out);
    }
}

#[cfg(not(test))]
#[doc(hidden)]
#[unstable(feature = "update_panic_count", issue = "none")]
pub mod panic_count {
    use crate::cell::Cell;
    use crate::sync::atomic::{AtomicUsize, Ordering};

    pub const ALWAYS_ABORT_FLAG: usize = 1 << (usize::BITS - 1);

    // 当前线程的 Panic 计数。
    thread_local! { static LOCAL_PANIC_COUNT: Cell<usize> = Cell::new(0) }

    // panic 的总和来自所有线程。目的是在 `is_zero` (`panicking` 使用) 中具有快速路径。
    // 在任何特定线程中,如果该线程当前将 `GLOBAL_PANIC_COUNT` 视为零,则该线程中的 `LOCAL_PANIC_COUNT` 为零。
    // 该不变在增加和减少之前和之后均成立,但不一定在其执行期间成立。
    //
    // 此外,GLOBAL_PANIC_COUNT (GLOBAL_ALWAYS_ABORT_FLAG) 的最高位记录 panic::always_abort () 是否已被调用。这只能设置,永远不会清除。
    //
    // 这可以看作是一个包含一个位和一个 n-1 位值的结构体,但是如果我们这样写它就不仅仅是一个单词,甚至一个围绕 usize 的 newtype 也会很笨拙,因为我们需要原子.
    //
    // 但是我们使用这样一个元组作为 increase() 的返回类型。
    //
    // 窃取一点是可以的,因为它只是假设每个 panicking 线程至少消耗 2 字节的地址空间。
    //
    //
    //
    //
    //
    //
    static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0);

    pub fn increase() -> (bool, usize) {
        (
            GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed) & ALWAYS_ABORT_FLAG != 0,
            LOCAL_PANIC_COUNT.with(|c| {
                let next = c.get() + 1;
                c.set(next);
                next
            }),
        )
    }

    pub fn decrease() {
        GLOBAL_PANIC_COUNT.fetch_sub(1, Ordering::Relaxed);
        LOCAL_PANIC_COUNT.with(|c| {
            let next = c.get() - 1;
            c.set(next);
            next
        });
    }

    pub fn set_always_abort() {
        GLOBAL_PANIC_COUNT.fetch_or(ALWAYS_ABORT_FLAG, Ordering::Relaxed);
    }

    // 忽略 ALWAYS_ABORT_FLAG
    pub fn get_count() -> usize {
        LOCAL_PANIC_COUNT.with(|c| c.get())
    }

    // 忽略 ALWAYS_ABORT_FLAG
    #[inline]
    pub fn count_is_zero() -> bool {
        if GLOBAL_PANIC_COUNT.load(Ordering::Relaxed) & !ALWAYS_ABORT_FLAG == 0 {
            // 快速路径: 如果 `GLOBAL_PANIC_COUNT` 为零,则所有线程 (包括当前线程) 的 `LOCAL_PANIC_COUNT` 均等于零,因此可以避免 TLS 访问。
            //
            // 在性能方面,宽松的原子负载类似于正常对齐的内存读取 (例如,x86 中的 mov 指令),但有一些编译器优化限制。
            // 另一方面,TLS 访问可能需要调用不可插入的函数 (例如,使用 GD TLS 模型时为 `__tls_get_addr`)。
            //
            //
            //
            //
            //
            true
        } else {
            is_zero_slow_path()
        }
    }

    // 慢速路径位于单独的函数中,以减少从 `is_zero` 内联的代码量。
    //
    #[inline(never)]
    #[cold]
    fn is_zero_slow_path() -> bool {
        LOCAL_PANIC_COUNT.with(|c| c.get() == 0)
    }
}

#[cfg(test)]
pub use realstd::rt::panic_count;

/// 调用一个闭包,如果发生,请捕获展开 panic 的原因。
pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
    union Data<F, R> {
        f: ManuallyDrop<F>,
        r: ManuallyDrop<R>,
        p: ManuallyDrop<Box<dyn Any + Send>>,
    }

    // 为了性能起见,我们在此处使用所有权进行一些粗略的操作。
    // 我们只能将指针向下传递到 `do_call` (不能按值传递对象),所以我们在此处使用 union 进行手动的所有的所有权跟踪。
    //
    //
    // 我们经历了一个过渡,其中:
    //
    // * 首先,我们将数据字段 `f` 设置为要调用的无参数闭包。
    // * 在进行下面的 `do_call` 函数的函数调用时,我们将拥有函数指针的所有权。
    // 此时,`data` union 完全没有初始化。
    // * 如果闭包成功返回,则将返回值写入数据的返回插槽 (字段 `r`)。
    // * 如果闭包 panics (下面的 `do_catch`),我们将 panic 有效负载写入字段 `p`。
    // * 最后,当我们退出 `try` 内联函数时,我们处于以下两种状态之一:
    //
    //      1. 闭包不是 panic,在这种情况下将填写返回值。我们将其移出 `data.r` 并返回。
    //      2. 闭包恐慌,在这种情况下,panic 有效负载被填充。我们将其移出 `data.p` 并返回。
    //
    // 一旦我们把所有这些都堆在一起,我们就有了最有效的方法,可以在兼顾所有权的同时触发 panic。
    //
    //
    //
    //
    //
    //
    //
    let mut data = Data { f: ManuallyDrop::new(f) };

    let data_ptr = &mut data as *mut _ as *mut u8;
    // SAFETY:
    //
    // 访问 union 的字段: 这是 `std`,我们知道 `r#try` 内联函数根据其返回值填充 `r` 或 `p` union 字段。
    //
    //
    // 通过以下方法可以安全地调用 `intrinsics::r#try`:
    // - `do_call`, 第一个参数,可以用初始 `data_ptr` 调用。
    // - `do_catch`, 第二个参数,也可以用 `data_ptr` 调用。
    // 有关更多信息,请参见其安全先决条件
    unsafe {
        return if intrinsics::r#try(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 {
            Ok(ManuallyDrop::into_inner(data.r))
        } else {
            Err(ManuallyDrop::into_inner(data.p))
        };
    }

    // 我们认为展开很少见,因此将此函数标记为 `cold`。
    // 但是,请勿将其标记为非内联 - 最好将决定权留给优化器 (在撰写此评论之时,大多数情况下,即使作为普通的非冷函数,也不会内联此函数)。
    //
    //
    #[cold]
    unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send + 'static> {
        // SAFETY: 整个不安全块取决于 panic 处理程序 `__rust_panic_cleanup` 的正确实现。
        // 因此,我们只能假设它为 `Box::from_raw` 工作时返回正确的东西,而没有未定义的行为。
        //
        //
        let obj = unsafe { Box::from_raw(__rust_panic_cleanup(payload)) };
        panic_count::decrease();
        obj
    }

    // SAFETY:
    // 数据必须为非 NUL,正确对齐且指向 `Data<F, R>` 的指针,其必须包含可用于填充 `data.r` 的有效 `f` (类型: F) 值。
    //
    //
    // 此函数不能标记为 `unsafe`,因为 `intrinsics::r#try` 需要正常的函数指针。
    //
    //
    #[inline]
    fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
        // SAFETY: 这是调用者的责任,请参见上文。
        unsafe {
            let data = data as *mut Data<F, R>;
            let data = &mut (*data);
            let f = ManuallyDrop::take(&mut data.f);
            data.r = ManuallyDrop::new(f());
        }
    }

    // 我们 *确实* 希望这部分的 catch 被内联: 这允许编译器正确跟踪对 Data union 的访问,并在大多数情况下对其进行优化。
    //
    // SAFETY:
    // 数据必须为非 NUL,正确对齐并指向 `Data<F, R>` 的指针。由于它使用 `cleanup`,因此还取决于 `__rustc_panic_cleanup` 的正确实现。
    //
    //
    // 此函数不能标记为 `unsafe`,因为 `intrinsics::r#try` 需要正常的函数指针。
    //
    //
    //
    //
    #[inline]
    fn do_catch<F: FnOnce() -> R, R>(data: *mut u8, payload: *mut u8) {
        // SAFETY: 这是调用者的责任,请参见上文。
        //
        // 正确实现 `__rustc_panic_cleaner` 后,我们可以依靠 `obj` 作为传递给 `data.p` 的正确对象 (在 `ManuallyDrop` 中包装)。
        //
        //
        unsafe {
            let data = data as *mut Data<F, R>;
            let data = &mut (*data);
            let obj = cleanup(payload);
            data.p = ManuallyDrop::new(obj);
        }
    }
}

/// 确定当前线程是否由于 panic 而处于展开状态。
#[inline]
pub fn panicking() -> bool {
    !panic_count::count_is_zero()
}

/// 带有格式化消息的恐慌的入口点。
///
/// 通过将实际格式移到该共享位置,可以最大程度地减少调用站点上所需的代码量 (以使 `panic!()` 对 (e.g.) 内联其他函数的影响尽可能小)。
///
///
///
#[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")]
#[cold]
// 如果使用 panic_immediate_abort,则内联终止调用,否则请避免内联,因为它是冷路径。
//
#[cfg_attr(not(feature = "panic_immediate_abort"), track_caller)]
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>) -> ! {
    if cfg!(feature = "panic_immediate_abort") {
        intrinsics::abort()
    }

    let info = PanicInfo::internal_constructor(Some(msg), Location::caller());
    begin_panic_handler(&info)
}

/// libcore crate (`panic_impl` lang 项) 中 panics 的入口点。
#[cfg_attr(not(test), panic_handler)]
#[unwind(allowed)]
pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
    struct PanicPayload<'a> {
        inner: &'a fmt::Arguments<'a>,
        string: Option<String>,
    }

    impl<'a> PanicPayload<'a> {
        fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> {
            PanicPayload { inner, string: None }
        }

        fn fill(&mut self) -> &mut String {
            use crate::fmt::Write;

            let inner = self.inner;
            // 懒惰的是,第一次调用此方法时,请运行实际的字符串格式。
            self.string.get_or_insert_with(|| {
                let mut s = String::new();
                drop(s.write_fmt(*inner));
                s
            })
        }
    }

    unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
        fn take_box(&mut self) -> *mut (dyn Any + Send) {
            // 不幸的是,我们在这里做了两个分配。
            // 但是 (a) 是当前方案所必需的,而 (b) 我们无论如何都无法正确处理 panic + OOM (请参见下面 begin_panic 中的注释)。
            //
            let contents = mem::take(self.fill());
            Box::into_raw(Box::new(contents))
        }

        fn get(&mut self) -> &(dyn Any + Send) {
            self.fill()
        }
    }

    struct StrPanicPayload(&'static str);

    unsafe impl BoxMeUp for StrPanicPayload {
        fn take_box(&mut self) -> *mut (dyn Any + Send) {
            Box::into_raw(Box::new(self.0))
        }

        fn get(&mut self) -> &(dyn Any + Send) {
            &self.0
        }
    }

    let loc = info.location().unwrap(); // 当前的实现总是返回 Some
    let msg = info.message().unwrap(); // 当前的实现总是返回 Some
    crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
        if let Some(msg) = msg.as_str() {
            rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc);
        } else {
            rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
        }
    })
}

/// 这是 panic! () 和 assert! () 的非格式字符串成员恐慌的入口点。
/// 特别是,这是唯一支持任意有效载荷的入口点,而不仅仅是格式字符串。
///
#[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")]
#[cfg_attr(not(test), lang = "begin_panic")]
// 除非 panic_immediate_abort 尽可能避免调用站点上的代码膨胀,否则 CTFE panic 支持的 lang 项永远不会内联
//
//
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[cold]
#[track_caller]
pub fn begin_panic<M: Any + Send>(msg: M) -> ! {
    if cfg!(feature = "panic_immediate_abort") {
        intrinsics::abort()
    }

    let loc = Location::caller();
    return crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
        rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc)
    });

    struct PanicPayload<A> {
        inner: Option<A>,
    }

    impl<A: Send + 'static> PanicPayload<A> {
        fn new(inner: A) -> PanicPayload<A> {
            PanicPayload { inner: Some(inner) }
        }
    }

    unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> {
        fn take_box(&mut self) -> *mut (dyn Any + Send) {
            // 请注意,这应该是在此代码路径中执行的唯一分配。
            // 当前,这意味着 OOM 上的 panic! () 将调用此代码路径,但是无论如何,我们仍然没有真正为 OOM 上的 panic 做好准备。
            // 如果确实开始执行此操作,则应将此分配传播给要在此线程的父级中执行,而不是在发生 panic 的线程中执行。
            //
            //
            let data = match self.inner.take() {
                Some(a) => Box::new(a) as Box<dyn Any + Send>,
                None => process::abort(),
            };
            Box::into_raw(data)
        }

        fn get(&mut self) -> &(dyn Any + Send) {
            match self.inner {
                Some(ref a) => a,
                None => process::abort(),
            }
        }
    }
}

/// 调度 panics 的中心点。
///
/// 执行 panic 的主要逻辑,包括检查递归 panics,panic hooks,最后将其分发到 panic 运行时以终止或 unwind。
///
///
fn rust_panic_with_hook(
    payload: &mut dyn BoxMeUp,
    message: Option<&fmt::Arguments<'_>>,
    location: &Location<'_>,
) -> ! {
    let (must_abort, panics) = panic_count::increase();

    // 如果这是第三个嵌套调用 (例如 panics == 2,则为 0 索引),则 panic hook 可能触发了最后一个 panic,否则,两次 panic 检查将中止该进程。
    // 在这种情况下,请尽快终止进程,因为我们不想再次调用它,因为它可能只是 panic。
    //
    //
    //
    if must_abort || panics > 2 {
        if panics > 2 {
            // 在这种情况下不要尝试打印消息
            // - 也许这导致了递归的 panics。
            rtprintpanic!("thread panicked while processing panic. aborting.\n");
        } else {
            // 不幸的是,这不会打印回溯,因为创建 `Backtrace` 将分配,我们必须在这里避免。
            //
            let panicinfo = PanicInfo::internal_constructor(message, location);
            rtprintpanic!("{}\npanicked after panic::always_abort(), aborting.\n", panicinfo);
        }
        intrinsics::abort()
    }

    unsafe {
        let mut info = PanicInfo::internal_constructor(message, location);
        let _guard = HOOK_LOCK.read();
        match HOOK {
            // 一些平台 (例如 wasm) 知道打印到 stderr 实际上不会打印任何内容,如果是这种情况,我们可以跳过默认的 hook。
            // 由于调用 `payload` 方法时字符串格式化的发生比较懒惰,因此这意味着我们完全避免格式化字符串!
            // (尽管 panic 运行时可能仍然调用 `payload.take_box()` 并触发格式化。)
            //
            //
            //
            Hook::Default if panic_output().is_none() => {}
            Hook::Default => {
                info.set_payload(payload.get());
                default_hook(&info);
            }
            Hook::Custom(ptr) => {
                info.set_payload(payload.get());
                (*ptr)(&info);
            }
        };
    }

    if panics > 1 {
        // 如果线程 panics 已经展开,则我们的选择有限。
        // 当前,我们的首选是终止。
        // 在 future 中,我们可以考虑恢复展开或以其他方式干净退出线程。
        //
        rtprintpanic!("thread panicked while panicking. aborting.\n");
        intrinsics::abort()
    }

    rust_panic(payload)
}

/// 这是 `resume_unwind` 的入口点。
/// 它只是将有效负载转发到 panic 运行时。
pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
    panic_count::increase();

    struct RewrapBox(Box<dyn Any + Send>);

    unsafe impl BoxMeUp for RewrapBox {
        fn take_box(&mut self) -> *mut (dyn Any + Send) {
            Box::into_raw(mem::replace(&mut self.0, Box::new(())))
        }

        fn get(&mut self) -> &(dyn Any + Send) {
            &*self.0
        }
    }

    rust_panic(&mut RewrapBox(payload))
}

/// 一个无残缺的函数 (通过 `rustc_std_internal_symbol`),可以在其上施加断点。
///
#[inline(never)]
#[cfg_attr(not(test), rustc_std_internal_symbol)]
fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! {
    let code = unsafe {
        let obj = &mut msg as *mut &mut dyn BoxMeUp;
        __rust_start_panic(obj)
    };
    rtabort!("failed to initiate panic, error {}", code)
}