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
//! 运行时服务
//!
//! `rt` 模块提供了一组 narrow 的运行时服务,包括全局堆 (在 `heap` 中导出) 以及展开和回溯支持。
//!
//! 该模块中的 API 高度不稳定,因此暂时应将其视为私有实现细节。
//!
//!

#![unstable(
    feature = "rt",
    reason = "this public module should not exist and is highly likely \
              to disappear",
    issue = "none"
)]
#![doc(hidden)]

// 重推出其他 crates 期望的一些实用工具。
pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count};

// 为了减少新 `lang_start` 的生成代码,此函数正在做实际工作。
//
#[cfg(not(test))]
fn lang_start_internal(
    main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe),
    argc: isize,
    argv: *const *const u8,
) -> Result<isize, !> {
    use crate::{mem, panic, sys, sys_common};
    let rt_abort = move |e| {
        mem::forget(e);
        rtabort!("initialization or cleanup bug");
    };
    // 在 Rust 控制的代码之外,要防范这个函数从展开中调用的代码,也就是 UB。
    // 这是由 `#[lang="start"]` 属性的实现方式以及 panicking 机制本身的实现所强加的要求。
    //
    //
    // 有几种情况可以开始展开。首先是 libstd 控制的 `rt::init`、`rt::cleanup` 等类似函数的内部。
    // 在这些情况下,panic 是 libstd 实现错误。
    // 也很有可能,因为没有任何方法可以防止 libstd 意外地将 panic 引入这些函数。
    // 另一个来自 `main` 的用户代码,或者更邪恶的是,如
    // issue #86030.
    // SAFETY: 在运行时初始化期间只调用一次。
    //
    panic::catch_unwind(move || unsafe { sys_common::rt::init(argc, argv) }).map_err(rt_abort)?;
    let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
        .map_err(move |e| {
            mem::forget(e);
            rtprintpanic!("drop of the panic payload panicked");
            sys::abort_internal()
        });
    panic::catch_unwind(sys_common::rt::cleanup).map_err(rt_abort)?;
    ret_code
}

#[cfg(not(test))]
#[lang = "start"]
fn lang_start<T: crate::process::Termination + 'static>(
    main: fn() -> T,
    argc: isize,
    argv: *const *const u8,
) -> isize {
    lang_start_internal(
        &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report(),
        argc,
        argv,
    )
    .into_ok()
}