File tree 1 file changed +12
-1
lines changed
1 file changed +12
-1
lines changed Original file line number Diff line number Diff line change @@ -213,6 +213,11 @@ impl<T> Channel<T> {
213
213
. compare_exchange ( block, new, Ordering :: Release , Ordering :: Relaxed )
214
214
. is_ok ( )
215
215
{
216
+ // This yield point leaves the channel in a half-initialized state where the
217
+ // tail.block pointer is set but the head.block is not. This is used to
218
+ // facilitate the test in src/tools/miri/tests/pass/issues/issue-139553.rs
219
+ #[ cfg( miri) ]
220
+ crate :: thread:: yield_now ( ) ;
216
221
self . head . block . store ( new, Ordering :: Release ) ;
217
222
block = new;
218
223
} else {
@@ -564,9 +569,15 @@ impl<T> Channel<T> {
564
569
// In that case, just wait until it gets initialized.
565
570
while block. is_null ( ) {
566
571
backoff. spin_heavy ( ) ;
567
- block = self . head . block . load ( Ordering :: Acquire ) ;
572
+ block = self . head . block . swap ( ptr :: null_mut ( ) , Ordering :: AcqRel ) ;
568
573
}
569
574
}
575
+ // After this point `head.block` is not modified again and it will be deallocated if it's
576
+ // non-null. The `Drop` code of the channel, which runs after this function, also attempts
577
+ // to deallocate `head.block` if it's non-null. Therefore this function must maintain the
578
+ // invariant that if a deallocation of head.block is attemped then it must also be set to
579
+ // NULL. Failing to do so will lead to the Drop code attempting a double free. For this
580
+ // reason both reads above do an atomic swap instead of a simple atomic load.
570
581
571
582
unsafe {
572
583
// Drop all messages between head and tail and deallocate the heap-allocated blocks.
You can’t perform that action at this time.
0 commit comments