Skip to content

Commit 9baed28

Browse files
davidwrightonCopilotAaronRobinsonMSFT
authored
Fix token memory ordering issue reading from the MethodDef and FieldDef token tables (#123557)
We have logic which loads a typedef, and if the typedef is loaded then we assume the method can be loaded via lookup in the MethodDef/FieldDef token map tables. HOWEVER, what this boils down to is we do a load from the TypeDef table, and if that succeeds we will do a load from the FieldDef/MethodDef token map tables, but that second load is done without an explicit memory barrier. Unfortunately, through the wonder of memory ordering behavior, its legal (and not actually all that uncommon) for the CPU to do the load from the FieldDef/MethodDef tables BEFORE it actually loads from the TypeDef table. So what can happen is that the fielddef table read can happen, then the typedef table read can happen, then the CPU does the if check to see if its ok to do the fielddef table read, then we use the value from the fielddef table read which happened earlier. This fix should fix that problem by using a VolatileLoad for all reads from the lookup maps. This is slightly slower but avoids the extremely easy to mess up dependency ordering rules. Fixes #120754 --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Aaron R Robinson <arobins@microsoft.com>
1 parent 687c8d9 commit 9baed28

File tree

1 file changed

+14
-2
lines changed

1 file changed

+14
-2
lines changed

src/coreclr/vm/ceeload.inl

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@ TYPE LookupMap<TYPE>::GetValueAt(PTR_TADDR pValue, TADDR* pFlags, TADDR supporte
1818
WRAPPER_NO_CONTRACT;
1919
SUPPORTS_DAC;
2020
#ifndef DACCESS_COMPILE
21-
TYPE value = dac_cast<TYPE>(VolatileLoadWithoutBarrier(pValue)); // LookupMap's hold pointers, so we can use a data dependency instead of an explicit barrier here.
21+
// LookupMap's hold pointers to data which is immutable, so normally we could use a data
22+
// dependency instead of an explicit barrier here. However, the access pattern between
23+
// m_TypeDefToMethodTableMap and m_MethodDefToDescMap/m_FieldDefToDescMap is such that a
24+
// data dependency is not sufficient to ensure that the MethodTable is visible when we
25+
// access the MethodDesc/FieldDesc. Since those loads are independent, we use
26+
// VolatileLoad here to ensure proper ordering.
27+
TYPE value = dac_cast<TYPE>(VolatileLoad(pValue));
2228
#else
2329
TYPE value = dac_cast<TYPE>(*pValue);
2430
#endif
@@ -51,7 +57,13 @@ SIZE_T LookupMap<SIZE_T>::GetValueAt(PTR_TADDR pValue, TADDR* pFlags, TADDR supp
5157
{
5258
WRAPPER_NO_CONTRACT;
5359

54-
TADDR value = VolatileLoadWithoutBarrier(pValue); // LookupMap's hold pointers, so we can use a data dependency instead of an explicit barrier here.
60+
// LookupMap's hold pointers to data which is immutable, so normally we could use a data
61+
// dependency instead of an explicit barrier here. However, the access pattern between
62+
// m_TypeDefToMethodTableMap and m_MethodDefToDescMap/m_FieldDefToDescMap is such that a
63+
// data dependency is not sufficient to ensure that the MethodTable is visible when we
64+
// access the MethodDesc/FieldDesc. Since those loads are independent, we use
65+
// VolatileLoad here to ensure proper ordering.
66+
TADDR value = VolatileLoad(pValue);
5567

5668
if (pFlags)
5769
*pFlags = value & supportedFlags;

0 commit comments

Comments
 (0)