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
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
//! `panic!` 宏的各个部分以及相关运行时块的实现。
//!
//!
//! 具体来说,该模块包含以下内容的实现:
//!
//! * Panic hooks
//! * 执行 panic 直到完成实际实现
//! * "try" 周围的垫片

#![deny(unsafe_op_in_unsafe_fn)]

use crate::panic::BacktraceStyle;
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::sync::{PoisonError, RwLock};
use crate::sys::stdio::panic_output;
use crate::sys_common::backtrace;
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 运行时都旨在实现这些符号 (具有相同的签名),因此我们可以对其进行匹配。
//
// 有一天,编译器可以帮助连接这些函数,这可能会看起来不那么特别,但今天不会了!
//
//
//
//
#[allow(improper_ctypes)]
extern "C" {
    fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static);
}

extern "Rust" {
    /// `BoxMeUp` 仅在需要时延迟执行分配 (这避免了使用 "abort" panic 运行时进行分配)。
    ///
    fn __rust_start_panic(payload: &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 运行时捕获到一个与 Rust panic 不对应的异常对象,则该函数由 panic 运行时调用。
///
#[cfg(not(test))]
#[rustc_std_internal_symbol]
extern "C" fn __rust_foreign_exception() -> ! {
    rtabort!("Rust cannot catch foreign exceptions");
}

enum Hook {
    Default,
    Custom(Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>),
}

impl Hook {
    #[inline]
    fn into_box(self) -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
        match self {
            Hook::Default => Box::new(default_hook),
            Hook::Custom(hook) => hook,
        }
    }
}

impl Default for Hook {
    #[inline]
    fn default() -> Hook {
        Hook::Default
    }
}

static HOOK: RwLock<Hook> = RwLock::new(Hook::Default);

/// 注册一个自定义的 panic hook,替换之前注册的 hook。
///
/// 当线程发生 panic 时,但在调用 panic 运行时之前,会调用 panic 钩子。这样,钩子将与中止和展开运行时一起运行。
///
/// 默认钩子在启动时注册,将消息打印到标准错误并在请求时生成回溯。可以使用 `set_hook` 函数自定义此行为。
/// 可以在使用 [`take_hook`] 函数恢复默认钩子的同时检索当前钩子。
///
/// [`take_hook`]: ./fn.take_hook.html
///
/// 该钩子提供了一个 `PanicInfo` 结构体,该结构体包含有关 panic 的起源的信息,包括传递给 `panic!` 的有效载荷和包含 panic 起源的源代码位置。
///
///
/// panic 钩子是一个全局资源。
///
/// # Panics
///
/// 如果从 panic 线程调用,就会出现 panic。
///
/// # 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");
    }

    let new = Hook::Custom(hook);
    let mut hook = HOOK.write().unwrap_or_else(PoisonError::into_inner);
    let old = mem::replace(&mut *hook, new);
    drop(hook);
    // 仅在释放锁后丢弃旧的钩子,以避免在其析构函数 panic 时发生死锁。
    //
    drop(old);
}

/// 注销当前的 panic 钩子,并返回它,在其位置注册默认,钩子。
///
///
/// *另请参见函数 [`set_hook`]。*
///
/// [`set_hook`]: ./fn.set_hook.html
///
/// 如果默认钩子已注册,它将被返回,但保持注册状态。
///
/// # Panics
///
/// 如果从 panic 线程调用,就会出现 panic。
///
/// # Examples
///
/// 以下将打印 "Normal panic":
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|_| {
///     println!("Custom panic hook");
/// }));
///
/// let _ = panic::take_hook();
///
/// panic!("Normal panic");
/// ```
#[must_use]
#[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");
    }

    let mut hook = HOOK.write().unwrap_or_else(PoisonError::into_inner);
    let old_hook = mem::take(&mut *hook);
    drop(hook);

    old_hook.into_box()
}

/// [`take_hook`] 和 [`set_hook`] 的原子组合。
/// 使用它来用一个新的 panic 处理程序替换 panic 处理程序,该处理程序会做一些事情然后执行旧的处理程序。
///
/// [`take_hook`]: ./fn.take_hook.html
/// [`set_hook`]: ./fn.set_hook.html
///
/// # Panics
///
/// 如果从 panic 线程调用,就会出现 panic。
///
/// # Examples
///
/// 下面会打印自定义消息,然后正常输出 panic。
///
/// ```should_panic
/// #![feature(panic_update_hook)]
/// use std::panic;
///
/// // 相当于
/// // let prev = panic::take_hook();
/// // panic::set_hook(move |info| {
/// //     println!("...");
/// //     prev(info);
/// // );
/// panic::update_hook(move |prev, info| {
///     println!("Print custom message and execute panic handler as usual");
///     prev(info);
/// });
///
/// panic!("Custom and then normal");
/// ```
#[unstable(feature = "panic_update_hook", issue = "92649")]
pub fn update_hook<F>(hook_fn: F)
where
    F: Fn(&(dyn Fn(&PanicInfo<'_>) + Send + Sync + 'static), &PanicInfo<'_>)
        + Sync
        + Send
        + 'static,
{
    if thread::panicking() {
        panic!("cannot modify the panic hook from a panicking thread");
    }

    let mut hook = HOOK.write().unwrap_or_else(PoisonError::into_inner);
    let prev = mem::take(&mut *hook).into_box();
    *hook = Hook::Custom(Box::new(move |info| hook_fn(&prev, info)));
}

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

    // 当前实现始终返回 `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 '{name}' panicked at '{msg}', {location}");

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

        match backtrace {
            Some(BacktraceStyle::Short) => {
                drop(backtrace::print(err, crate::backtrace_rs::PrintFmt::Short))
            }
            Some(BacktraceStyle::Full) => {
                drop(backtrace::print(err, crate::backtrace_rs::PrintFmt::Full))
            }
            Some(BacktraceStyle::Off) => {
                if FIRST_PANIC.swap(false, Ordering::SeqCst) {
                    let _ = writeln!(
                        err,
                        "note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace"
                    );
                }
            }
            // 如果不支持回溯,则什么也不做。
            None => {}
        }
    };

    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 的原因。
    #[derive(Debug)]
    pub enum MustAbort {
        AlwaysAbort,
        PanicInHook,
    }

    // 当前线程的 panic 计数以及当前是否正在执行 panic 钩子。
    //
    thread_local! {
        static LOCAL_PANIC_COUNT: Cell<(usize, bool)> = const { Cell::new((0, false)) }
    }

    // 所有线程的 panic 计数总和。这样做的目的是在 `count_is_zero` (`panicking` 使用) 中有一个快速路径。
    // 在任何特定线程中,如果该线程当前将 `GLOBAL_PANIC_COUNT` 视为零,则该线程中的 `LOCAL_PANIC_COUNT` 为零。
    // 该不变在增加和减少之前和之后均成立,但不一定在其执行期间成立。
    //
    // 此外,GLOBAL_PANIC_COUNT (GLOBAL_ALWAYS_ABORT_FLAG) 的最高位记录 panic::always_abort () 是否已被调用。这只能设置,永远不会清除。
    // panic::always_abort () 通常被调用来防止由 `libc::fork` 创建的子进程中的 panic 处理完成的内存分配。
    // 在大多数操作系统中,在使用 `libc::fork` 创建的子进程中执行的内存分配是未定义的行为。
    // 在 `libc::fork` 创建的子节点中访问 LOCAL_PANIC_COUNT 会导致内存分配。在这种情况下,只能访问 GLOBAL_PANIC_COUNT。
    // 这已经足够了,因为子进程总是只有一个线程。
    // 有关详细信息,另请参见 #85261。
    //
    // 这可以看作是一个包含一个位和一个 n-1 位值的结构体,但是如果我们这样写它就不仅仅是一个单词,甚至一个围绕 usize 的 newtype 也会很笨拙,因为我们需要原子.
    //
    // 但是我们使用这样一个元组作为 increase() 的返回类型。
    //
    // 窃取一点是可以的,因为它只是假设每个 panicking 线程至少消耗 2 字节的地址空间。
    //
    //
    //
    //
    //
    //
    //
    //
    //
    static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0);

    // 增加全局和局部 panic 计数,并返回是否需要立即中止。
    //
    // 这也会更新线程本地状态以跟踪当前是否正在执行 panic hook。
    //
    //
    pub fn increase(run_panic_hook: bool) -> Option<MustAbort> {
        let global_count = GLOBAL_PANIC_COUNT.fetch_add(1, Ordering::Relaxed);
        if global_count & ALWAYS_ABORT_FLAG != 0 {
            return Some(MustAbort::AlwaysAbort);
        }

        LOCAL_PANIC_COUNT.with(|c| {
            let (count, in_panic_hook) = c.get();
            if in_panic_hook {
                return Some(MustAbort::PanicInHook);
            }
            c.set((count + 1, run_panic_hook));
            None
        })
    }

    pub fn finished_panic_hook() {
        LOCAL_PANIC_COUNT.with(|c| {
            let (count, _) = c.get();
            c.set((count, false));
        });
    }

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

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

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

    // 忽略 ALWAYS_ABORT_FLAG
    #[must_use]
    #[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()
        }
    }

    // 慢路径在一个单独的函数中,以减少从 `count_is_zero` 内联的代码量。
    //
    #[inline(never)]
    #[cold]
    fn is_zero_slow_path() -> bool {
        LOCAL_PANIC_COUNT.with(|c| c.get().0 == 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 后,在这种情况下,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]
    #[rustc_nounwind] // `intrinsic::r#try` 要求 catch fn 为 nounwind
    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()
}

/// 来自 core crate (`panic_impl` lang 项) 的 panic 入口点。
#[cfg(not(test))]
#[panic_handler]
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();
                let _err = 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, info.can_unwind());
        } else {
            rust_panic_with_hook(
                &mut PanicPayload::new(msg),
                info.message(),
                loc,
                info.can_unwind(),
            );
        }
    })
}

/// 这是 panic!() 和 assert!() 的非格式字符串变体 panic 的入口点。
/// 特别是,这是唯一支持任意的有效载荷的入口点,而不仅仅是格式字符串。
///
#[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)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
#[rustc_do_not_const_check] // 被 const-eval 钩住了
pub const 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, true)
    });

    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 的主要逻辑,包括检查递归 panic,panic 钩子,最后将其分发到 panic 运行时以中止或 unwind。
///
///
fn rust_panic_with_hook(
    payload: &mut dyn BoxMeUp,
    message: Option<&fmt::Arguments<'_>>,
    location: &Location<'_>,
    can_unwind: bool,
) -> ! {
    let must_abort = panic_count::increase(true);

    // 检查我们是否需要立即中止。
    if let Some(must_abort) = must_abort {
        match must_abort {
            panic_count::MustAbort::PanicInHook => {
                // 在这种情况下不要尝试打印消息
                // - 也许这导致了递归的 panics。
                rtprintpanic!("thread panicked while processing panic. aborting.\n");
            }
            panic_count::MustAbort::AlwaysAbort => {
                // 不幸的是,这不会打印回溯,因为创建 `Backtrace` 将分配,我们必须在这里避免。
                //
                let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind);
                rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n");
            }
        }
        crate::sys::abort_internal();
    }

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

    // 表明我们已经完成了 panic hook 的执行。
    // 在这一点之后,如果在执行析构函数时出现 panic 就没有问题,只要它包含在 `catch_unwind` 中即可。
    //
    panic_count::finished_panic_hook();

    if !can_unwind {
        // 如果一个线程在运行析构函数或尝试通过 nounwind 函数 (例如
        // extern "C") 那么我们不能继续展开,必须立即中止。
        //
        rtprintpanic!("thread caused non-unwinding panic. aborting.\n");
        crate::sys::abort_internal();
    }

    rust_panic(payload)
}

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

    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(msg: &mut dyn BoxMeUp) -> ! {
    let code = unsafe { __rust_start_panic(msg) };
    rtabort!("failed to initiate panic, error {code}")
}