rt.rs - source
Description: Source of the Rust file `library/std/src/rt.rs`.

#
std/
rt.rs

    1//! Runtime services
    2//!
    3//! The `rt` module provides a narrow set of runtime services,
    4//! including the global heap (exported in `heap`) and unwinding and
    5//! backtrace support. The APIs in this module are highly unstable,
    6//! and should be considered as private implementation details for the
    7//! time being.
    8
    9#![unstable(
    10    feature = "rt",
    11    reason = "this public module should not exist and is highly likely \
    12              to disappear",
    13    issue = "none"
    14)]
    15#![doc(hidden)]
    16#![deny(unsafe_op_in_unsafe_fn)]
    17#![allow(unused_macros)]
    18
    19#[rustfmt::skip]
    20pub use crate::panicking::{begin_panic, panic_count};
    21pub use core::panicking::{panic_display, panic_fmt};
    22
    23#[rustfmt::skip]
    24use crate::any::Any;
    25use crate::sync::Once;
    26use crate::thread::{self, main_thread};
    27use crate::{mem, panic, sys};
    28
    29// This function is needed by the panic runtime.
    30#[cfg(not(test))]
    31#[rustc_std_internal_symbol]
    32fn __rust_abort() {
    33    crate::process::abort();
    34}
    35
    36// Prints to the "panic output", depending on the platform this may be:
    37// - the standard error output
    38// - some dedicated platform specific output
    39// - nothing (so this macro is a no-op)
    40macro_rules! rtprintpanic {
    41    ($($t:tt)*) => {
    42        #[cfg(not(panic = "immediate-abort"))]
    43        if let Some(mut out) = crate::sys::stdio::panic_output() {
    44            let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*));
    45        }
    46        #[cfg(panic = "immediate-abort")]
    47        {
    48            let _ = format_args!($($t)*);
    49        }
    50    }
    51}
    52
    53macro_rules! rtabort {
    54    ($($t:tt)*) => {
    55        {
    56            rtprintpanic!("fatal runtime error: {}, aborting\n", format_args!($($t)*));
    57            crate::process::abort();
    58        }
    59    }
    60}
    61
    62macro_rules! rtassert {
    63    ($e:expr) => {
    64        if !$e {
    65            rtabort!(concat!("assertion failed: ", stringify!($e)));
    66        }
    67    };
    68}
    69
    70macro_rules! rtunwrap {
    71    ($ok:ident, $e:expr) => {
    72        match $e {
    73            $ok(v) => v,
    74            ref err => {
    75                let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug
    76                rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err)
    77            }
    78        }
    79    };
    80}
    81
    82fn handle_rt_panic<T>(e: Box<dyn Any + Send>) -> T {
    83    mem::forget(e);
    84    rtabort!("initialization or cleanup bug");
    85}
    86
    87// One-time runtime initialization.
    88// Runs before `main`.
    89// SAFETY: must be called only once during runtime initialization.
    90// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
    91//
    92// # The `sigpipe` parameter
    93//
    94// Since 2014, the Rust runtime on Unix has set the `SIGPIPE` handler to
    95// `SIG_IGN`. Applications have good reasons to want a different behavior
    96// though, so there is a `-Zon-broken-pipe` compiler flag that
    97// can be used to select how `SIGPIPE` shall be setup (if changed at all) before
    98// `fn main()` is called. See <https://github.com/rust-lang/rust/issues/97889>
    99// for more info.
    100//
    101// The `sigpipe` parameter to this function gets its value via the code that
    102// rustc generates to invoke `fn lang_start()`. The reason we have `sigpipe` for
    103// all platforms and not only Unix, is because std is not allowed to have `cfg`
    104// directives as this high level. See the module docs in
    105// `src/tools/tidy/src/pal.rs` for more info. On all other platforms, `sigpipe`
    106// has a value, but its value is ignored.
    107//
    108// Even though it is an `u8`, it only ever has 4 values. These are documented in
    109// `compiler/rustc_session/src/config/sigpipe.rs`.
    110#[cfg_attr(test, allow(dead_code))]
    111unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
    112    // Remember the main thread ID to give it the correct name.
    113    // SAFETY: this is the only time and place where we call this function.
    114    unsafe { main_thread::set(thread::current_id()) };
    115
    116    #[cfg_attr(target_os = "teeos", allow(unused_unsafe))]
    117    unsafe {
    118        sys::init(argc, argv, sigpipe)
    119    };
    120}
    121
    122/// Clean up the thread-local runtime state. This *should* be run after all other
    123/// code managed by the Rust runtime, but will not cause UB if that condition is
    124/// not fulfilled. Also note that this function is not guaranteed to be run, but
    125/// skipping it will cause leaks and therefore is to be avoided.
    126pub(crate) fn thread_cleanup() {
    127    // This function is run in situations where unwinding leads to an abort
    128    // (think `extern "C"` functions). Abort here instead so that we can
    129    // print a nice message.
    130    panic::catch_unwind(|| {
    131        crate::thread::drop_current();
    132    })
    133    .unwrap_or_else(handle_rt_panic);
    134}
    135
    136// One-time runtime cleanup.
    137// Runs after `main` or at program exit.
    138// NOTE: this is not guaranteed to run, for example when the program aborts.
    139pub(crate) fn cleanup() {
    140    static CLEANUP: Once = Once::new();
    141    CLEANUP.call_once(|| unsafe {
    142        // Flush stdout and disable buffering.
    143        crate::io::cleanup();
    144        // SAFETY: Only called once during runtime cleanup.
    145        sys::cleanup();
    146    });
    147}
    148
    149// To reduce the generated code of the new `lang_start`, this function is doing
    150// the real work.
    151#[cfg(not(test))]
    152fn lang_start_internal(
    153    main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe),
    154    argc: isize,
    155    argv: *const *const u8,
    156    sigpipe: u8,
    157) -> isize {
    158    // Guard against the code called by this function from unwinding outside of the Rust-controlled
    159    // code, which is UB. This is a requirement imposed by a combination of how the
    160    // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking
    161    // mechanism itself.
    162    //
    163    // There are a couple of instances where unwinding can begin. First is inside of the
    164    // `rt::init`, `rt::cleanup` and similar functions controlled by std. In those instances a
    165    // panic is a std implementation bug. A quite likely one too, as there isn't any way to
    166    // prevent std from accidentally introducing a panic to these functions. Another is from
    167    // user code from `main` or, more nefariously, as described in e.g. issue #86030.
    168    //
    169    // We use `catch_unwind` with `handle_rt_panic` instead of `abort_unwind` to make the error in
    170    // case of a panic a bit nicer.
    171    panic::catch_unwind(move || {
    172        // SAFETY: Only called once during runtime initialization.
    173        unsafe { init(argc, argv, sigpipe) };
    174
    175        let ret_code = panic::catch_unwind(main).unwrap_or_else(move |payload| {
    176            // Carefully dispose of the panic payload.
    177            let payload = panic::AssertUnwindSafe(payload);
    178            panic::catch_unwind(move || drop({ payload }.0)).unwrap_or_else(move |e| {
    179                mem::forget(e); // do *not* drop the 2nd payload
    180                rtabort!("drop of the panic payload panicked");
    181            });
    182            // Return error code for panicking programs.
    183            101
    184        });
    185        let ret_code = ret_code as isize;
    186
    187        cleanup();
    188        // Guard against multiple threads calling `libc::exit` concurrently.
    189        // See the documentation for `unique_thread_exit` for more information.
    190        crate::sys::exit_guard::unique_thread_exit();
    191
    192        ret_code
    193    })
    194    .unwrap_or_else(handle_rt_panic)
    195}
    196
    197#[cfg(not(any(test, doctest)))]
    198#[lang = "start"]
    199fn lang_start<T: crate::process::Termination + 'static>(
    200    main: fn() -> T,
    201    argc: isize,
    202    argv: *const *const u8,
    203    sigpipe: u8,
    204) -> isize {
    205    lang_start_internal(
    206        &move || crate::sys::backtrace::__rust_begin_short_backtrace(main).report().to_i32(),
    207        argc,
    208        argv,
    209        sigpipe,
    210    )
    211}