Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guard against calling libc::exit multiple times on Linux. #126606

Merged
merged 12 commits into from
Jul 13, 2024
Prev Previous commit
Attempt to fix CI
  • Loading branch information
zachs18 authored Jul 8, 2024
commit 8bcbab5dd1c6449c2acd3ea6a94b245c0936722d
15 changes: 12 additions & 3 deletions library/std/src/sys/exit_guard.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
cfg_if::cfg_if! {
if #[cfg(target_os = "linux")] {
/// pthread_t is a pointer on some platforms,
/// so we wrap it in this to impl Send + Sync.
#[derive(Clone, Copy)]
#[repr(transparent)]
struct PThread(libc::pthread_t);
// Safety: pthread_t is safe to send between threads
unsafe impl Send for PThread {}
// Safety: pthread_t is safe to share between threads
unsafe impl Sync for PThread {}
/// Mitigation for <https://github.com/rust-lang/rust/issues/126600>
///
/// On glibc, `libc::exit` has been observed to not always be thread-safe.
Expand All @@ -23,17 +32,17 @@ cfg_if::cfg_if! {
pub(crate) fn unique_thread_exit() {
let this_thread_id = unsafe { libc::pthread_self() };
use crate::sync::{Mutex, PoisonError};
static EXITING_THREAD_ID: Mutex<Option<libc::pthread_t>> = Mutex::new(None);
static EXITING_THREAD_ID: Mutex<Option<PThread>> = Mutex::new(None);
let mut exiting_thread_id =
EXITING_THREAD_ID.lock().unwrap_or_else(PoisonError::into_inner);
match *exiting_thread_id {
None => {
// This is the first thread to call `unique_thread_exit`,
// and this is the first time it is called.
// Set EXITING_THREAD_ID to this thread's ID and return.
*exiting_thread_id = Some(this_thread_id);
*exiting_thread_id = Some(PThread(this_thread_id));
},
Some(exiting_thread_id) if exiting_thread_id == this_thread_id => {
Some(exiting_thread_id) if exiting_thread_id.0 == this_thread_id => {
// This is the first thread to call `unique_thread_exit`,
// but this is the second time it is called.
// Abort the process.
Expand Down
Loading