relibc: init Pthread.robust_list_head in create() and add null guard
Two fixes for the Pthread.robust_list_head field added in
P5-robust-mutexes:
1. create() at src/pthread/mod.rs:172 didn't initialize the
new_tcb.pthread.robust_list_head. The Tcb::new memory
happens to be zeroed, so the first non-main thread's first
pthread_mutex_lock of a ROBUST mutex would have
robust_list_head = 0 (null), which the original code at
src/sync/pthread_mutex.rs:301 dereferences with
'let mut node = unsafe { *head }' — that's a UB on null.
Add explicit init to null in create() so the invariant is
documented and future Tcb::new changes (e.g. switching to
MaybeUninit for performance) don't break the assumption.
2. mark_robust_mutexes_dead at src/sync/pthread_mutex.rs:299
dereferences *head without a null check. Even with the init
fix above, a thread may legitimately have an empty robust list
(never locked a robust mutex). Add the null guard so the
function is a no-op for empty lists.
Discovered by Oracle review of Phase 0c patches (Issue 4).
The init was missing because P5-robust-mutexes was applied as
an overlay patch that referenced the field but didn't include
the init line in the right scope.
This commit is contained in:
@@ -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<MaybeUninit<Pthread>>).
|
||||
// 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;
|
||||
|
||||
@@ -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 };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user