Skip to content

Commit bd89e61

Browse files
authored
Merge pull request #35369 from mikeash/fix-concurrentarray-memory-order2-5.4
[5.4][Runtime] Fix incorrect memory ordering in ConcurrentReadableArray/HashMap
2 parents 406291b + 118a6b0 commit bd89e61

File tree

2 files changed

+338
-296
lines changed

2 files changed

+338
-296
lines changed

include/swift/Runtime/Concurrent.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -527,13 +527,18 @@ template <class ElemTy> struct ConcurrentReadableArray {
527527

528528
storage = newStorage;
529529
Capacity = newCapacity;
530-
Elements.store(storage, std::memory_order_release);
530+
531+
// Use seq_cst here to ensure that the subsequent load of ReaderCount is
532+
// ordered after this store. If ReaderCount is loaded first, then a new
533+
// reader could come in between that load and this store, and then we
534+
// could end up freeing the old storage pointer while it's still in use.
535+
Elements.store(storage, std::memory_order_seq_cst);
531536
}
532537

533538
new(&storage->data()[count]) ElemTy(elem);
534539
storage->Count.store(count + 1, std::memory_order_release);
535540

536-
if (ReaderCount.load(std::memory_order_acquire) == 0)
541+
if (ReaderCount.load(std::memory_order_seq_cst) == 0)
537542
deallocateFreeList();
538543
}
539544

@@ -848,7 +853,7 @@ struct ConcurrentReadableHashMap {
848853
/// Free all the arrays in the free lists if there are no active readers. If
849854
/// there are active readers, do nothing.
850855
void deallocateFreeListIfSafe() {
851-
if (ReaderCount.load(std::memory_order_acquire) == 0)
856+
if (ReaderCount.load(std::memory_order_seq_cst) == 0)
852857
FreeListNode::freeAll(&FreeList);
853858
}
854859

@@ -866,7 +871,11 @@ struct ConcurrentReadableHashMap {
866871
FreeListNode::add(&FreeList, elements);
867872
}
868873

869-
Elements.store(newElements, std::memory_order_release);
874+
// Use seq_cst here to ensure that the subsequent load of ReaderCount is
875+
// ordered after this store. If ReaderCount is loaded first, then a new
876+
// reader could come in between that load and this store, and then we
877+
// could end up freeing the old elements pointer while it's still in use.
878+
Elements.store(newElements, std::memory_order_seq_cst);
870879
return newElements;
871880
}
872881

@@ -900,7 +909,11 @@ struct ConcurrentReadableHashMap {
900909
newIndices.storeIndexAt(nullptr, index, newI, std::memory_order_relaxed);
901910
}
902911

903-
Indices.store(newIndices.Value, std::memory_order_release);
912+
// Use seq_cst here to ensure that the subsequent load of ReaderCount is
913+
// ordered after this store. If ReaderCount is loaded first, then a new
914+
// reader could come in between that load and this store, and then we
915+
// could end up freeing the old indices pointer while it's still in use.
916+
Indices.store(newIndices.Value, std::memory_order_seq_cst);
904917

905918
if (auto *ptr = indices.pointer())
906919
FreeListNode::add(&FreeList, ptr);

0 commit comments

Comments
 (0)