]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
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 | ||
60c5eb7d XL |
9 | #![unstable( |
10 | feature = "rt", | |
11 | reason = "this public module should not exist and is highly likely \ | |
12 | to disappear", | |
dfeec247 | 13 | issue = "none" |
60c5eb7d | 14 | )] |
e9174d1e | 15 | #![doc(hidden)] |
c295e0f8 XL |
16 | #![deny(unsafe_op_in_unsafe_fn)] |
17 | #![allow(unused_macros)] | |
18 | ||
19 | use crate::ffi::CString; | |
e9174d1e | 20 | |
2c00a5a8 | 21 | // Re-export some of our utilities which are expected by other crates. |
3c0e092e XL |
22 | pub use crate::panicking::{begin_panic, panic_count}; |
23 | pub use core::panicking::{panic_display, panic_fmt}; | |
c295e0f8 XL |
24 | |
25 | use crate::sync::Once; | |
26 | use crate::sys; | |
27 | use crate::sys_common::thread_info; | |
28 | use crate::thread::Thread; | |
29 | ||
30 | // Prints to the "panic output", depending on the platform this may be: | |
31 | // - the standard error output | |
32 | // - some dedicated platform specific output | |
33 | // - nothing (so this macro is a no-op) | |
34 | macro_rules! rtprintpanic { | |
35 | ($($t:tt)*) => { | |
36 | if let Some(mut out) = crate::sys::stdio::panic_output() { | |
37 | let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*)); | |
38 | } | |
39 | } | |
40 | } | |
41 | ||
42 | macro_rules! rtabort { | |
43 | ($($t:tt)*) => { | |
44 | { | |
45 | rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*)); | |
46 | crate::sys::abort_internal(); | |
47 | } | |
48 | } | |
49 | } | |
50 | ||
51 | macro_rules! rtassert { | |
52 | ($e:expr) => { | |
53 | if !$e { | |
54 | rtabort!(concat!("assertion failed: ", stringify!($e))); | |
55 | } | |
56 | }; | |
57 | } | |
58 | ||
59 | macro_rules! rtunwrap { | |
60 | ($ok:ident, $e:expr) => { | |
61 | match $e { | |
62 | $ok(v) => v, | |
63 | ref err => { | |
64 | let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug | |
65 | rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err) | |
66 | } | |
67 | } | |
68 | }; | |
69 | } | |
70 | ||
71 | // One-time runtime initialization. | |
72 | // Runs before `main`. | |
73 | // SAFETY: must be called only once during runtime initialization. | |
74 | // NOTE: this is not guaranteed to run, for example when Rust code is called externally. | |
75 | #[cfg_attr(test, allow(dead_code))] | |
76 | unsafe fn init(argc: isize, argv: *const *const u8) { | |
77 | unsafe { | |
78 | sys::init(argc, argv); | |
79 | ||
80 | let main_guard = sys::thread::guard::init(); | |
81 | // Next, set up the current Thread with the guard information we just | |
82 | // created. Note that this isn't necessary in general for new threads, | |
83 | // but we just do this to name the main thread and to give it correct | |
84 | // info about the stack bounds. | |
85 | let thread = Thread::new(Some(rtunwrap!(Ok, CString::new("main")))); | |
86 | thread_info::set(main_guard, thread); | |
87 | } | |
88 | } | |
89 | ||
90 | // One-time runtime cleanup. | |
91 | // Runs after `main` or at program exit. | |
92 | // NOTE: this is not guaranteed to run, for example when the program aborts. | |
93 | pub(crate) fn cleanup() { | |
94 | static CLEANUP: Once = Once::new(); | |
95 | CLEANUP.call_once(|| unsafe { | |
96 | // Flush stdout and disable buffering. | |
97 | crate::io::cleanup(); | |
98 | // SAFETY: Only called once during runtime cleanup. | |
99 | sys::cleanup(); | |
100 | }); | |
101 | } | |
e9174d1e | 102 | |
ff7c6d11 XL |
103 | // To reduce the generated code of the new `lang_start`, this function is doing |
104 | // the real work. | |
2c00a5a8 | 105 | #[cfg(not(test))] |
60c5eb7d XL |
106 | fn lang_start_internal( |
107 | main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe), | |
108 | argc: isize, | |
109 | argv: *const *const u8, | |
136023e0 | 110 | ) -> Result<isize, !> { |
c295e0f8 | 111 | use crate::{mem, panic}; |
136023e0 XL |
112 | let rt_abort = move |e| { |
113 | mem::forget(e); | |
114 | rtabort!("initialization or cleanup bug"); | |
115 | }; | |
116 | // Guard against the code called by this function from unwinding outside of the Rust-controlled | |
117 | // code, which is UB. This is a requirement imposed by a combination of how the | |
118 | // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking | |
119 | // mechanism itself. | |
120 | // | |
121 | // There are a couple of instances where unwinding can begin. First is inside of the | |
122 | // `rt::init`, `rt::cleanup` and similar functions controlled by libstd. In those instances a | |
123 | // panic is a libstd implementation bug. A quite likely one too, as there isn't any way to | |
124 | // prevent libstd from accidentally introducing a panic to these functions. Another is from | |
125 | // user code from `main` or, more nefariously, as described in e.g. issue #86030. | |
cdc7bbd5 | 126 | // SAFETY: Only called once during runtime initialization. |
c295e0f8 | 127 | panic::catch_unwind(move || unsafe { init(argc, argv) }).map_err(rt_abort)?; |
136023e0 XL |
128 | let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize) |
129 | .map_err(move |e| { | |
130 | mem::forget(e); | |
3c0e092e | 131 | rtabort!("drop of the panic payload panicked"); |
136023e0 | 132 | }); |
c295e0f8 | 133 | panic::catch_unwind(cleanup).map_err(rt_abort)?; |
136023e0 | 134 | ret_code |
ff7c6d11 XL |
135 | } |
136 | ||
2c00a5a8 | 137 | #[cfg(not(test))] |
ff7c6d11 | 138 | #[lang = "start"] |
60c5eb7d XL |
139 | fn lang_start<T: crate::process::Termination + 'static>( |
140 | main: fn() -> T, | |
141 | argc: isize, | |
142 | argv: *const *const u8, | |
143 | ) -> isize { | |
c295e0f8 | 144 | let Ok(v) = lang_start_internal( |
5099ac24 | 145 | &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report().to_i32(), |
3dfed10e XL |
146 | argc, |
147 | argv, | |
c295e0f8 XL |
148 | ); |
149 | v | |
ff7c6d11 | 150 | } |