Skip to content

Commit eaea271

Browse files
Fix UnsafeAccessor scenario for modopts/modreqs when comparing field sigs. (#111648) (#111675)
* Consume custom modifiers and ByRef in RetType signature prior to comparing field signature.
1 parent 0b71788 commit eaea271

File tree

4 files changed

+71
-14
lines changed

4 files changed

+71
-14
lines changed

Diff for: src/coreclr/vm/prestub.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -1445,11 +1445,18 @@ namespace
14451445

14461446
DWORD declArgCount;
14471447
IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &declArgCount));
1448+
if (pSig1 >= pEndSig1)
1449+
ThrowHR(META_E_BAD_SIGNATURE);
14481450

1449-
// UnsafeAccessors for fields require return types be byref.
1450-
// This was explicitly checked in TryGenerateUnsafeAccessor().
1451+
// UnsafeAccessors for fields require return types be byref. However, we first need to
1452+
// consume any custom modifiers which are prior to the expected ELEMENT_TYPE_BYREF in
1453+
// the RetType signature (II.23.2.11).
1454+
_ASSERTE(state.IgnoreCustomModifiers); // We should always ignore custom modifiers for field look-up.
1455+
MetaSig::ConsumeCustomModifiers(pSig1, pEndSig1);
14511456
if (pSig1 >= pEndSig1)
14521457
ThrowHR(META_E_BAD_SIGNATURE);
1458+
1459+
// The ELEMENT_TYPE_BYREF was explicitly checked in TryGenerateUnsafeAccessor().
14531460
CorElementType byRefType = CorSigUncompressElementType(pSig1);
14541461
_ASSERTE(byRefType == ELEMENT_TYPE_BYREF);
14551462

Diff for: src/coreclr/vm/siginfo.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -3604,7 +3604,7 @@ BOOL CompareTypeTokens(mdToken tk1, mdToken tk2, ModuleBase *pModule1, ModuleBas
36043604
#endif //!DACCESS_COMPILE
36053605
} // CompareTypeTokens
36063606

3607-
static void ConsumeCustomModifiers(PCCOR_SIGNATURE& pSig, PCCOR_SIGNATURE pEndSig)
3607+
void MetaSig::ConsumeCustomModifiers(PCCOR_SIGNATURE& pSig, PCCOR_SIGNATURE pEndSig)
36083608
{
36093609
mdToken tk;
36103610
CorElementType type;

Diff for: src/coreclr/vm/siginfo.hpp

+8
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,14 @@ class MetaSig
945945
//------------------------------------------------------------------
946946
CorElementType GetByRefType(TypeHandle* pTy) const;
947947

948+
//------------------------------------------------------------------
949+
// Consume the custom modifiers, if any, in the current signature
950+
// and update it.
951+
// This is a non destructive operation if the current signature is not
952+
// pointing at a sequence of ELEMENT_TYPE_CMOD_REQD or ELEMENT_TYPE_CMOD_OPT.
953+
//------------------------------------------------------------------
954+
static void ConsumeCustomModifiers(PCCOR_SIGNATURE& pSig, PCCOR_SIGNATURE pEndSig);
955+
948956
// Struct used to capture in/out state during the comparison
949957
// of element types.
950958
struct CompareState

Diff for: src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.cs

+53-11
Original file line numberDiff line numberDiff line change
@@ -328,28 +328,70 @@ public static void Verify_AccessAllFields_CorElementType()
328328
extern static ref delegate*<void> GetFPtr(ref AllFields f);
329329
}
330330

331-
// Contains fields that have modopts/modreqs
332-
struct FieldsWithModifiers
331+
// Contains fields that are volatile
332+
struct VolatileFields
333333
{
334334
private static volatile int s_vInt;
335335
private volatile int _vInt;
336336
}
337337

338+
// Accessors for fields that are volatile
339+
static class AccessorsVolatile
340+
{
341+
[UnsafeAccessor(UnsafeAccessorKind.StaticField, Name="s_vInt")]
342+
public extern static ref int GetStaticVolatileInt(ref VolatileFields f);
343+
344+
[UnsafeAccessor(UnsafeAccessorKind.Field, Name="_vInt")]
345+
public extern static ref int GetVolatileInt(ref VolatileFields f);
346+
}
347+
338348
[Fact]
339-
public static void Verify_AccessFieldsWithModifiers()
349+
public static void Verify_AccessFieldsWithVolatile()
340350
{
341-
Console.WriteLine($"Running {nameof(Verify_AccessFieldsWithModifiers)}");
351+
Console.WriteLine($"Running {nameof(Verify_AccessFieldsWithVolatile)}");
342352

343-
FieldsWithModifiers fieldsWithModifiers = default;
353+
VolatileFields fieldsWithVolatile = default;
344354

345-
GetStaticVolatileInt(ref fieldsWithModifiers) = default;
346-
GetVolatileInt(ref fieldsWithModifiers) = default;
355+
AccessorsVolatile.GetStaticVolatileInt(ref fieldsWithVolatile) = default;
356+
AccessorsVolatile.GetVolatileInt(ref fieldsWithVolatile) = default;
357+
}
347358

348-
[UnsafeAccessor(UnsafeAccessorKind.StaticField, Name="s_vInt")]
349-
extern static ref int GetStaticVolatileInt(ref FieldsWithModifiers f);
359+
// Contains fields that are readonly
360+
readonly struct ReadOnlyFields
361+
{
362+
public static readonly int s_rInt;
363+
public readonly int _rInt;
364+
}
350365

351-
[UnsafeAccessor(UnsafeAccessorKind.Field, Name="_vInt")]
352-
extern static ref int GetVolatileInt(ref FieldsWithModifiers f);
366+
// Accessors for fields that are readonly
367+
static class AccessorsReadOnly
368+
{
369+
[UnsafeAccessor(UnsafeAccessorKind.StaticField, Name="s_rInt")]
370+
public extern static ref readonly int GetStaticReadOnlyInt(ref readonly ReadOnlyFields f);
371+
372+
[UnsafeAccessor(UnsafeAccessorKind.Field, Name="_rInt")]
373+
public extern static ref readonly int GetReadOnlyInt(ref readonly ReadOnlyFields f);
374+
}
375+
376+
[Fact]
377+
public static void Verify_AccessFieldsWithReadOnlyRefs()
378+
{
379+
Console.WriteLine($"Running {nameof(Verify_AccessFieldsWithReadOnlyRefs)}");
380+
381+
ReadOnlyFields readOnlyFields = default;
382+
383+
Assert.True(Unsafe.AreSame(in AccessorsReadOnly.GetStaticReadOnlyInt(in readOnlyFields), in ReadOnlyFields.s_rInt));
384+
Assert.True(Unsafe.AreSame(in AccessorsReadOnly.GetReadOnlyInt(in readOnlyFields), in readOnlyFields._rInt));
385+
386+
// Test the local declaration of the signature since it places modopts/modreqs differently.
387+
Assert.True(Unsafe.AreSame(in GetStaticReadOnlyIntLocal(in readOnlyFields), in ReadOnlyFields.s_rInt));
388+
Assert.True(Unsafe.AreSame(in GetReadOnlyIntLocal(in readOnlyFields), in readOnlyFields._rInt));
389+
390+
[UnsafeAccessor(UnsafeAccessorKind.StaticField, Name="s_rInt")]
391+
extern static ref readonly int GetStaticReadOnlyIntLocal(ref readonly ReadOnlyFields f);
392+
393+
[UnsafeAccessor(UnsafeAccessorKind.Field, Name="_rInt")]
394+
extern static ref readonly int GetReadOnlyIntLocal(ref readonly ReadOnlyFields f);
353395
}
354396

355397
[Fact]

0 commit comments

Comments
 (0)