From 0bc47022d839d900c48e079b076e8d8a2a47d328 Mon Sep 17 00:00:00 2001 From: Juan Sebastian Hoyos Ayala Date: Thu, 5 Feb 2026 21:10:17 -0800 Subject: [PATCH] Fix missing release semantics in VolatilePtr VolatilePtr inherits from Volatile

, which defines operator=(P val) to call VolatileStore() with release semantics (stlr on ARM64). However, VolatilePtr did not declare its own operator=, so the compiler-generated copy/move assignment operator hid the base class operator= and performed plain stores (str) instead, bypassing the memory barrier entirely. This affected all VolatilePtr assignments including DeadlockAwareLock's m_pHoldingThread and Thread's m_pBlockingLock fields, which were being written without release semantics despite being read with acquire semantics (ldapr) on the other side. Fix by adding a using declaration to bring Volatile

::operator= into scope, and an explicit copy assignment operator (which the using declaration cannot suppress the compiler from generating). --- src/coreclr/gc/env/volatile.h | 10 ++++++++++ src/coreclr/inc/volatile.h | 13 +++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/coreclr/gc/env/volatile.h b/src/coreclr/gc/env/volatile.h index c15dcb1ca66448..8b414d5850fb76 100644 --- a/src/coreclr/gc/env/volatile.h +++ b/src/coreclr/gc/env/volatile.h @@ -469,6 +469,16 @@ class VolatilePtr : public Volatile

{ } + // + // Bring the base class operator= into scope. + // + using Volatile

::operator=; + + // + // Copy assignment operator. + // + inline VolatilePtr& operator=(const VolatilePtr& other) {this->Store(other.Load()); return *this;} + // // Cast to the pointer type // diff --git a/src/coreclr/inc/volatile.h b/src/coreclr/inc/volatile.h index 90fd1a766cb29a..c5b9c63fef76e3 100644 --- a/src/coreclr/inc/volatile.h +++ b/src/coreclr/inc/volatile.h @@ -531,6 +531,19 @@ class VolatilePtr : public Volatile

STATIC_CONTRACT_SUPPORTS_DAC; } + // + // Bring the base class operator= into scope. Without this, the compiler-generated + // copy assignment operator hides Volatile

::operator= and performs a plain store, + // bypassing the memory barriers provided by VolatileStore. + // + using Volatile

::operator=; + + // + // Copy assignment operator. The using declaration above does not suppress the + // compiler-generated copy assignment, so we must define it explicitly. + // + inline VolatilePtr& operator=(const VolatilePtr& other) {this->Store(other.Load()); return *this;} + // // Cast to the pointer type //