@@ -21,9 +21,10 @@ pub use crate::panicking::{begin_panic, panic_count};
2121pub use core:: panicking:: { panic_display, panic_fmt} ;
2222
2323#[ rustfmt:: skip]
24+ use crate :: any:: Any ;
2425use crate :: sync:: Once ;
25- use crate :: sys;
2626use crate :: thread:: { self , Thread } ;
27+ use crate :: { mem, panic, sys} ;
2728
2829// Prints to the "panic output", depending on the platform this may be:
2930// - the standard error output
@@ -66,6 +67,11 @@ macro_rules! rtunwrap {
6667 } ;
6768}
6869
70+ fn handle_rt_panic ( e : Box < dyn Any + Send > ) {
71+ mem:: forget ( e) ;
72+ rtabort ! ( "initialization or cleanup bug" ) ;
73+ }
74+
6975// One-time runtime initialization.
7076// Runs before `main`.
7177// SAFETY: must be called only once during runtime initialization.
@@ -101,6 +107,20 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
101107 thread:: set_current ( thread) ;
102108}
103109
110+ /// Clean up the thread-local runtime state. This *should* be run after all other
111+ /// code managed by the Rust runtime, but will not cause UB if that condition is
112+ /// not fulfilled. Also note that this function is not guaranteed to be run, but
113+ /// skipping it will cause leaks and therefore is to be avoided.
114+ pub ( crate ) fn thread_cleanup ( ) {
115+ // This function is run in situations where unwinding leads to an abort
116+ // (think `extern "C"` functions). Abort here instead so that we can
117+ // print a nice message.
118+ panic:: catch_unwind ( || {
119+ crate :: thread:: drop_current ( ) ;
120+ } )
121+ . unwrap_or_else ( handle_rt_panic) ;
122+ }
123+
104124// One-time runtime cleanup.
105125// Runs after `main` or at program exit.
106126// NOTE: this is not guaranteed to run, for example when the program aborts.
@@ -123,11 +143,6 @@ fn lang_start_internal(
123143 argv : * const * const u8 ,
124144 sigpipe : u8 ,
125145) -> Result < isize , !> {
126- use crate :: { mem, panic} ;
127- let rt_abort = move |e| {
128- mem:: forget ( e) ;
129- rtabort ! ( "initialization or cleanup bug" ) ;
130- } ;
131146 // Guard against the code called by this function from unwinding outside of the Rust-controlled
132147 // code, which is UB. This is a requirement imposed by a combination of how the
133148 // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking
@@ -139,16 +154,17 @@ fn lang_start_internal(
139154 // prevent std from accidentally introducing a panic to these functions. Another is from
140155 // user code from `main` or, more nefariously, as described in e.g. issue #86030.
141156 // SAFETY: Only called once during runtime initialization.
142- panic:: catch_unwind ( move || unsafe { init ( argc, argv, sigpipe) } ) . map_err ( rt_abort) ?;
157+ panic:: catch_unwind ( move || unsafe { init ( argc, argv, sigpipe) } )
158+ . unwrap_or_else ( handle_rt_panic) ;
143159 let ret_code = panic:: catch_unwind ( move || panic:: catch_unwind ( main) . unwrap_or ( 101 ) as isize )
144160 . map_err ( move |e| {
145161 mem:: forget ( e) ;
146162 rtabort ! ( "drop of the panic payload panicked" ) ;
147163 } ) ;
148- panic:: catch_unwind ( cleanup) . map_err ( rt_abort ) ? ;
164+ panic:: catch_unwind ( cleanup) . unwrap_or_else ( handle_rt_panic ) ;
149165 // Guard against multiple threads calling `libc::exit` concurrently.
150166 // See the documentation for `unique_thread_exit` for more information.
151- panic:: catch_unwind ( || crate :: sys:: exit_guard:: unique_thread_exit ( ) ) . map_err ( rt_abort ) ? ;
167+ panic:: catch_unwind ( crate :: sys:: exit_guard:: unique_thread_exit) . unwrap_or_else ( handle_rt_panic ) ;
152168 ret_code
153169}
154170
0 commit comments