m_nativeHome.InitHome(ILStubMarshalHome::HomeType_ILByrefLocal, pcsSetup->NewLocal(nativeFieldTypeByRef), &nativeType, /* unalignedIndirectStore */ true);
+ // During the cleanup pass, the managed typed is explicitly passed as null - see DestroyStructure(). This works
+ // except if the type has nested non-blittable fields. Not checking for null will compute invalid offsets that
+ // can cause an access violation during the field clean-up.
+ ILCodeLabel *pSkipComputeOffsetLabel = pcsSetup->NewCodeLabel();
+
pcsSetup->EmitNOP("// field setup {");
pcsSetup->EmitNOP("// managed field setup {");
pcsSetup->EmitLDARG(StructMarshalStubs::MANAGED_STRUCT_ARGIDX);
+ pcsSetup->EmitDUP();
+ pcsSetup->EmitBRFALSE(pSkipComputeOffsetLabel);
pcsSetup->EmitLDC(managedOffset);
pcsSetup->EmitADD();
+ pcsSetup->EmitLabel(pSkipComputeOffsetLabel);
EmitStoreManagedHomeAddr(pcsSetup);
pcsSetup->EmitNOP("// } managed field setup");
pcsSetup->EmitNOP("// native field setup {");
Assert.Equal(*opaqueData, *marshaledOpaqueData);
}
+ [Fact]
+ public void StructureToPtr_Flat_And_Nested_NonBlittableStructure_Success()
+ {
+ MarshalAndDestroy(new NonBlittableStruct_Flat
+ {
+ del = null,
+ b = 0x55,
+ });
+
+ MarshalAndDestroy(new NonBlittableStruct_Nested
+ {
+ s = { del = null },
+ b = 0x55,
+ });
+
+ static unsafe void MarshalAndDestroy<T>(T value) where T : struct
+ {
+ int sizeof_T = Marshal.SizeOf<T>();
+ void* ptr = stackalloc byte[sizeof_T];
+ Marshal.StructureToPtr(value, (IntPtr)ptr, false);
+ Marshal.DestroyStructure<T>((IntPtr)ptr);
+ }
+ }
+
public struct StructWithIntField
{
public int value;
public OpaqueStruct opaque;
public string str;
}
+
+ public struct NonBlittableStruct_Flat
+ {
+ public Delegate del;
+ public byte b;
+ }
+
+ public struct NonBlittableStruct_Nested
+ {
+ public struct InnerStruct
+ {
+ public Delegate del;
+ }
+
+ public InnerStruct s;
+ public byte b;
+ }
}
}