| //! Runtime services | |
| //! | |
| //! The `rt` module provides a narrow set of runtime services, | |
| //! including the global heap (exported in `heap`) and unwinding and | |
| //! backtrace support. The APIs in this module are highly unstable, | |
| //! and should be considered as private implementation details for the | |
| //! time being. | |
| #![unstable( | |
| feature = "rt", | |
| reason = "this public module should not exist and is highly likely \ | |
| to disappear", | |
| issue = "none" | |
| )] | |
| #![doc(hidden)] | |
| #![deny(unsafe_op_in_unsafe_fn)] | |
| #![allow(unused_macros)] | |
| #[rustfmt::skip] | |
| pub use crate::panicking::{begin_panic, panic_count}; | |
| pub use core::panicking::{panic_display, panic_fmt}; | |
| #[rustfmt::skip] | |
| use crate::any::Any; | |
| use crate::sync::Once; | |
| use crate::thread::{self, main_thread}; | |
| use crate::{mem, panic, sys}; | |
| // This function is needed by the panic runtime. | |
| #[cfg(not(test))] | |
| #[rustc_std_internal_symbol] | |
| fn __rust_abort() { | |
| crate::process::abort(); | |
| } | |
| // Prints to the "panic output", depending on the platform this may be: | |
| // - the standard error output | |
| // - some dedicated platform specific output | |
| // - nothing (so this macro is a no-op) | |
| macro_rules! rtprintpanic { | |
| ($($t:tt)*) => { | |
| #[cfg(not(panic = "immediate-abort"))] | |
| if let Some(mut out) = crate::sys::stdio::panic_output() { | |
| let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*)); | |
| } | |
| #[cfg(panic = "immediate-abort")] | |
| { | |
| let _ = format_args!($($t)*); | |
| } | |
| } | |
| } | |
| macro_rules! rtabort { | |
| ($($t:tt)*) => { | |
| { | |
| rtprintpanic!("fatal runtime error: {}, aborting\n", format_args!($($t)*)); | |
| crate::process::abort(); | |
| } | |
| } | |
| } | |
| macro_rules! rtassert { | |
| ($e:expr) => { | |
| if !$e { | |
| rtabort!(concat!("assertion failed: ", stringify!($e))); | |
| } | |
| }; | |
| } | |
| macro_rules! rtunwrap { | |
| ($ok:ident, $e:expr) => { | |
| match $e { | |
| $ok(v) => v, | |
| ref err => { | |
| let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug | |
| rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err) | |
| } | |
| } | |
| }; | |
| } | |
| fn handle_rt_panic<T>(e: Box<dyn Any + Send>) -> T { | |
| mem::forget(e); | |
| rtabort!("initialization or cleanup bug"); | |
| } | |
| // One-time runtime initialization. | |
| // Runs before `main`. | |
| // SAFETY: must be called only once during runtime initialization. | |
| // NOTE: this is not guaranteed to run, for example when Rust code is called externally. | |
| // | |
| // # The `sigpipe` parameter | |
| // | |
| // Since 2014, the Rust runtime on Unix has set the `SIGPIPE` handler to | |
| // `SIG_IGN`. Applications have good reasons to want a different behavior | |
| // though, so there is a `-Zon-broken-pipe` compiler flag that | |
| // can be used to select how `SIGPIPE` shall be setup (if changed at all) before | |
| // `fn main()` is called. See <https://github.com/rust-lang/rust/issues/97889> | |
| // for more info. | |
| // | |
| // The `sigpipe` parameter to this function gets its value via the code that | |
| // rustc generates to invoke `fn lang_start()`. The reason we have `sigpipe` for | |
| // all platforms and not only Unix, is because std is not allowed to have `cfg` | |
| // directives as this high level. See the module docs in | |
| // `src/tools/tidy/src/pal.rs` for more info. On all other platforms, `sigpipe` | |
| // has a value, but its value is ignored. | |
| // | |
| // Even though it is an `u8`, it only ever has 4 values. These are documented in | |
| // `compiler/rustc_session/src/config/sigpipe.rs`. | |
| #[cfg_attr(test, allow(dead_code))] | |
| unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { | |
| // Remember the main thread ID to give it the correct name. | |
| // SAFETY: this is the only time and place where we call this function. | |
| unsafe { main_thread::set(thread::current_id()) }; | |
| #[cfg_attr(target_os = "teeos", allow(unused_unsafe))] | |
| unsafe { | |
| sys::init(argc, argv, sigpipe) | |
| }; | |
| } | |
| /// Clean up the thread-local runtime state. This *should* be run after all other | |
| /// code managed by the Rust runtime, but will not cause UB if that condition is | |
| /// not fulfilled. Also note that this function is not guaranteed to be run, but | |
| /// skipping it will cause leaks and therefore is to be avoided. | |
| pub(crate) fn thread_cleanup() { | |
| // This function is run in situations where unwinding leads to an abort | |
| // (think `extern "C"` functions). Abort here instead so that we can | |
| // print a nice message. | |
| panic::catch_unwind(|| { | |
| crate::thread::drop_current(); | |
| }) | |
| .unwrap_or_else(handle_rt_panic); | |
| } | |
| // One-time runtime cleanup. | |
| // Runs after `main` or at program exit. | |
| // NOTE: this is not guaranteed to run, for example when the program aborts. | |
| pub(crate) fn cleanup() { | |
| static CLEANUP: Once = Once::new(); | |
| CLEANUP.call_once(|| unsafe { | |
| // Flush stdout and disable buffering. | |
| crate::io::cleanup(); | |
| // SAFETY: Only called once during runtime cleanup. | |
| sys::cleanup(); | |
| }); | |
| } | |
| // To reduce the generated code of the new `lang_start`, this function is doing | |
| // the real work. | |
| #[cfg(not(test))] | |
| fn lang_start_internal( | |
| main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe), | |
| argc: isize, | |
| argv: *const *const u8, | |
| sigpipe: u8, | |
| ) -> isize { | |
| // Guard against the code called by this function from unwinding outside of the Rust-controlled | |
| // code, which is UB. This is a requirement imposed by a combination of how the | |
| // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking | |
| // mechanism itself. | |
| // | |
| // There are a couple of instances where unwinding can begin. First is inside of the | |
| // `rt::init`, `rt::cleanup` and similar functions controlled by std. In those instances a | |
| // panic is a std implementation bug. A quite likely one too, as there isn't any way to | |
| // prevent std from accidentally introducing a panic to these functions. Another is from | |
| // user code from `main` or, more nefariously, as described in e.g. issue #86030. | |
| // | |
| // We use `catch_unwind` with `handle_rt_panic` instead of `abort_unwind` to make the error in | |
| // case of a panic a bit nicer. | |
| panic::catch_unwind(move || { | |
| // SAFETY: Only called once during runtime initialization. | |
| unsafe { init(argc, argv, sigpipe) }; | |
| let ret_code = panic::catch_unwind(main).unwrap_or_else(move |payload| { | |
| // Carefully dispose of the panic payload. | |
| let payload = panic::AssertUnwindSafe(payload); | |
| panic::catch_unwind(move || drop({ payload }.0)).unwrap_or_else(move |e| { | |
| mem::forget(e); // do *not* drop the 2nd payload | |
| rtabort!("drop of the panic payload panicked"); | |
| }); | |
| // Return error code for panicking programs. | |
| 101 | |
| }); | |
| let ret_code = ret_code as isize; | |
| cleanup(); | |
| // Guard against multiple threads calling `libc::exit` concurrently. | |
| // See the documentation for `unique_thread_exit` for more information. | |
| crate::sys::exit::unique_thread_exit(); | |
| ret_code | |
| }) | |
| .unwrap_or_else(handle_rt_panic) | |
| } | |
| #[cfg(not(any(test, doctest)))] | |
| #[lang = "start"] | |
| fn lang_start<T: crate::process::Termination + 'static>( | |
| main: fn() -> T, | |
| argc: isize, | |
| argv: *const *const u8, | |
| sigpipe: u8, | |
| ) -> isize { | |
| lang_start_internal( | |
| &move || crate::sys::backtrace::__rust_begin_short_backtrace(main).report().to_i32(), | |
| argc, | |
| argv, | |
| sigpipe, | |
| ) | |
| } |