From 6a5154ddda28ed9fa286ede1c5254cbf75e0807f Mon Sep 17 00:00:00 2001 From: Brad Barnich Date: Sat, 4 Jul 2026 20:25:43 -0400 Subject: [PATCH] Publish handle assignments with release semantics GC handles can be observed by other threads after assignment. On weakly ordered ARM64 systems, a plain store to the handle slot can publish the object reference before prior object initialization writes are visible to the observing thread. Use VolatileStore when assigning handle slots in HndAssignHandle and HndAssignHandleGC so the handle publication is a release store. This matches the runtime's volatile publication pattern and prevents weak-reference readers from seeing partially initialized objects. --- src/coreclr/gc/handletable.inl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/coreclr/gc/handletable.inl b/src/coreclr/gc/handletable.inl index de4ab2a9db9515..c21d835ea11c4d 100644 --- a/src/coreclr/gc/handletable.inl +++ b/src/coreclr/gc/handletable.inl @@ -43,8 +43,9 @@ inline void HndAssignHandle(OBJECTHANDLE handle, OBJECTREF objref) if (value) HndWriteBarrier(handle, objref); - // store the pointer - *(_UNCHECKED_OBJECTREF *)handle = value; + // Store the pointer with release semantics so object field writes are visible + // before the handle can publish the object to another thread. + VolatileStore((_UNCHECKED_OBJECTREF *)handle, value); } // This is used by the GC before we actually construct the object so we cannot @@ -69,8 +70,9 @@ inline void HndAssignHandleGC(OBJECTHANDLE handle, uint8_t* objref) if (value) HndWriteBarrierWorker(handle, value); - // store the pointer - *(_UNCHECKED_OBJECTREF *)handle = value; + // Store the pointer with release semantics so object field writes are visible + // before the handle can publish the object to another thread. + VolatileStore((_UNCHECKED_OBJECTREF *)handle, value); } inline void* HndInterlockedCompareExchangeHandle(OBJECTHANDLE handle, OBJECTREF objref, OBJECTREF oldObjref)