Skip to content

Commit

Permalink
std: detect stack overflows in TLS destructors on UNIX
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
joboet committed Oct 5, 2024
1 parent 11ee3a8 commit f46b255
Show file tree
Hide file tree
Showing 13 changed files with 196 additions and 177 deletions.
1 change: 1 addition & 0 deletions library/std/src/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ pub(crate) fn thread_cleanup() {
// print a nice message.
panic::catch_unwind(|| {
crate::thread::drop_current();
crate::sys::thread_cleanup();
})
.unwrap_or_else(handle_rt_panic);
}
Expand Down
2 changes: 2 additions & 0 deletions library/std/src/sys/pal/hermit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
}
}

pub fn thread_cleanup() {}

// SAFETY: must be called only once during runtime cleanup.
// NOTE: this is not guaranteed to run, for example when the program aborts.
pub unsafe fn cleanup() {}
Expand Down
2 changes: 2 additions & 0 deletions library/std/src/sys/pal/sgx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
}
}

pub fn thread_cleanup() {}

// SAFETY: must be called only once during runtime cleanup.
// NOTE: this is not guaranteed to run, for example when the program aborts.
pub unsafe fn cleanup() {}
Expand Down
2 changes: 2 additions & 0 deletions library/std/src/sys/pal/solid/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ pub mod time;
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}

pub fn thread_cleanup() {}

// SAFETY: must be called only once during runtime cleanup.
pub unsafe fn cleanup() {}

Expand Down
2 changes: 2 additions & 0 deletions library/std/src/sys/pal/teeos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub fn abort_internal() -> ! {
// so this should never be called.
pub fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {}

pub fn thread_cleanup() {}

// SAFETY: must be called only once during runtime cleanup.
// this is not guaranteed to run, for example when the program aborts.
pub unsafe fn cleanup() {
Expand Down
2 changes: 2 additions & 0 deletions library/std/src/sys/pal/uefi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ pub(crate) unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
}
}

pub fn thread_cleanup() {}

/// # SAFETY
/// this is not guaranteed to run, for example when the program aborts.
/// - must be called only once during runtime cleanup.
Expand Down
10 changes: 6 additions & 4 deletions library/std/src/sys/pal/unix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
// behavior.
reset_sigpipe(sigpipe);

stack_overflow::init();
stack_overflow::protect(true);
args::init(argc, argv);

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

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

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

#[allow(unused_imports)]
pub use libc::signal;

Expand Down
Loading

0 comments on commit f46b255

Please sign in to comment.