Skip to content

Commit b5305cb

Browse files
The DestroyStructure API passes null to the IL marshaller for managed valuetypes. This is an issue with field marshallers of nested non-blittable types. (#62002)
Co-authored-by: Aaron Robinson <arobins@microsoft.com>
1 parent 8f06e33 commit b5305cb

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

src/coreclr/vm/ilmarshalers.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,11 +988,19 @@ class ILMarshaler
988988

989989
m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILByrefLocal, pcsSetup->NewLocal(nativeFieldTypeByRef), &nativeType, /* unalignedIndirectStore */ true);
990990

991+
// During the cleanup pass, the managed typed is explicitly passed as null - see DestroyStructure(). This works
992+
// except if the type has nested non-blittable fields. Not checking for null will compute invalid offsets that
993+
// can cause an access violation during the field clean-up.
994+
ILCodeLabel *pSkipComputeOffsetLabel = pcsSetup->NewCodeLabel();
995+
991996
pcsSetup->EmitNOP("// field setup {");
992997
pcsSetup->EmitNOP("// managed field setup {");
993998
pcsSetup->EmitLDARG(StructMarshalStubs::MANAGED_STRUCT_ARGIDX);
999+
pcsSetup->EmitDUP();
1000+
pcsSetup->EmitBRFALSE(pSkipComputeOffsetLabel);
9941001
pcsSetup->EmitLDC(managedOffset);
9951002
pcsSetup->EmitADD();
1003+
pcsSetup->EmitLabel(pSkipComputeOffsetLabel);
9961004
EmitStoreManagedHomeAddr(pcsSetup);
9971005
pcsSetup->EmitNOP("// } managed field setup");
9981006
pcsSetup->EmitNOP("// native field setup {");

src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/StructureToPtrTests.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,30 @@ public unsafe void StructureToPtr_OpaqueStruct_In_NonBlittableStructure_Success(
256256
Assert.Equal(*opaqueData, *marshaledOpaqueData);
257257
}
258258

259+
[Fact]
260+
public void StructureToPtr_Flat_And_Nested_NonBlittableStructure_Success()
261+
{
262+
MarshalAndDestroy(new NonBlittableStruct_Flat
263+
{
264+
del = null,
265+
b = 0x55,
266+
});
267+
268+
MarshalAndDestroy(new NonBlittableStruct_Nested
269+
{
270+
s = { del = null },
271+
b = 0x55,
272+
});
273+
274+
static unsafe void MarshalAndDestroy<T>(T value) where T : struct
275+
{
276+
int sizeof_T = Marshal.SizeOf<T>();
277+
void* ptr = stackalloc byte[sizeof_T];
278+
Marshal.StructureToPtr(value, (IntPtr)ptr, false);
279+
Marshal.DestroyStructure<T>((IntPtr)ptr);
280+
}
281+
}
282+
259283
public struct StructWithIntField
260284
{
261285
public int value;
@@ -318,5 +342,22 @@ public struct NonBlittableWithOpaque
318342
public OpaqueStruct opaque;
319343
public string str;
320344
}
345+
346+
public struct NonBlittableStruct_Flat
347+
{
348+
public Delegate del;
349+
public byte b;
350+
}
351+
352+
public struct NonBlittableStruct_Nested
353+
{
354+
public struct InnerStruct
355+
{
356+
public Delegate del;
357+
}
358+
359+
public InnerStruct s;
360+
public byte b;
361+
}
321362
}
322363
}

0 commit comments

Comments
 (0)