diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index 3d5f7da15005ef..e5545635ba3172 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -972,9 +972,18 @@ public override unsafe IntPtr ConvertToNative(object managed, int dwFlags) int allocSize = Marshal.SizeOfHelper((RuntimeType)_layoutType, false); IntPtr pNative = Marshal.AllocCoTaskMem(allocSize); - if (IsIn(dwFlags)) + try { - StubHelpers.LayoutTypeConvertToUnmanaged(managed, (byte*)pNative, ref _cleanupWorkList); + if (IsIn(dwFlags)) + { + StubHelpers.LayoutTypeConvertToUnmanaged(managed, (byte*)pNative, ref _cleanupWorkList); + } + } + catch + { + StubHelpers.DestroyCleanupList(ref _cleanupWorkList); + Marshal.FreeCoTaskMem(pNative); + throw; } return pNative; diff --git a/src/tests/Interop/PInvoke/AsAny/AsAnyTest.cs b/src/tests/Interop/PInvoke/AsAny/AsAnyTest.cs index f53a66919e1cf1..d8f68093574de8 100644 --- a/src/tests/Interop/PInvoke/AsAny/AsAnyTest.cs +++ b/src/tests/Interop/PInvoke/AsAny/AsAnyTest.cs @@ -318,6 +318,7 @@ public static int TestEntryPoint() TestIntPtrArray(); TestUIntPtrArray(); TestLayout(); + TestLayoutConvertToNativeExceptionPath(); RunAsAnyFieldTests(); TestUnicodeString(); TestUnicodeStringArray(); @@ -654,6 +655,16 @@ public static void TestLayout() { Console.WriteLine("------------------------"); } + private static void TestLayoutConvertToNativeExceptionPath() + { + // AsAnyField contains a field with [MarshalAs(UnmanagedType.AsAny)], which is not + // supported in layout marshaling. When passed via AsAny, LayoutImplementation.ConvertToNative + // allocates a native buffer and then calls LayoutTypeConvertToUnmanaged, which throws + // TypeLoadException. Verify the exception propagates correctly; the fix ensures the + // native buffer is freed on this exception path rather than leaked. + Assert.Throws(() => PassLayout(new AsAnyField())); + } + static void CharArrayInit(char[] unMappableCharArray_In, char[] unMappableCharArray_InOut, char[] unMappableCharArray_Out, char[] mappableCharArray_In, char[] mappableCharArray_InOut, char[] mappableCharArray_Out, string unMappableStr, string mappableStr)