From 010d6ead042d8bfc9f9db0218867b3a137e2fcba 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 e1c014543139a0..21a83f9b682054 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 efcb25f8acd8a5..5d42fc0ffbd95c 100644 --- a/src/coreclr/inc/volatile.h +++ b/src/coreclr/inc/volatile.h @@ -517,6 +517,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 //