Skip to content

Commit 2eff4d0

Browse files
author
Michael Grier
committed
Fix CAS bug, add tests
1 parent 84c70c9 commit 2eff4d0

2 files changed

Lines changed: 529 additions & 8 deletions

File tree

src/libraries/arefc_ptr/include/m/arefc_ptr/arefc_ptr.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,8 @@ namespace m
602602

603603
T* old_e = e; // save a copy so we don't have to re-load
604604

605+
// Pre-increment d's refcount so that if the CAS succeeds, m_ptr holds
606+
// a valid reference to d without a window where the refcount is zero.
605607
increment_ref(d);
606608

607609
if (m_ptr.compare_exchange_strong(e, d, std::memory_order_acq_rel))
@@ -613,8 +615,12 @@ namespace m
613615
return true;
614616
}
615617

616-
// The compare_exchange "failed", so now we need to update
617-
// "expected" to the new value.
618+
// The CAS failed: m_ptr still holds its current value (now captured in `e`).
619+
// `d` was pre-incremented above but was never stored in m_ptr, so we must
620+
// undo that increment to avoid a permanent ref-count leak on `desired`.
621+
decrement_ref(d);
622+
623+
// Update `expected` to reflect the actual current value of m_ptr.
618624
expected.reset(e);
619625

620626
return false;
@@ -692,6 +698,13 @@ namespace m
692698

693699
std::atomic<T*> m_ptr{nullptr};
694700

701+
// All specializations of arefc_ptr are friends of each other so that the
702+
// cross-type converting constructor and assignment operators can call the
703+
// private addref() / put() members on a related specialization.
704+
template <typename U>
705+
requires(arefc_ptr_requirements<U>)
706+
friend class arefc_ptr;
707+
695708
template <typename T1, typename... Args>
696709
requires(arefc_ptr_requirements<T1>)
697710
friend arefc_ptr<T1>

0 commit comments

Comments
 (0)