Skip to content

Commit ccc3d9f

Browse files
authored
Remove the sealed blittable layoutclass correctness fix because of backcompat. (#54235)
1 parent 42a764d commit ccc3d9f

5 files changed

Lines changed: 37 additions & 18 deletions

File tree

src/coreclr/vm/classlayoutinfo.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -653,12 +653,8 @@ VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
653653
DEBUGARG(szName)
654654
);
655655

656-
// Type is blittable only if parent is also blittable and is not empty.
657-
if (isBlittable && fHasNonTrivialParent)
658-
{
659-
isBlittable = pParentMT->IsBlittable() // Check parent
660-
&& (!pParentLayoutInfo || !pParentLayoutInfo->IsZeroSized()); // Ensure non-zero size
661-
}
656+
// Type is blittable only if parent is also blittable
657+
isBlittable = isBlittable && (fHasNonTrivialParent ? pParentMT->IsBlittable() : TRUE);
662658
pEEClassLayoutInfoOut->SetIsBlittable(isBlittable);
663659

664660
S_UINT32 cbSortArraySize = S_UINT32(cTotalFields) * S_UINT32(sizeof(LayoutRawFieldInfo*));

src/coreclr/vm/ilmarshalers.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2496,10 +2496,14 @@ void ILBlittablePtrMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslIL
24962496

24972497
bool ILBlittablePtrMarshaler::CanMarshalViaPinning()
24982498
{
2499+
// [COMPAT] For correctness, we can't marshal via pinning if we might need to marshal differently at runtime.
2500+
// See calls to EmitExactTypeCheck where we check the runtime type of the object being marshalled.
2501+
// However, we previously supported pinning non-sealed blittable classes, even though that could result
2502+
// in some data still being unmarshalled if a subclass is provided. This optimization is incorrect,
2503+
// but libraries like NAudio have taken a hard dependency on this incorrect behavior, so we need to preserve it.
24992504
return IsCLRToNative(m_dwMarshalFlags) &&
25002505
!IsByref(m_dwMarshalFlags) &&
2501-
!IsFieldMarshal(m_dwMarshalFlags) &&
2502-
m_pargs->m_pMT->IsSealed(); // We can't marshal via pinning if we might need to marshal differently at runtime. See calls to EmitExactTypeCheck where we check the runtime type of the object being marshalled.
2506+
!IsFieldMarshal(m_dwMarshalFlags);
25032507
}
25042508

25052509
void ILBlittablePtrMarshaler::EmitMarshalViaPinning(ILCodeStream* pslILEmit)

src/coreclr/vm/mlinfo.cpp

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,8 +1138,6 @@ MarshalInfo::MarshalInfo(Module* pModule,
11381138
CorElementType corElemType = ELEMENT_TYPE_END;
11391139
m_pMT = NULL;
11401140
m_pMD = pMD;
1141-
// [Compat] For backward compatibility reasons, some marshalers imply [In, Out] behavior when marked as [In], [Out], or not marked with either.
1142-
BOOL byValAlwaysInOut = FALSE;
11431141

11441142
#ifdef FEATURE_COMINTEROP
11451143
m_fDispItf = FALSE;
@@ -1884,7 +1882,6 @@ MarshalInfo::MarshalInfo(Module* pModule,
18841882
}
18851883
m_type = IsFieldScenario() ? MARSHAL_TYPE_BLITTABLE_LAYOUTCLASS : MARSHAL_TYPE_BLITTABLEPTR;
18861884
m_args.m_pMT = m_pMT;
1887-
byValAlwaysInOut = TRUE;
18881885
}
18891886
else if (m_pMT->HasLayout())
18901887
{
@@ -2377,13 +2374,7 @@ MarshalInfo::MarshalInfo(Module* pModule,
23772374
}
23782375
}
23792376

2380-
if (!m_byref && byValAlwaysInOut)
2381-
{
2382-
// Some marshalers expect [In, Out] behavior with [In], [Out], or no directional attributes.
2383-
m_in = TRUE;
2384-
m_out = TRUE;
2385-
}
2386-
else if (!m_in && !m_out)
2377+
if (!m_in && !m_out)
23872378
{
23882379
// If neither IN nor OUT are true, this signals the URT to use the default
23892380
// rules.

src/tests/Interop/LayoutClass/LayoutClassNative.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ DLL_EXPORT BOOL STDMETHODCALLTYPE SimpleNestedLayoutClassByValue(NestedLayoutCla
108108
return SimpleSeqLayoutClassByRef(&v.str);
109109
}
110110

111+
extern "C"
112+
DLL_EXPORT BOOL STDMETHODCALLTYPE PointersEqual(void* ptr, void* ptr2)
113+
{
114+
return ptr == ptr2 ? TRUE : FALSE;
115+
}
116+
111117
extern "C"
112118
DLL_EXPORT void __cdecl Invalid(...)
113119
{

src/tests/Interop/LayoutClass/LayoutClassTest.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,12 @@ class StructureTests
174174
[DllImport("LayoutClassNative", EntryPoint = SimpleBlittableSeqLayoutClass_UpdateField)]
175175
private static extern bool SealedBlittableSeqLayoutClassByOutAttr([Out] SealedBlittable p);
176176

177+
[DllImport("LayoutClassNative")]
178+
private static extern bool PointersEqual(SealedBlittable obj, ref int field);
179+
180+
[DllImport("LayoutClassNative")]
181+
private static extern bool PointersEqual(Blittable obj, ref int field);
182+
177183
[DllImport("LayoutClassNative")]
178184
private static extern bool SimpleNestedLayoutClassByValue(NestedLayout p);
179185

@@ -280,6 +286,20 @@ public static void SealedBlittableClassByOutAttr()
280286
ValidateSealedBlittableClassInOut(SealedBlittableSeqLayoutClassByOutAttr);
281287
}
282288

289+
public static void SealedBlittablePinned()
290+
{
291+
Console.WriteLine($"Running {nameof(SealedBlittablePinned)}...");
292+
var blittable = new SealedBlittable(1);
293+
Assert.IsTrue(PointersEqual(blittable, ref blittable.a));
294+
}
295+
296+
public static void BlittablePinned()
297+
{
298+
Console.WriteLine($"Running {nameof(BlittablePinned)}...");
299+
var blittable = new Blittable(1);
300+
Assert.IsTrue(PointersEqual(blittable, ref blittable.a));
301+
}
302+
283303
public static void NestedLayoutClass()
284304
{
285305
Console.WriteLine($"Running {nameof(NestedLayoutClass)}...");
@@ -317,6 +337,8 @@ public static int Main(string[] argv)
317337
SealedBlittableClassByOutAttr();
318338
NestedLayoutClass();
319339
RecursiveNativeLayout();
340+
SealedBlittablePinned();
341+
BlittablePinned();
320342
}
321343
catch (Exception e)
322344
{

0 commit comments

Comments
 (0)