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 #![doc(hidden)] 10 #![deny(unsafe_op_in_unsafe_fn)] 11 #![allow(unused_macros)] 12 13 use crate::std::ffi::CString; 14 15 // Re-export some of our utilities which are expected by other crates. 16 pub use crate::std::panicking::{begin_panic, panic_count}; 17 pub use core::panicking::{panic_display, panic_fmt}; 18 19 use crate::std::sync::Once; 20 use crate::std::sys; 21 use crate::std::sys_common::thread_info; 22 use crate::std::thread::Thread; 23 24 // Prints to the "panic output", depending on the platform this may be: 25 // - the standard error output 26 // - some dedicated platform specific output 27 // - nothing (so this macro is a no-op) 28 macro_rules! rtprintpanic { 29 ($($t:tt)*) => { 30 if let Some(mut out) = crate::std::sys::stdio::panic_output() { 31 let _ = crate::std::io::Write::write_fmt(&mut out, format_args!($($t)*)); 32 } 33 } 34 } 35 36 macro_rules! rtabort { 37 ($($t:tt)*) => { 38 { 39 rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*)); 40 crate::std::sys::abort_internal(); 41 } 42 } 43 } 44 45 macro_rules! rtassert { 46 ($e:expr) => { 47 if !$e { 48 rtabort!(concat!("assertion failed: ", stringify!($e))); 49 } 50 }; 51 } 52 53 macro_rules! rtunwrap { 54 ($ok:ident, $e:expr) => { 55 match $e { 56 $ok(v) => v, 57 ref err => { 58 let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug 59 rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err) 60 } 61 } 62 }; 63 } 64 65 // One-time runtime initialization. 66 // Runs before `main`. 67 // SAFETY: must be called only once during runtime initialization. 68 // NOTE: this is not guaranteed to run, for example when Rust code is called externally. 69 // 70 // # The `sigpipe` parameter 71 // 72 // Since 2014, the Rust runtime on Unix has set the `SIGPIPE` handler to 73 // `SIG_IGN`. Applications have good reasons to want a different behavior 74 // though, so there is a `#[unix_sigpipe = "..."]` attribute on `fn main()` that 75 // can be used to select how `SIGPIPE` shall be setup (if changed at all) before 76 // `fn main()` is called. See <https://github.com/rust-lang/rust/issues/97889> 77 // for more info. 78 // 79 // The `sigpipe` parameter to this function gets its value via the code that 80 // rustc generates to invoke `fn lang_start()`. The reason we have `sigpipe` for 81 // all platforms and not only Unix, is because std is not allowed to have `cfg` 82 // directives as this high level. See the module docs in 83 // `src/tools/tidy/src/pal.rs` for more info. On all other platforms, `sigpipe` 84 // has a value, but its value is ignored. 85 // 86 // Even though it is an `u8`, it only ever has 4 values. These are documented in 87 // `compiler/rustc_session/src/config/sigpipe.rs`. 88 #[cfg_attr(test, allow(dead_code))] 89 #[allow(dead_code)] 90 unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { 91 unsafe { 92 sys::init(argc, argv, sigpipe); 93 94 let main_guard = sys::thread::guard::init(); 95 // Next, set up the current Thread with the guard information we just 96 // created. Note that this isn't necessary in general for new threads, 97 // but we just do this to name the main thread and to give it correct 98 // info about the stack bounds. 99 let thread = Thread::new(Some(rtunwrap!(Ok, CString::new("main")))); 100 thread_info::set(main_guard, thread); 101 } 102 } 103 104 // One-time runtime cleanup. 105 // Runs after `main` or at program exit. 106 // NOTE: this is not guaranteed to run, for example when the program aborts. 107 pub(crate) fn cleanup() { 108 static CLEANUP: Once = Once::new(); 109 CLEANUP.call_once(|| unsafe { 110 // Flush stdout and disable buffering. 111 crate::std::io::cleanup(); 112 // SAFETY: Only called once during runtime cleanup. 113 sys::cleanup(); 114 }); 115 } 116 117 // To reduce the generated code of the new `lang_start`, this function is doing 118 // the real work. 119 #[cfg(not(test))] 120 #[allow(dead_code)] 121 fn lang_start_internal( 122 main: &(dyn Fn() -> i32 + Sync + crate::std::panic::RefUnwindSafe), 123 argc: isize, 124 argv: *const *const u8, 125 sigpipe: u8, 126 ) -> Result<isize, !> { 127 use crate::std::{mem, panic}; 128 let rt_abort = move |e| { 129 mem::forget(e); 130 rtabort!("initialization or cleanup bug"); 131 }; 132 // Guard against the code called by this function from unwinding outside of the Rust-controlled 133 // code, which is UB. This is a requirement imposed by a combination of how the 134 // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking 135 // mechanism itself. 136 // 137 // There are a couple of instances where unwinding can begin. First is inside of the 138 // `rt::init`, `rt::cleanup` and similar functions controlled by bstd. In those instances a 139 // panic is a std implementation bug. A quite likely one too, as there isn't any way to 140 // prevent std from accidentally introducing a panic to these functions. Another is from 141 // user code from `main` or, more nefariously, as described in e.g. issue #86030. 142 // SAFETY: Only called once during runtime initialization. 143 panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?; 144 let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize) 145 .map_err(move |e| { 146 mem::forget(e); 147 rtabort!("drop of the panic payload panicked"); 148 }); 149 panic::catch_unwind(cleanup).map_err(rt_abort)?; 150 ret_code 151 } 152 153 // #[cfg(not(test))] 154 // #[lang = "start"] 155 // fn lang_start<T: crate::std::process::Termination + 'static>( 156 // main: fn() -> T, 157 // argc: isize, 158 // argv: *const *const u8, 159 // sigpipe: u8, 160 // ) -> isize { 161 // let Ok(v) = lang_start_internal( 162 // &move || crate::std::sys_common::backtrace::__rust_begin_short_backtrace(main).report().to_i32(), 163 // argc, 164 // argv, 165 // sigpipe, 166 // ); 167 // v 168 // } 169