Skip to content

Commit f46b255

Browse files
committed
std: detect stack overflows in TLS destructors on UNIX
Fixes rust-lang#111272. With rust-lang#127912 merged, we now have all the infrastructure in place to support stack overflow detection in TLS destructors. This was not possible before because the signal stack was freed in the thread main function, thus a SIGSEGV afterwards would immediately crash. And on platforms without native TLS, the guard page address was stored in an allocation freed in a TLS destructor, so would not be available. rust-lang#127912 introduced the `local_pointer` macro which allows storing a pointer-sized TLS variable without allocation and the `thread_cleanup` runtime function which is called after all other code managed by the Rust runtime. This PR simply moves the signal stack cleanup to the end of `thread_cleanup` and uses `local_pointer` to store every necessary variable. And so, everything run under the Rust runtime is now properly protected against stack overflows.
1 parent 11ee3a8 commit f46b255

File tree

13 files changed

+196
-177
lines changed

13 files changed

+196
-177
lines changed

library/std/src/rt.rs

+1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ pub(crate) fn thread_cleanup() {
117117
// print a nice message.
118118
panic::catch_unwind(|| {
119119
crate::thread::drop_current();
120+
crate::sys::thread_cleanup();
120121
})
121122
.unwrap_or_else(handle_rt_panic);
122123
}

library/std/src/sys/pal/hermit/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
6969
}
7070
}
7171

72+
pub fn thread_cleanup() {}
73+
7274
// SAFETY: must be called only once during runtime cleanup.
7375
// NOTE: this is not guaranteed to run, for example when the program aborts.
7476
pub unsafe fn cleanup() {}

library/std/src/sys/pal/sgx/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
3737
}
3838
}
3939

40+
pub fn thread_cleanup() {}
41+
4042
// SAFETY: must be called only once during runtime cleanup.
4143
// NOTE: this is not guaranteed to run, for example when the program aborts.
4244
pub unsafe fn cleanup() {}

library/std/src/sys/pal/solid/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ pub mod time;
3838
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
3939
pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
4040

41+
pub fn thread_cleanup() {}
42+
4143
// SAFETY: must be called only once during runtime cleanup.
4244
pub unsafe fn cleanup() {}
4345

library/std/src/sys/pal/teeos/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ pub fn abort_internal() -> ! {
3737
// so this should never be called.
3838
pub fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {}
3939

40+
pub fn thread_cleanup() {}
41+
4042
// SAFETY: must be called only once during runtime cleanup.
4143
// this is not guaranteed to run, for example when the program aborts.
4244
pub unsafe fn cleanup() {

library/std/src/sys/pal/uefi/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ pub(crate) unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
7777
}
7878
}
7979

80+
pub fn thread_cleanup() {}
81+
8082
/// # SAFETY
8183
/// this is not guaranteed to run, for example when the program aborts.
8284
/// - must be called only once during runtime cleanup.

library/std/src/sys/pal/unix/mod.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
5454
// behavior.
5555
reset_sigpipe(sigpipe);
5656

57-
stack_overflow::init();
57+
stack_overflow::protect(true);
5858
args::init(argc, argv);
5959

6060
// Normally, `thread::spawn` will call `Thread::set_name` but since this thread
@@ -228,12 +228,14 @@ pub(crate) fn on_broken_pipe_flag_used() -> bool {
228228
ON_BROKEN_PIPE_FLAG_USED.load(crate::sync::atomic::Ordering::Relaxed)
229229
}
230230

231-
// SAFETY: must be called only once during runtime cleanup.
232-
// NOTE: this is not guaranteed to run, for example when the program aborts.
233-
pub unsafe fn cleanup() {
231+
pub fn thread_cleanup() {
234232
stack_overflow::cleanup();
235233
}
236234

235+
// SAFETY: must be called only once during runtime cleanup.
236+
// NOTE: this is not guaranteed to run, for example when the program aborts.
237+
pub unsafe fn cleanup() {}
238+
237239
#[allow(unused_imports)]
238240
pub use libc::signal;
239241

0 commit comments

Comments
 (0)