diff --git a/src/pthread/mod.rs b/src/pthread/mod.rs index 7755f7153f..6b67d63358 100644 --- a/src/pthread/mod.rs +++ b/src/pthread/mod.rs @@ -172,6 +172,14 @@ pub(crate) unsafe fn create( new_tcb.pthread.flags = flags.bits().into(); new_tcb.pthread.stack_base = stack_base; new_tcb.pthread.stack_size = stack_size; + // Initialize the robust mutex list head to null. The + // Pthread struct is zero-initialized in Tcb::new but we + // set this explicitly for documentation/clarity, and to + // guard against future changes that might not zero the + // struct (e.g. a switch to Box>). + // Without this, the first pthread_mutex_lock of a + // ROBUST mutex would dereference an uninitialized pointer. + new_tcb.pthread.robust_list_head = UnsafeCell::new(core::ptr::null_mut()); new_tcb.masters_ptr = current_tcb.masters_ptr; new_tcb.masters_len = current_tcb.masters_len; diff --git a/src/sync/pthread_mutex.rs b/src/sync/pthread_mutex.rs index af0c42926b..160a93152e 100644 --- a/src/sync/pthread_mutex.rs +++ b/src/sync/pthread_mutex.rs @@ -298,6 +298,15 @@ impl RlctMutex { pub(crate) unsafe fn mark_robust_mutexes_dead(thread: &crate::pthread::Pthread) { let head = thread.robust_list_head.get(); + // Null guard: if the thread's robust_list_head is null + // (e.g. the thread was created but never locked a robust + // mutex, or the kernel's robust list walk is invoked for a + // thread that doesn't support it), the list is empty and + // there's nothing to do. Without this check, dereferencing + // *head on a null pointer would be UB. + if (*head).is_null() { + return; + } let this_thread = os_tid_invalid_after_fork(); let mut node = unsafe { *head };