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