19
19
pub use crate :: panicking:: { begin_panic, panic_count} ;
20
20
pub use core:: panicking:: { panic_display, panic_fmt} ;
21
21
22
+ use crate :: any:: Any ;
22
23
use crate :: sync:: Once ;
23
24
use crate :: sys;
24
25
use crate :: thread:: { self , Thread } ;
26
+ use crate :: { mem, panic} ;
25
27
26
28
// Prints to the "panic output", depending on the platform this may be:
27
29
// - the standard error output
@@ -64,6 +66,11 @@ macro_rules! rtunwrap {
64
66
} ;
65
67
}
66
68
69
+ fn handle_rt_panic ( e : Box < dyn Any + Send > ) {
70
+ mem:: forget ( e) ;
71
+ rtabort ! ( "initialization or cleanup bug" ) ;
72
+ }
73
+
67
74
// One-time runtime initialization.
68
75
// Runs before `main`.
69
76
// SAFETY: must be called only once during runtime initialization.
@@ -99,6 +106,20 @@ unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
99
106
thread:: set_current ( thread) ;
100
107
}
101
108
109
+ /// Clean up the thread-local runtime state. This *should* be run after all other
110
+ /// code managed by the Rust runtime, but will not cause UB if that condition is
111
+ /// not fulfilled. Also note that this function is not guaranteed to be run, but
112
+ /// skipping it will cause leaks and therefore is to be avoided.
113
+ pub ( crate ) fn thread_cleanup ( ) {
114
+ // This function is run in situations where unwinding leads to an abort
115
+ // (think `extern "C"` functions). Abort here instead so that we can
116
+ // print a nice message.
117
+ panic:: catch_unwind ( || {
118
+ crate :: thread:: drop_current ( ) ;
119
+ } )
120
+ . unwrap_or_else ( handle_rt_panic) ;
121
+ }
122
+
102
123
// One-time runtime cleanup.
103
124
// Runs after `main` or at program exit.
104
125
// NOTE: this is not guaranteed to run, for example when the program aborts.
@@ -121,11 +142,6 @@ fn lang_start_internal(
121
142
argv : * const * const u8 ,
122
143
sigpipe : u8 ,
123
144
) -> 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
145
// Guard against the code called by this function from unwinding outside of the Rust-controlled
130
146
// code, which is UB. This is a requirement imposed by a combination of how the
131
147
// `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking
@@ -137,16 +153,17 @@ fn lang_start_internal(
137
153
// prevent std from accidentally introducing a panic to these functions. Another is from
138
154
// user code from `main` or, more nefariously, as described in e.g. issue #86030.
139
155
// SAFETY: Only called once during runtime initialization.
140
- panic:: catch_unwind ( move || unsafe { init ( argc, argv, sigpipe) } ) . map_err ( rt_abort) ?;
156
+ panic:: catch_unwind ( move || unsafe { init ( argc, argv, sigpipe) } )
157
+ . unwrap_or_else ( handle_rt_panic) ;
141
158
let ret_code = panic:: catch_unwind ( move || panic:: catch_unwind ( main) . unwrap_or ( 101 ) as isize )
142
159
. map_err ( move |e| {
143
160
mem:: forget ( e) ;
144
161
rtabort ! ( "drop of the panic payload panicked" ) ;
145
162
} ) ;
146
- panic:: catch_unwind ( cleanup) . map_err ( rt_abort ) ? ;
163
+ panic:: catch_unwind ( cleanup) . unwrap_or_else ( handle_rt_panic ) ;
147
164
// Guard against multple threads calling `libc::exit` concurrently.
148
165
// See the documentation for `unique_thread_exit` for more information.
149
- panic:: catch_unwind ( || crate :: sys:: exit_guard:: unique_thread_exit ( ) ) . map_err ( rt_abort ) ? ;
166
+ panic:: catch_unwind ( crate :: sys:: exit_guard:: unique_thread_exit) . unwrap_or_else ( handle_rt_panic ) ;
150
167
ret_code
151
168
}
152
169
0 commit comments