-
Notifications
You must be signed in to change notification settings - Fork 118
Closed
Description
I developed a static analysis tool to detect issues related to memory ordering, thread performance, and security. During my examination of several crates, I encountered alarms triggered by the following code:
Lines 213 to 232 in c48d3c2
let node = Waiter { | |
thread: Cell::new(Some(thread::current())), | |
signaled: AtomicBool::new(false), | |
next: strict::map_addr(curr_queue, |q| q & !STATE_MASK), | |
}; | |
let me = &node as *const Waiter as *mut Waiter; | |
let exchange = queue.compare_exchange( | |
curr_queue, | |
strict::map_addr(me, |q| q | curr_state), | |
Ordering::Release, | |
Ordering::Relaxed, | |
); | |
if let Err(new_queue) = exchange { | |
if strict::addr(new_queue) & STATE_MASK != curr_state { | |
return; | |
} | |
curr_queue = new_queue; | |
continue; | |
} |
The meaning of the code should be that we need to have a successful initialization operation in Line222, but the compare exchange also entails reading the atomic pointer to the
exchange
. Therefore, it's necessary to use AcqRel
and Acquire
to observe any other modifications to the memory that the atomic pointer references, both when the compare exchange succeeds and when it fails.
I think compare exchange for queue
uses AcqRel
for the success case and Acquire
for the fail case.
(happy to make a PR if this looks reasonable)
matklad
Metadata
Metadata
Assignees
Labels
No labels