From 59d8690d3b94736ce358a9f1bfa429403e622780 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 19:05:24 +0000 Subject: [PATCH 01/25] Improve InvalidCastException message for generic types from different ALCs When the outermost types of a same-name cast failure share the same module, the error message now reports the first differing generic type argument's assembly and ALC context instead of the (identical) outer type's info. Fixes #80526 Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> --- src/coreclr/vm/excep.cpp | 116 ++++++++++++++++++ .../InvalidCastGenericALC.cs | 74 +++++++++++ .../InvalidCastGenericALC.csproj | 19 +++ .../InvalidCastGenericALC/SharedType.cs | 9 ++ .../InvalidCastGenericALC/SharedType.csproj | 8 ++ 5 files changed, 226 insertions(+) create mode 100644 src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs create mode 100644 src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.csproj create mode 100644 src/tests/Loader/classloader/InvalidCastGenericALC/SharedType.cs create mode 100644 src/tests/Loader/classloader/InvalidCastGenericALC/SharedType.csproj diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index d53c2052479bf3..13cc46370b1904 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -10161,6 +10161,77 @@ VOID GetAssemblyDetailInfo(SString &sType, sAssemblyDetailInfo.Append(detailsUtf8.GetUnicode()); } +VOID GetGenericArgAssemblyDetailInfo(SString &sType, + SString &sGenericArgName, + SString &sAssemblyDisplayName, + PEAssembly *pPEAssembly, + SString &sAssemblyDetailInfo) +{ + WRAPPER_NO_CONTRACT; + + SString detailsUtf8; + + SString sAlcName; + pPEAssembly->GetAssemblyBinder()->GetNameForDiagnostics(sAlcName); + SString assemblyPath{ pPEAssembly->GetPath() }; + if (assemblyPath.IsEmpty()) + { + detailsUtf8.Printf("Type %s has a generic argument '%s' that originates from '%s' in the context '%s' in a byte array", + sType.GetUTF8(), + sGenericArgName.GetUTF8(), + sAssemblyDisplayName.GetUTF8(), + sAlcName.GetUTF8()); + } + else + { + detailsUtf8.Printf("Type %s has a generic argument '%s' that originates from '%s' in the context '%s' at location '%s'", + sType.GetUTF8(), + sGenericArgName.GetUTF8(), + sAssemblyDisplayName.GetUTF8(), + sAlcName.GetUTF8(), + assemblyPath.GetUTF8()); + } + + sAssemblyDetailInfo.Append(detailsUtf8.GetUnicode()); +} + +// When the outermost types of a same-name cast failure share the same module, +// the actual difference lies in their generic type arguments. This function +// recursively finds the first pair of differing generic type arguments. +static BOOL FindFirstDifferingGenericArgument(TypeHandle thFrom, TypeHandle thTo, + TypeHandle *pthArgFrom, TypeHandle *pthArgTo) +{ + WRAPPER_NO_CONTRACT; + + Instantiation instFrom = thFrom.GetInstantiation(); + Instantiation instTo = thTo.GetInstantiation(); + + if (instFrom.IsEmpty() || instTo.IsEmpty() || instFrom.GetNumArgs() != instTo.GetNumArgs()) + return FALSE; + + for (DWORD i = 0; i < instFrom.GetNumArgs(); i++) + { + if (instFrom[i] != instTo[i]) + { + // If both arguments are from the same module, drill deeper + // into their own generic arguments to find the root difference. + Module *pModFrom = instFrom[i].GetModule(); + Module *pModTo = instTo[i].GetModule(); + if (pModFrom != NULL && pModTo != NULL && pModFrom == pModTo) + { + if (FindFirstDifferingGenericArgument(instFrom[i], instTo[i], pthArgFrom, pthArgTo)) + return TRUE; + } + + *pthArgFrom = instFrom[i]; + *pthArgTo = instTo[i]; + return TRUE; + } + } + + return FALSE; +} + VOID CheckAndThrowSameTypeAndAssemblyInvalidCastException(TypeHandle thCastFrom, TypeHandle thCastTo) { @@ -10198,6 +10269,51 @@ VOID CheckAndThrowSameTypeAndAssemblyInvalidCastException(TypeHandle thCastFrom, thCastFrom.GetName(strCastFromName); thCastTo.GetName(strCastToName); + // If the outermost types come from the same module, the actual difference + // must be in their generic type arguments. Report the differing generic + // argument's assembly info instead, which is more helpful to the user. + TypeHandle thDifferingArgFrom, thDifferingArgTo; + if (pModuleTypeFrom == pModuleTypeTo && + FindFirstDifferingGenericArgument(thCastFrom, thCastTo, &thDifferingArgFrom, &thDifferingArgTo)) + { + Module *pModuleArgFrom = thDifferingArgFrom.GetModule(); + Module *pModuleArgTo = thDifferingArgTo.GetModule(); + + if ((pModuleArgFrom != NULL) && (pModuleArgTo != NULL)) + { + StackSString sGenericArgName; + thDifferingArgFrom.GetName(sGenericArgName); + + PEAssembly *pPEAssemblyArgFrom = pModuleArgFrom->GetAssembly()->GetPEAssembly(); + PEAssembly *pPEAssemblyArgTo = pModuleArgTo->GetAssembly()->GetPEAssembly(); + + StackSString sArgAssemblyFromDisplayName; + StackSString sArgAssemblyToDisplayName; + pPEAssemblyArgFrom->GetDisplayName(sArgAssemblyFromDisplayName); + pPEAssemblyArgTo->GetDisplayName(sArgAssemblyToDisplayName); + + SString typeA = SL(W("A")); + GetGenericArgAssemblyDetailInfo(typeA, + sGenericArgName, + sArgAssemblyFromDisplayName, + pPEAssemblyArgFrom, + sAssemblyDetailInfoFrom); + SString typeB = SL(W("B")); + GetGenericArgAssemblyDetailInfo(typeB, + sGenericArgName, + sArgAssemblyToDisplayName, + pPEAssemblyArgTo, + sAssemblyDetailInfoTo); + + COMPlusThrow(kInvalidCastException, + IDS_EE_CANNOTCASTSAME, + strCastFromName.GetUnicode(), + strCastToName.GetUnicode(), + sAssemblyDetailInfoFrom.GetUnicode(), + sAssemblyDetailInfoTo.GetUnicode()); + } + } + SString typeA = SL(W("A")); GetAssemblyDetailInfo(typeA, sAssemblyFromDisplayName, diff --git a/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs b/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs new file mode 100644 index 00000000000000..2df6bd8a280f09 --- /dev/null +++ b/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.Loader; +using Xunit; + +public class InvalidCastGenericALC +{ + public static void ForceCast(object obj) + { + T result = (T)obj; + GC.KeepAlive(result); + } + + [Fact] + public static void InvalidCastException_GenericTypeArg_ShowsDifferingAssemblyInfo() + { + string sharedTypePath = Path.Combine( + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + "SharedType.dll"); + + var alc1 = new AssemblyLoadContext("ALC1"); + var alc2 = new AssemblyLoadContext("ALC2"); + + Assembly asm1 = alc1.LoadFromAssemblyPath(sharedTypePath); + Assembly asm2 = alc2.LoadFromAssemblyPath(sharedTypePath); + + Type type1 = asm1.GetType("SharedAssembly.SharedType"); + Type type2 = asm2.GetType("SharedAssembly.SharedType"); + + // StrongBox is from System.Private.CoreLib - same in all contexts. + // The generic argument types come from different ALCs. + Type boxType1 = typeof(StrongBox<>).MakeGenericType(type1); + Type boxType2 = typeof(StrongBox<>).MakeGenericType(type2); + + object instance = Activator.CreateInstance(boxType1); + + // Trigger InvalidCastException by trying to cast boxType1 instance to boxType2 + MethodInfo forceCast = typeof(InvalidCastGenericALC) + .GetMethod(nameof(ForceCast)) + .MakeGenericMethod(boxType2); + + try + { + forceCast.Invoke(null, new object[] { instance }); + Assert.Fail("Expected InvalidCastException was not thrown"); + } + catch (TargetInvocationException ex) when (ex.InnerException is InvalidCastException ice) + { + Console.WriteLine("InvalidCastException message:"); + Console.WriteLine(ice.Message); + + if (ice.Message.Contains("Debugging resource strings are unavailable")) + { + Console.WriteLine("Skipping message validation - resource strings unavailable"); + return; + } + + // The message should mention the generic argument and its differing ALCs. + // Before the fix, it would only report the outer type's assembly + // (System.Private.CoreLib from the Default context for both), + // making the message unhelpful. + // After the fix, it reports the generic argument's assembly and ALC context. + Assert.Contains("generic argument", ice.Message); + Assert.Contains("SharedAssembly.SharedType", ice.Message); + Assert.Contains("ALC1", ice.Message); + Assert.Contains("ALC2", ice.Message); + } + } +} diff --git a/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.csproj b/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.csproj new file mode 100644 index 00000000000000..356ed57594087b --- /dev/null +++ b/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.csproj @@ -0,0 +1,19 @@ + + + + true + + + + + + + + + + $(OutputPath)/../SharedType + + + + + diff --git a/src/tests/Loader/classloader/InvalidCastGenericALC/SharedType.cs b/src/tests/Loader/classloader/InvalidCastGenericALC/SharedType.cs new file mode 100644 index 00000000000000..9071a38c9ee543 --- /dev/null +++ b/src/tests/Loader/classloader/InvalidCastGenericALC/SharedType.cs @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace SharedAssembly +{ + public class SharedType + { + } +} diff --git a/src/tests/Loader/classloader/InvalidCastGenericALC/SharedType.csproj b/src/tests/Loader/classloader/InvalidCastGenericALC/SharedType.csproj new file mode 100644 index 00000000000000..41bbc46bc2b0a1 --- /dev/null +++ b/src/tests/Loader/classloader/InvalidCastGenericALC/SharedType.csproj @@ -0,0 +1,8 @@ + + + Library + + + + + From 4d8d120639dc5a748da6bfb9c9f57622d2302b53 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 19:11:32 +0000 Subject: [PATCH 02/25] Fix test: set RequiresProcessIsolation and use int-returning TestEntryPoint Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> --- .../InvalidCastGenericALC.cs | 37 +++++++++++++++---- .../InvalidCastGenericALC.csproj | 1 + 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs b/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs index 2df6bd8a280f09..7c30f25551c9a4 100644 --- a/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs +++ b/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs @@ -17,7 +17,7 @@ public static void ForceCast(object obj) } [Fact] - public static void InvalidCastException_GenericTypeArg_ShowsDifferingAssemblyInfo() + public static int TestEntryPoint() { string sharedTypePath = Path.Combine( Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @@ -47,7 +47,8 @@ public static void InvalidCastException_GenericTypeArg_ShowsDifferingAssemblyInf try { forceCast.Invoke(null, new object[] { instance }); - Assert.Fail("Expected InvalidCastException was not thrown"); + Console.WriteLine("FAIL: Expected InvalidCastException was not thrown"); + return 101; } catch (TargetInvocationException ex) when (ex.InnerException is InvalidCastException ice) { @@ -56,8 +57,8 @@ public static void InvalidCastException_GenericTypeArg_ShowsDifferingAssemblyInf if (ice.Message.Contains("Debugging resource strings are unavailable")) { - Console.WriteLine("Skipping message validation - resource strings unavailable"); - return; + Console.WriteLine("PASS (skipping message validation - resource strings unavailable)"); + return 100; } // The message should mention the generic argument and its differing ALCs. @@ -65,10 +66,30 @@ public static void InvalidCastException_GenericTypeArg_ShowsDifferingAssemblyInf // (System.Private.CoreLib from the Default context for both), // making the message unhelpful. // After the fix, it reports the generic argument's assembly and ALC context. - Assert.Contains("generic argument", ice.Message); - Assert.Contains("SharedAssembly.SharedType", ice.Message); - Assert.Contains("ALC1", ice.Message); - Assert.Contains("ALC2", ice.Message); + bool hasGenericArgMention = ice.Message.Contains("generic argument"); + bool hasTypeName = ice.Message.Contains("SharedAssembly.SharedType"); + bool hasAlc1 = ice.Message.Contains("ALC1"); + bool hasAlc2 = ice.Message.Contains("ALC2"); + + if (hasGenericArgMention && hasTypeName && hasAlc1 && hasAlc2) + { + Console.WriteLine("PASS"); + return 100; + } + else + { + Console.WriteLine("FAIL: InvalidCastException message does not mention the differing generic argument's ALC info"); + if (!hasGenericArgMention) Console.WriteLine(" Missing: 'generic argument'"); + if (!hasTypeName) Console.WriteLine(" Missing: 'SharedAssembly.SharedType'"); + if (!hasAlc1) Console.WriteLine(" Missing: 'ALC1'"); + if (!hasAlc2) Console.WriteLine(" Missing: 'ALC2'"); + return 102; + } + } + catch (Exception ex) + { + Console.WriteLine($"FAIL: Unexpected exception: {ex}"); + return 103; } } } diff --git a/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.csproj b/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.csproj index 356ed57594087b..1df5414b36928b 100644 --- a/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.csproj +++ b/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.csproj @@ -1,5 +1,6 @@ + true true From 3e3080710988611e031b4c7af71cade564a5b40e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 19:15:14 +0000 Subject: [PATCH 03/25] Add ActiveIssue exclusions for Mono and NativeAOT in test Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> --- .../classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs b/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs index 7c30f25551c9a4..9ab24cc6a22d74 100644 --- a/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs +++ b/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs @@ -6,6 +6,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Loader; +using TestLibrary; using Xunit; public class InvalidCastGenericALC @@ -16,6 +17,8 @@ public static void ForceCast(object obj) GC.KeepAlive(result); } + [ActiveIssue("https://github.com/dotnet/runtimelab/issues/194", typeof(Utilities), nameof(Utilities.IsNativeAot))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/80526", TestRuntimes.Mono)] [Fact] public static int TestEntryPoint() { From 9c4f35b650bdcee899223613f7dbb6175412ceab Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 19:16:12 +0000 Subject: [PATCH 04/25] Address code review: fix ActiveIssue reason for Mono exclusion Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> --- .../classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs b/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs index 9ab24cc6a22d74..114d25cbde9f55 100644 --- a/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs +++ b/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs @@ -18,7 +18,7 @@ public static void ForceCast(object obj) } [ActiveIssue("https://github.com/dotnet/runtimelab/issues/194", typeof(Utilities), nameof(Utilities.IsNativeAot))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/80526", TestRuntimes.Mono)] + [ActiveIssue("Error message format is CoreCLR-specific", TestRuntimes.Mono)] [Fact] public static int TestEntryPoint() { From 2e5a46dd1c90f7ec51378076e67640cc2a51616a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 22:38:38 +0000 Subject: [PATCH 05/25] Move InvalidCastGenericALC test to System.Runtime.Loader libraries tests Move the test from src/tests/Loader/classloader/ to src/libraries/System.Runtime.Loader/tests/ as requested. The test now uses standard xUnit Assert patterns and PlatformDetection attributes. Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> --- .../tests/AssemblyLoadContextTest.cs | 52 ++++++++++ .../InvalidCastGenericALC.csproj} | 2 +- .../InvalidCastGenericALC/SharedType.cs | 0 .../tests/System.Runtime.Loader.Tests.csproj | 1 + .../InvalidCastGenericALC.cs | 98 ------------------- .../InvalidCastGenericALC.csproj | 20 ---- 6 files changed, 54 insertions(+), 119 deletions(-) rename src/{tests/Loader/classloader/InvalidCastGenericALC/SharedType.csproj => libraries/System.Runtime.Loader/tests/InvalidCastGenericALC/InvalidCastGenericALC.csproj} (71%) rename src/{tests/Loader/classloader => libraries/System.Runtime.Loader/tests}/InvalidCastGenericALC/SharedType.cs (100%) delete mode 100644 src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs delete mode 100644 src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.csproj diff --git a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs index 3292f12de6d7b8..3b313d57cc8056 100644 --- a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs @@ -5,6 +5,7 @@ using System.IO; using System.Reflection; using System.Reflection.Emit; +using System.Runtime.CompilerServices; using Xunit; namespace System.Runtime.Loader.Tests @@ -275,5 +276,56 @@ public static void LoadNonRuntimeAssembly() Exception error = Assert.Throws(() => alc.LoadFromAssemblyName(new AssemblyName("MyAssembly"))); Assert.IsType(error.InnerException); } + + private static void ForceCast(object obj) + { + T result = (T)obj; + GC.KeepAlive(result); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ActiveIssue("Error message format is CoreCLR-specific", TestRuntimes.Mono)] + public static void InvalidCastException_GenericTypeArg_ShowsDifferingAssemblyInfo() + { + string sharedTypePath = Path.Combine( + Path.GetDirectoryName(typeof(AssemblyLoadContextTest).Assembly.Location), + "InvalidCastGenericALC.dll"); + + var alc1 = new AssemblyLoadContext("ALC1"); + var alc2 = new AssemblyLoadContext("ALC2"); + + Assembly asm1 = alc1.LoadFromAssemblyPath(sharedTypePath); + Assembly asm2 = alc2.LoadFromAssemblyPath(sharedTypePath); + + Type type1 = asm1.GetType("SharedAssembly.SharedType"); + Type type2 = asm2.GetType("SharedAssembly.SharedType"); + + // StrongBox is from System.Private.CoreLib - same in all contexts. + // The generic argument types come from different ALCs. + Type boxType1 = typeof(StrongBox<>).MakeGenericType(type1); + Type boxType2 = typeof(StrongBox<>).MakeGenericType(type2); + + object instance = Activator.CreateInstance(boxType1); + + MethodInfo forceCast = typeof(AssemblyLoadContextTest) + .GetMethod(nameof(ForceCast), BindingFlags.NonPublic | BindingFlags.Static) + .MakeGenericMethod(boxType2); + + var ex = Assert.Throws(() => forceCast.Invoke(null, new object[] { instance })); + var ice = Assert.IsType(ex.InnerException); + + // The message should mention the generic argument and its differing ALCs. + // Before the fix, it would only report the outer type's assembly + // (System.Private.CoreLib from the Default context for both), + // making the message unhelpful. + // After the fix, it reports the generic argument's assembly and ALC context. + if (!ice.Message.Contains("Debugging resource strings are unavailable")) + { + Assert.Contains("generic argument", ice.Message); + Assert.Contains("SharedAssembly.SharedType", ice.Message); + Assert.Contains("ALC1", ice.Message); + Assert.Contains("ALC2", ice.Message); + } + } } } diff --git a/src/tests/Loader/classloader/InvalidCastGenericALC/SharedType.csproj b/src/libraries/System.Runtime.Loader/tests/InvalidCastGenericALC/InvalidCastGenericALC.csproj similarity index 71% rename from src/tests/Loader/classloader/InvalidCastGenericALC/SharedType.csproj rename to src/libraries/System.Runtime.Loader/tests/InvalidCastGenericALC/InvalidCastGenericALC.csproj index 41bbc46bc2b0a1..fa6c5b3ae37c63 100644 --- a/src/tests/Loader/classloader/InvalidCastGenericALC/SharedType.csproj +++ b/src/libraries/System.Runtime.Loader/tests/InvalidCastGenericALC/InvalidCastGenericALC.csproj @@ -1,6 +1,6 @@ - Library + $(NetCoreAppCurrent) diff --git a/src/tests/Loader/classloader/InvalidCastGenericALC/SharedType.cs b/src/libraries/System.Runtime.Loader/tests/InvalidCastGenericALC/SharedType.cs similarity index 100% rename from src/tests/Loader/classloader/InvalidCastGenericALC/SharedType.cs rename to src/libraries/System.Runtime.Loader/tests/InvalidCastGenericALC/SharedType.cs diff --git a/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj b/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj index 6fa7eb235138d8..2e284bb1b33d66 100644 --- a/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj +++ b/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj @@ -56,6 +56,7 @@ + diff --git a/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs b/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs deleted file mode 100644 index 114d25cbde9f55..00000000000000 --- a/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.cs +++ /dev/null @@ -1,98 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.IO; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.Loader; -using TestLibrary; -using Xunit; - -public class InvalidCastGenericALC -{ - public static void ForceCast(object obj) - { - T result = (T)obj; - GC.KeepAlive(result); - } - - [ActiveIssue("https://github.com/dotnet/runtimelab/issues/194", typeof(Utilities), nameof(Utilities.IsNativeAot))] - [ActiveIssue("Error message format is CoreCLR-specific", TestRuntimes.Mono)] - [Fact] - public static int TestEntryPoint() - { - string sharedTypePath = Path.Combine( - Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), - "SharedType.dll"); - - var alc1 = new AssemblyLoadContext("ALC1"); - var alc2 = new AssemblyLoadContext("ALC2"); - - Assembly asm1 = alc1.LoadFromAssemblyPath(sharedTypePath); - Assembly asm2 = alc2.LoadFromAssemblyPath(sharedTypePath); - - Type type1 = asm1.GetType("SharedAssembly.SharedType"); - Type type2 = asm2.GetType("SharedAssembly.SharedType"); - - // StrongBox is from System.Private.CoreLib - same in all contexts. - // The generic argument types come from different ALCs. - Type boxType1 = typeof(StrongBox<>).MakeGenericType(type1); - Type boxType2 = typeof(StrongBox<>).MakeGenericType(type2); - - object instance = Activator.CreateInstance(boxType1); - - // Trigger InvalidCastException by trying to cast boxType1 instance to boxType2 - MethodInfo forceCast = typeof(InvalidCastGenericALC) - .GetMethod(nameof(ForceCast)) - .MakeGenericMethod(boxType2); - - try - { - forceCast.Invoke(null, new object[] { instance }); - Console.WriteLine("FAIL: Expected InvalidCastException was not thrown"); - return 101; - } - catch (TargetInvocationException ex) when (ex.InnerException is InvalidCastException ice) - { - Console.WriteLine("InvalidCastException message:"); - Console.WriteLine(ice.Message); - - if (ice.Message.Contains("Debugging resource strings are unavailable")) - { - Console.WriteLine("PASS (skipping message validation - resource strings unavailable)"); - return 100; - } - - // The message should mention the generic argument and its differing ALCs. - // Before the fix, it would only report the outer type's assembly - // (System.Private.CoreLib from the Default context for both), - // making the message unhelpful. - // After the fix, it reports the generic argument's assembly and ALC context. - bool hasGenericArgMention = ice.Message.Contains("generic argument"); - bool hasTypeName = ice.Message.Contains("SharedAssembly.SharedType"); - bool hasAlc1 = ice.Message.Contains("ALC1"); - bool hasAlc2 = ice.Message.Contains("ALC2"); - - if (hasGenericArgMention && hasTypeName && hasAlc1 && hasAlc2) - { - Console.WriteLine("PASS"); - return 100; - } - else - { - Console.WriteLine("FAIL: InvalidCastException message does not mention the differing generic argument's ALC info"); - if (!hasGenericArgMention) Console.WriteLine(" Missing: 'generic argument'"); - if (!hasTypeName) Console.WriteLine(" Missing: 'SharedAssembly.SharedType'"); - if (!hasAlc1) Console.WriteLine(" Missing: 'ALC1'"); - if (!hasAlc2) Console.WriteLine(" Missing: 'ALC2'"); - return 102; - } - } - catch (Exception ex) - { - Console.WriteLine($"FAIL: Unexpected exception: {ex}"); - return 103; - } - } -} diff --git a/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.csproj b/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.csproj deleted file mode 100644 index 1df5414b36928b..00000000000000 --- a/src/tests/Loader/classloader/InvalidCastGenericALC/InvalidCastGenericALC.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - true - - true - - - - - - - - - - $(OutputPath)/../SharedType - - - - - From e84224532a38b5939427e4473745fa2efa897cd6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 23:42:46 +0000 Subject: [PATCH 06/25] Simplify InvalidCastGenericALC test: inline type, remove reflection Remove the separate InvalidCastGenericALC assembly project. Instead, define InvalidCastSharedType directly in the test assembly and load the test assembly itself into a custom ALC. Replace the reflection- based ForceCast helper with a direct cast to StrongBox. Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> --- .../tests/AssemblyLoadContextTest.cs | 49 +++++++------------ .../InvalidCastGenericALC.csproj | 8 --- .../tests/InvalidCastGenericALC/SharedType.cs | 9 ---- .../tests/System.Runtime.Loader.Tests.csproj | 1 - 4 files changed, 19 insertions(+), 48 deletions(-) delete mode 100644 src/libraries/System.Runtime.Loader/tests/InvalidCastGenericALC/InvalidCastGenericALC.csproj delete mode 100644 src/libraries/System.Runtime.Loader/tests/InvalidCastGenericALC/SharedType.cs diff --git a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs index 3b313d57cc8056..c22020cdaa1414 100644 --- a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs @@ -277,42 +277,27 @@ public static void LoadNonRuntimeAssembly() Assert.IsType(error.InnerException); } - private static void ForceCast(object obj) - { - T result = (T)obj; - GC.KeepAlive(result); - } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] [ActiveIssue("Error message format is CoreCLR-specific", TestRuntimes.Mono)] public static void InvalidCastException_GenericTypeArg_ShowsDifferingAssemblyInfo() { - string sharedTypePath = Path.Combine( - Path.GetDirectoryName(typeof(AssemblyLoadContextTest).Assembly.Location), - "InvalidCastGenericALC.dll"); + var alc = new AssemblyLoadContext("TestALC"); + Assembly alcAssembly = alc.LoadFromAssemblyPath(typeof(AssemblyLoadContextTest).Assembly.Location); - var alc1 = new AssemblyLoadContext("ALC1"); - var alc2 = new AssemblyLoadContext("ALC2"); - - Assembly asm1 = alc1.LoadFromAssemblyPath(sharedTypePath); - Assembly asm2 = alc2.LoadFromAssemblyPath(sharedTypePath); - - Type type1 = asm1.GetType("SharedAssembly.SharedType"); - Type type2 = asm2.GetType("SharedAssembly.SharedType"); + // Get the same-named type from the custom ALC's copy of this assembly. + Type alcType = alcAssembly.GetType(typeof(InvalidCastSharedType).FullName); // StrongBox is from System.Private.CoreLib - same in all contexts. // The generic argument types come from different ALCs. - Type boxType1 = typeof(StrongBox<>).MakeGenericType(type1); - Type boxType2 = typeof(StrongBox<>).MakeGenericType(type2); - - object instance = Activator.CreateInstance(boxType1); + Type boxType = typeof(StrongBox<>).MakeGenericType(alcType); + object instance = Activator.CreateInstance(boxType); - MethodInfo forceCast = typeof(AssemblyLoadContextTest) - .GetMethod(nameof(ForceCast), BindingFlags.NonPublic | BindingFlags.Static) - .MakeGenericMethod(boxType2); - - var ex = Assert.Throws(() => forceCast.Invoke(null, new object[] { instance })); - var ice = Assert.IsType(ex.InnerException); + // Cast to StrongBox where InvalidCastSharedType is + // from this assembly's Default ALC - should throw InvalidCastException. + var ice = Assert.Throws(() => + { + StrongBox _ = (StrongBox)instance; + }); // The message should mention the generic argument and its differing ALCs. // Before the fix, it would only report the outer type's assembly @@ -322,10 +307,14 @@ public static void InvalidCastException_GenericTypeArg_ShowsDifferingAssemblyInf if (!ice.Message.Contains("Debugging resource strings are unavailable")) { Assert.Contains("generic argument", ice.Message); - Assert.Contains("SharedAssembly.SharedType", ice.Message); - Assert.Contains("ALC1", ice.Message); - Assert.Contains("ALC2", ice.Message); + Assert.Contains(nameof(InvalidCastSharedType), ice.Message); + Assert.Contains("Default", ice.Message); + Assert.Contains("TestALC", ice.Message); } } } + + public class InvalidCastSharedType + { + } } diff --git a/src/libraries/System.Runtime.Loader/tests/InvalidCastGenericALC/InvalidCastGenericALC.csproj b/src/libraries/System.Runtime.Loader/tests/InvalidCastGenericALC/InvalidCastGenericALC.csproj deleted file mode 100644 index fa6c5b3ae37c63..00000000000000 --- a/src/libraries/System.Runtime.Loader/tests/InvalidCastGenericALC/InvalidCastGenericALC.csproj +++ /dev/null @@ -1,8 +0,0 @@ - - - $(NetCoreAppCurrent) - - - - - diff --git a/src/libraries/System.Runtime.Loader/tests/InvalidCastGenericALC/SharedType.cs b/src/libraries/System.Runtime.Loader/tests/InvalidCastGenericALC/SharedType.cs deleted file mode 100644 index 9071a38c9ee543..00000000000000 --- a/src/libraries/System.Runtime.Loader/tests/InvalidCastGenericALC/SharedType.cs +++ /dev/null @@ -1,9 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace SharedAssembly -{ - public class SharedType - { - } -} diff --git a/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj b/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj index 2e284bb1b33d66..6fa7eb235138d8 100644 --- a/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj +++ b/src/libraries/System.Runtime.Loader/tests/System.Runtime.Loader.Tests.csproj @@ -56,7 +56,6 @@ - From 10c6d05c3cad45e68fde0639559911d2a2d2cdf9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 16:13:12 +0000 Subject: [PATCH 07/25] Add test for existing InvalidCastException behavior with types from different ALCs Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> --- .../tests/AssemblyLoadContextTest.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs index c22020cdaa1414..581b2cf55c28d7 100644 --- a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs @@ -277,6 +277,31 @@ public static void LoadNonRuntimeAssembly() Assert.IsType(error.InnerException); } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] + [ActiveIssue("Error message format is CoreCLR-specific", TestRuntimes.Mono)] + public static void InvalidCastException_DifferentALC_ShowsAssemblyInfo() + { + var alc = new AssemblyLoadContext("TestALC"); + Assembly alcAssembly = alc.LoadFromAssemblyPath(typeof(AssemblyLoadContextTest).Assembly.Location); + + Type alcType = alcAssembly.GetType(typeof(InvalidCastSharedType).FullName); + object instance = Activator.CreateInstance(alcType); + + // Cast directly to InvalidCastSharedType from the Default ALC. + var ice = Assert.Throws(() => + { + InvalidCastSharedType _ = (InvalidCastSharedType)instance; + }); + + // The message should report both ALC contexts for the same-named type. + if (!ice.Message.Contains("Debugging resource strings are unavailable")) + { + Assert.Contains(nameof(InvalidCastSharedType), ice.Message); + Assert.Contains("Default", ice.Message); + Assert.Contains("TestALC", ice.Message); + } + } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] [ActiveIssue("Error message format is CoreCLR-specific", TestRuntimes.Mono)] public static void InvalidCastException_GenericTypeArg_ShowsDifferingAssemblyInfo() From 1740b5f3c3538beefad5927450fb72316a391daf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 18:11:11 +0000 Subject: [PATCH 08/25] Rename GenericTypeArg test to include DifferentALC, trim comments Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/16c73d75-5a84-4ccb-ac10-38103665e5aa --- .../tests/AssemblyLoadContextTest.cs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs index 581b2cf55c28d7..40c2b65ab74949 100644 --- a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs @@ -304,31 +304,23 @@ public static void InvalidCastException_DifferentALC_ShowsAssemblyInfo() [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] [ActiveIssue("Error message format is CoreCLR-specific", TestRuntimes.Mono)] - public static void InvalidCastException_GenericTypeArg_ShowsDifferingAssemblyInfo() + public static void InvalidCastException_GenericTypeArg_DifferentALC_ShowsAssemblyInfo() { var alc = new AssemblyLoadContext("TestALC"); Assembly alcAssembly = alc.LoadFromAssemblyPath(typeof(AssemblyLoadContextTest).Assembly.Location); - // Get the same-named type from the custom ALC's copy of this assembly. + // The outer type (StrongBox) is from CoreLib (same in all contexts), + // but the generic argument comes from a different ALC. Type alcType = alcAssembly.GetType(typeof(InvalidCastSharedType).FullName); - - // StrongBox is from System.Private.CoreLib - same in all contexts. - // The generic argument types come from different ALCs. Type boxType = typeof(StrongBox<>).MakeGenericType(alcType); object instance = Activator.CreateInstance(boxType); - // Cast to StrongBox where InvalidCastSharedType is - // from this assembly's Default ALC - should throw InvalidCastException. var ice = Assert.Throws(() => { StrongBox _ = (StrongBox)instance; }); - // The message should mention the generic argument and its differing ALCs. - // Before the fix, it would only report the outer type's assembly - // (System.Private.CoreLib from the Default context for both), - // making the message unhelpful. - // After the fix, it reports the generic argument's assembly and ALC context. + // The message should identify the differing generic argument and its ALCs. if (!ice.Message.Contains("Debugging resource strings are unavailable")) { Assert.Contains("generic argument", ice.Message); From cca13cd0dc3e0a3812fc4d7763aea4a984312ddd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 18:37:42 +0000 Subject: [PATCH 09/25] Flip if-condition in FindFirstDifferingGenericArgument to reduce nesting Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e1d701c5-c2ec-491b-befa-d8dab35d1de1 --- src/coreclr/vm/excep.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index 13cc46370b1904..69028696f3d768 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -10211,22 +10211,22 @@ static BOOL FindFirstDifferingGenericArgument(TypeHandle thFrom, TypeHandle thTo for (DWORD i = 0; i < instFrom.GetNumArgs(); i++) { - if (instFrom[i] != instTo[i]) - { - // If both arguments are from the same module, drill deeper - // into their own generic arguments to find the root difference. - Module *pModFrom = instFrom[i].GetModule(); - Module *pModTo = instTo[i].GetModule(); - if (pModFrom != NULL && pModTo != NULL && pModFrom == pModTo) - { - if (FindFirstDifferingGenericArgument(instFrom[i], instTo[i], pthArgFrom, pthArgTo)) - return TRUE; - } + if (instFrom[i] == instTo[i]) + continue; - *pthArgFrom = instFrom[i]; - *pthArgTo = instTo[i]; - return TRUE; + // If both arguments are from the same module, drill deeper + // into their own generic arguments to find the root difference. + Module *pModFrom = instFrom[i].GetModule(); + Module *pModTo = instTo[i].GetModule(); + if (pModFrom != NULL && pModTo != NULL && pModFrom == pModTo) + { + if (FindFirstDifferingGenericArgument(instFrom[i], instTo[i], pthArgFrom, pthArgTo)) + return TRUE; } + + *pthArgFrom = instFrom[i]; + *pthArgTo = instTo[i]; + return TRUE; } return FALSE; From 9a23ea96d5f2b07099c22e89abc446b47ef5cd92 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 19:07:47 +0000 Subject: [PATCH 10/25] Remove comments from FindFirstDifferingGenericArgument Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/c1f52900-c4ea-4bb3-b3ed-ea94bf45ddd1 --- src/coreclr/vm/excep.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index 69028696f3d768..64144c766bcb79 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -10195,9 +10195,6 @@ VOID GetGenericArgAssemblyDetailInfo(SString &sType, sAssemblyDetailInfo.Append(detailsUtf8.GetUnicode()); } -// When the outermost types of a same-name cast failure share the same module, -// the actual difference lies in their generic type arguments. This function -// recursively finds the first pair of differing generic type arguments. static BOOL FindFirstDifferingGenericArgument(TypeHandle thFrom, TypeHandle thTo, TypeHandle *pthArgFrom, TypeHandle *pthArgTo) { @@ -10214,8 +10211,6 @@ static BOOL FindFirstDifferingGenericArgument(TypeHandle thFrom, TypeHandle thTo if (instFrom[i] == instTo[i]) continue; - // If both arguments are from the same module, drill deeper - // into their own generic arguments to find the root difference. Module *pModFrom = instFrom[i].GetModule(); Module *pModTo = instTo[i].GetModule(); if (pModFrom != NULL && pModTo != NULL && pModFrom == pModTo) From 032f2004e551d39d9e28f055660ebb4f9f312e67 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 19:27:33 +0000 Subject: [PATCH 11/25] Update generic type arg test to validate outer type name in exception message Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/4cbf1501-48cc-49c3-aec8-02e328ee2821 --- .../System.Runtime.Loader/tests/AssemblyLoadContextTest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs index 40c2b65ab74949..d67a8d595a6442 100644 --- a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs @@ -323,6 +323,7 @@ public static void InvalidCastException_GenericTypeArg_DifferentALC_ShowsAssembl // The message should identify the differing generic argument and its ALCs. if (!ice.Message.Contains("Debugging resource strings are unavailable")) { + Assert.Contains(nameof(StrongBox), ice.Message); Assert.Contains("generic argument", ice.Message); Assert.Contains(nameof(InvalidCastSharedType), ice.Message); Assert.Contains("Default", ice.Message); From 3cdda47aa60cc7a52786a0250a6d0f20c7dbf319 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 19:59:54 +0000 Subject: [PATCH 12/25] Replace ActiveIssue with ConditionalFact for CoreCLR-only test filtering Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/a98cdf0b-cd91-4412-bb00-09c8914373ca --- .../System.Runtime.Loader/tests/AssemblyLoadContextTest.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs index d67a8d595a6442..0e15dbaac9418c 100644 --- a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs @@ -277,8 +277,7 @@ public static void LoadNonRuntimeAssembly() Assert.IsType(error.InnerException); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] - [ActiveIssue("Error message format is CoreCLR-specific", TestRuntimes.Mono)] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.IsNotMonoRuntime))] public static void InvalidCastException_DifferentALC_ShowsAssemblyInfo() { var alc = new AssemblyLoadContext("TestALC"); @@ -302,8 +301,7 @@ public static void InvalidCastException_DifferentALC_ShowsAssemblyInfo() } } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported))] - [ActiveIssue("Error message format is CoreCLR-specific", TestRuntimes.Mono)] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.IsNotMonoRuntime))] public static void InvalidCastException_GenericTypeArg_DifferentALC_ShowsAssemblyInfo() { var alc = new AssemblyLoadContext("TestALC"); From 416b937bcf433a2c9617f898d5e09311f17ed26f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 20:12:43 +0000 Subject: [PATCH 13/25] Use PlatformDetection.IsCoreCLR instead of IsNotMonoRuntime Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/34896f01-de92-4f71-8d95-569e53202f97 --- .../System.Runtime.Loader/tests/AssemblyLoadContextTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs index 0e15dbaac9418c..51ce8df222ef11 100644 --- a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs @@ -277,7 +277,7 @@ public static void LoadNonRuntimeAssembly() Assert.IsType(error.InnerException); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.IsNotMonoRuntime))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.IsCoreCLR))] public static void InvalidCastException_DifferentALC_ShowsAssemblyInfo() { var alc = new AssemblyLoadContext("TestALC"); @@ -301,7 +301,7 @@ public static void InvalidCastException_DifferentALC_ShowsAssemblyInfo() } } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.IsNotMonoRuntime))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.IsCoreCLR))] public static void InvalidCastException_GenericTypeArg_DifferentALC_ShowsAssemblyInfo() { var alc = new AssemblyLoadContext("TestALC"); From a04b0e41a82618ce1f135a165f7c04f5cd618b17 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 20:41:36 +0000 Subject: [PATCH 14/25] Replace IsNotMonoRuntime + IsNotNativeAot with IsCoreCLR across test files Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/a2b2c386-336b-4819-8a0f-d9d1ff954208 --- .../tests/Lambda/LambdaTests.cs | 4 ++-- ...eratedComInterfaceComImportInteropTests.cs | 3 +-- .../System/Environment.GetCommandLineArgs.cs | 6 ++---- .../Runtime/ControlledExecutionTests.cs | 20 +++++++++---------- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/libraries/System.Linq.Expressions/tests/Lambda/LambdaTests.cs b/src/libraries/System.Linq.Expressions/tests/Lambda/LambdaTests.cs index 6a14476a1a6bf6..75ed5768ae75be 100644 --- a/src/libraries/System.Linq.Expressions/tests/Lambda/LambdaTests.cs +++ b/src/libraries/System.Linq.Expressions/tests/Lambda/LambdaTests.cs @@ -941,7 +941,7 @@ public void PrivateDelegate(bool useInterpreter) Assert.Equal(42, del.DynamicInvoke()); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] public void ValidateThatInterpreterWithSimpleTypeUsesNonDynamicThunk() { Expression action = () => Console.WriteLine(""); @@ -959,7 +959,7 @@ public void ValidateThatInterpreterWithSimpleTypeUsesNonDynamicThunk() Assert.True(func2.Compile(preferInterpretation:true).Method.GetType().Name == "RuntimeMethodInfo"); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] public void ValidateThatInterpreterWithSimpleTypeUsesDynamicThunk() { Expression> complexaction = (object o1, object o2, object o3) => Console.WriteLine(""); diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/GeneratedComInterfaceComImportInteropTests.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/GeneratedComInterfaceComImportInteropTests.cs index bcc8186f24f18b..1e964ee5e684bd 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/GeneratedComInterfaceComImportInteropTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/GeneratedComInterfaceComImportInteropTests.cs @@ -16,8 +16,7 @@ public unsafe partial class GeneratedComInterfaceComImportInteropTests public static bool IsSupported => RemoteExecutor.IsSupported && PlatformDetection.IsWindows - && PlatformDetection.IsNotMonoRuntime - && PlatformDetection.IsNotNativeAot; + && PlatformDetection.IsCoreCLR; [LibraryImport(NativeExportsNE.NativeExportsNE_Binary, EntryPoint = "new_get_and_set_int")] private static partial IGetAndSetInt NewNativeObject(); diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Environment.GetCommandLineArgs.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Environment.GetCommandLineArgs.cs index 2d19226a2787d8..9fab69a884b97d 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Environment.GetCommandLineArgs.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Environment.GetCommandLineArgs.cs @@ -74,8 +74,7 @@ public static int CheckCommandLineArgs(string[] args) [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] public void GetCommandLineArgs_Fallback_Returns() { - if (PlatformDetection.IsNotMonoRuntime - && PlatformDetection.IsNotNativeAot + if (PlatformDetection.IsCoreCLR && PlatformDetection.IsWindows) { // Currently fallback command line is only implemented on Windows coreclr @@ -106,8 +105,7 @@ public static int CheckCommandLineArgsFallback() public static bool IsWindowsCoreCLRJit => PlatformDetection.IsWindows - && PlatformDetection.IsNotMonoRuntime - && PlatformDetection.IsNotNativeAot; + && PlatformDetection.IsCoreCLR; [ConditionalTheory(typeof(GetCommandLineArgs), nameof(IsWindowsCoreCLRJit))] [InlineData(@"cmd ""abc"" d e", new[] { "cmd", "abc", "d", "e" })] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Runtime/ControlledExecutionTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Runtime/ControlledExecutionTests.cs index 7e71e6c1d06e6d..e4ee9d9d465237 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Runtime/ControlledExecutionTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Runtime/ControlledExecutionTests.cs @@ -19,7 +19,7 @@ public sealed class ControlledExecutionTests private volatile int _counter; // Tests that the Run method finishes normally if no cancellation is requested - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] public void RunWithoutCancelling() { var cts = new CancellationTokenSource(); @@ -35,7 +35,7 @@ void Test() } // Tests that a nested invocation of the Run method throws an InvalidOperationException - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] public void TestNestedRunInvocation() { bool nestedExecution = false; @@ -54,7 +54,7 @@ void Test() // Tests that an infinite loop may be aborted and that the ThreadAbortException is translated // to an OperationCanceledException. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] public void CancelOutsideOfTryCatchFinally() { var cts = new CancellationTokenSource(); @@ -74,7 +74,7 @@ void Test() // Tests that an infinite loop may be aborted, that the ThreadAbortException is automatically rethrown, // and that it is eventually translated to an OperationCanceledException. -// [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] +// [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] public void CancelInTryAndExitCatchNormally() { var cts = new CancellationTokenSource(); @@ -103,7 +103,7 @@ void Test() } // Tests that catch blocks are not aborted. The catch block swallows the ThreadAbortException and throws a different exception. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] public void CancelInTryAndThrowFromCatch() { var cts = new CancellationTokenSource(); @@ -131,7 +131,7 @@ void Test() } // Tests that finally blocks are not aborted. The finally block exits normally. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] public void CancelInFinallyThatSleeps() { var cts = new CancellationTokenSource(); @@ -160,7 +160,7 @@ void Test() } // Tests that finally blocks are not aborted. The finally block throws an exception. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] public void CancelInFinallyThatSleepsAndThrows() { var cts = new CancellationTokenSource(); @@ -188,7 +188,7 @@ void Test() } // Tests cancellation before calling the Run method. The action must never start. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] public void CancelBeforeRun() { var cts = new CancellationTokenSource(); @@ -205,7 +205,7 @@ void Test() } // Tests cancellation by the action itself -// [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] +// [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] public void CancelItselfOutsideOfTryCatchFinally() { var cts = new CancellationTokenSource(); @@ -224,7 +224,7 @@ void Test() } // Tests cancellation by the action itself. Finally blocks must be executed except the one that triggered cancellation. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] public void CancelItselfFromFinally() { bool finishedContainingFinally = false; From 787e86384852da46784469d67e371c07909f3cb8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 20:56:49 +0000 Subject: [PATCH 15/25] Revert test changes outside of AssemblyLoadContextTest.cs Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/c6d47d69-1faf-49ec-96b6-8365ca6a8214 --- .../tests/Lambda/LambdaTests.cs | 4 ++-- ...eratedComInterfaceComImportInteropTests.cs | 3 ++- .../System/Environment.GetCommandLineArgs.cs | 6 ++++-- .../Runtime/ControlledExecutionTests.cs | 20 +++++++++---------- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/libraries/System.Linq.Expressions/tests/Lambda/LambdaTests.cs b/src/libraries/System.Linq.Expressions/tests/Lambda/LambdaTests.cs index 75ed5768ae75be..6a14476a1a6bf6 100644 --- a/src/libraries/System.Linq.Expressions/tests/Lambda/LambdaTests.cs +++ b/src/libraries/System.Linq.Expressions/tests/Lambda/LambdaTests.cs @@ -941,7 +941,7 @@ public void PrivateDelegate(bool useInterpreter) Assert.Equal(42, del.DynamicInvoke()); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] public void ValidateThatInterpreterWithSimpleTypeUsesNonDynamicThunk() { Expression action = () => Console.WriteLine(""); @@ -959,7 +959,7 @@ public void ValidateThatInterpreterWithSimpleTypeUsesNonDynamicThunk() Assert.True(func2.Compile(preferInterpretation:true).Method.GetType().Name == "RuntimeMethodInfo"); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] public void ValidateThatInterpreterWithSimpleTypeUsesDynamicThunk() { Expression> complexaction = (object o1, object o2, object o3) => Console.WriteLine(""); diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/GeneratedComInterfaceComImportInteropTests.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/GeneratedComInterfaceComImportInteropTests.cs index 1e964ee5e684bd..bcc8186f24f18b 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/GeneratedComInterfaceComImportInteropTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/GeneratedComInterfaceComImportInteropTests.cs @@ -16,7 +16,8 @@ public unsafe partial class GeneratedComInterfaceComImportInteropTests public static bool IsSupported => RemoteExecutor.IsSupported && PlatformDetection.IsWindows - && PlatformDetection.IsCoreCLR; + && PlatformDetection.IsNotMonoRuntime + && PlatformDetection.IsNotNativeAot; [LibraryImport(NativeExportsNE.NativeExportsNE_Binary, EntryPoint = "new_get_and_set_int")] private static partial IGetAndSetInt NewNativeObject(); diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Environment.GetCommandLineArgs.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Environment.GetCommandLineArgs.cs index 9fab69a884b97d..2d19226a2787d8 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Environment.GetCommandLineArgs.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Environment.GetCommandLineArgs.cs @@ -74,7 +74,8 @@ public static int CheckCommandLineArgs(string[] args) [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] public void GetCommandLineArgs_Fallback_Returns() { - if (PlatformDetection.IsCoreCLR + if (PlatformDetection.IsNotMonoRuntime + && PlatformDetection.IsNotNativeAot && PlatformDetection.IsWindows) { // Currently fallback command line is only implemented on Windows coreclr @@ -105,7 +106,8 @@ public static int CheckCommandLineArgsFallback() public static bool IsWindowsCoreCLRJit => PlatformDetection.IsWindows - && PlatformDetection.IsCoreCLR; + && PlatformDetection.IsNotMonoRuntime + && PlatformDetection.IsNotNativeAot; [ConditionalTheory(typeof(GetCommandLineArgs), nameof(IsWindowsCoreCLRJit))] [InlineData(@"cmd ""abc"" d e", new[] { "cmd", "abc", "d", "e" })] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Runtime/ControlledExecutionTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Runtime/ControlledExecutionTests.cs index e4ee9d9d465237..7e71e6c1d06e6d 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Runtime/ControlledExecutionTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Runtime/ControlledExecutionTests.cs @@ -19,7 +19,7 @@ public sealed class ControlledExecutionTests private volatile int _counter; // Tests that the Run method finishes normally if no cancellation is requested - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] public void RunWithoutCancelling() { var cts = new CancellationTokenSource(); @@ -35,7 +35,7 @@ void Test() } // Tests that a nested invocation of the Run method throws an InvalidOperationException - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] public void TestNestedRunInvocation() { bool nestedExecution = false; @@ -54,7 +54,7 @@ void Test() // Tests that an infinite loop may be aborted and that the ThreadAbortException is translated // to an OperationCanceledException. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] public void CancelOutsideOfTryCatchFinally() { var cts = new CancellationTokenSource(); @@ -74,7 +74,7 @@ void Test() // Tests that an infinite loop may be aborted, that the ThreadAbortException is automatically rethrown, // and that it is eventually translated to an OperationCanceledException. -// [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] +// [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] public void CancelInTryAndExitCatchNormally() { var cts = new CancellationTokenSource(); @@ -103,7 +103,7 @@ void Test() } // Tests that catch blocks are not aborted. The catch block swallows the ThreadAbortException and throws a different exception. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] public void CancelInTryAndThrowFromCatch() { var cts = new CancellationTokenSource(); @@ -131,7 +131,7 @@ void Test() } // Tests that finally blocks are not aborted. The finally block exits normally. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] public void CancelInFinallyThatSleeps() { var cts = new CancellationTokenSource(); @@ -160,7 +160,7 @@ void Test() } // Tests that finally blocks are not aborted. The finally block throws an exception. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] public void CancelInFinallyThatSleepsAndThrows() { var cts = new CancellationTokenSource(); @@ -188,7 +188,7 @@ void Test() } // Tests cancellation before calling the Run method. The action must never start. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] public void CancelBeforeRun() { var cts = new CancellationTokenSource(); @@ -205,7 +205,7 @@ void Test() } // Tests cancellation by the action itself -// [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] +// [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] public void CancelItselfOutsideOfTryCatchFinally() { var cts = new CancellationTokenSource(); @@ -224,7 +224,7 @@ void Test() } // Tests cancellation by the action itself. Finally blocks must be executed except the one that triggered cancellation. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsCoreCLR))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime), nameof(PlatformDetection.IsNotNativeAot))] public void CancelItselfFromFinally() { bool finishedContainingFinally = false; From 13e4b5249ce5772f00a3706d7274117b1580f5e2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 23:07:57 +0000 Subject: [PATCH 16/25] Remove vestigial "Debugging resource strings are unavailable" checks from tests Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/06813479-8660-4f1e-b34b-6d989935069e --- .../tests/AssemblyLoadContextTest.cs | 21 ++++++------------- .../classloader/regressions/347422/b347422.cs | 2 +- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs index 51ce8df222ef11..e2e0631393e57d 100644 --- a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs @@ -293,12 +293,9 @@ public static void InvalidCastException_DifferentALC_ShowsAssemblyInfo() }); // The message should report both ALC contexts for the same-named type. - if (!ice.Message.Contains("Debugging resource strings are unavailable")) - { - Assert.Contains(nameof(InvalidCastSharedType), ice.Message); - Assert.Contains("Default", ice.Message); - Assert.Contains("TestALC", ice.Message); - } + Assert.Contains(nameof(InvalidCastSharedType), ice.Message); + Assert.Contains("Default", ice.Message); + Assert.Contains("TestALC", ice.Message); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsAssemblyLoadingSupported), nameof(PlatformDetection.IsCoreCLR))] @@ -318,15 +315,9 @@ public static void InvalidCastException_GenericTypeArg_DifferentALC_ShowsAssembl StrongBox _ = (StrongBox)instance; }); - // The message should identify the differing generic argument and its ALCs. - if (!ice.Message.Contains("Debugging resource strings are unavailable")) - { - Assert.Contains(nameof(StrongBox), ice.Message); - Assert.Contains("generic argument", ice.Message); - Assert.Contains(nameof(InvalidCastSharedType), ice.Message); - Assert.Contains("Default", ice.Message); - Assert.Contains("TestALC", ice.Message); - } + // The message should include the full generic type names with the differing argument. + Assert.Contains(nameof(StrongBox), ice.Message); + Assert.Contains(nameof(InvalidCastSharedType), ice.Message); } } diff --git a/src/tests/Loader/classloader/regressions/347422/b347422.cs b/src/tests/Loader/classloader/regressions/347422/b347422.cs index cbe049c8392473..a87036789d538c 100644 --- a/src/tests/Loader/classloader/regressions/347422/b347422.cs +++ b/src/tests/Loader/classloader/regressions/347422/b347422.cs @@ -35,7 +35,7 @@ public static int TestEntryPoint() string msg ="Unable to cast object of type 'System.Object' to type 'IFoo'."; - if (e.Message.Equals(msg) || e.Message.Contains("Debugging resource strings are unavailable")) + if (e.Message.Equals(msg)) { Console.WriteLine("PASS"); return 100; From 693a059c3e22d2a7abf0bb5788eb43e2ec35a30b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 21 Mar 2026 01:40:35 +0000 Subject: [PATCH 17/25] Add ALC context name assertions to generic type arg InvalidCastException test Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/7a0e3dae-656d-4402-b979-c1b041e026fe --- .../System.Runtime.Loader/tests/AssemblyLoadContextTest.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs index e2e0631393e57d..902085230a8075 100644 --- a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs @@ -315,9 +315,12 @@ public static void InvalidCastException_GenericTypeArg_DifferentALC_ShowsAssembl StrongBox _ = (StrongBox)instance; }); - // The message should include the full generic type names with the differing argument. + // The message should include the full generic type names with the differing argument + // and the ALC context names. Assert.Contains(nameof(StrongBox), ice.Message); Assert.Contains(nameof(InvalidCastSharedType), ice.Message); + Assert.Contains("Default", ice.Message); + Assert.Contains("TestALC", ice.Message); } } From 0179d51803d1e593c674f2ae63e8acdfc75905ce Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 21 Mar 2026 05:48:04 +0000 Subject: [PATCH 18/25] Revert b347422.cs change and update ALC test to assert generic argument phrase Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/af4ebb30-93b5-486b-a5d1-feaad1f92011 --- .../System.Runtime.Loader/tests/AssemblyLoadContextTest.cs | 2 +- src/tests/Loader/classloader/regressions/347422/b347422.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs index 902085230a8075..0d2c60e7a1b1c5 100644 --- a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs @@ -318,7 +318,7 @@ public static void InvalidCastException_GenericTypeArg_DifferentALC_ShowsAssembl // The message should include the full generic type names with the differing argument // and the ALC context names. Assert.Contains(nameof(StrongBox), ice.Message); - Assert.Contains(nameof(InvalidCastSharedType), ice.Message); + Assert.Contains("generic argument '", ice.Message); Assert.Contains("Default", ice.Message); Assert.Contains("TestALC", ice.Message); } diff --git a/src/tests/Loader/classloader/regressions/347422/b347422.cs b/src/tests/Loader/classloader/regressions/347422/b347422.cs index a87036789d538c..cbe049c8392473 100644 --- a/src/tests/Loader/classloader/regressions/347422/b347422.cs +++ b/src/tests/Loader/classloader/regressions/347422/b347422.cs @@ -35,7 +35,7 @@ public static int TestEntryPoint() string msg ="Unable to cast object of type 'System.Object' to type 'IFoo'."; - if (e.Message.Equals(msg)) + if (e.Message.Equals(msg) || e.Message.Contains("Debugging resource strings are unavailable")) { Console.WriteLine("PASS"); return 100; From fa265bd92a5304c23692a9a7d8298510836eb052 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 26 Mar 2026 00:32:31 +0000 Subject: [PATCH 19/25] Fix nullable handling in ALC InvalidCastException tests Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/ef85b9f5-bbfa-4943-ba70-6c021e862098 --- .../tests/AssemblyLoadContextTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs index 0d2c60e7a1b1c5..250e494faa550f 100644 --- a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs @@ -283,8 +283,8 @@ public static void InvalidCastException_DifferentALC_ShowsAssemblyInfo() var alc = new AssemblyLoadContext("TestALC"); Assembly alcAssembly = alc.LoadFromAssemblyPath(typeof(AssemblyLoadContextTest).Assembly.Location); - Type alcType = alcAssembly.GetType(typeof(InvalidCastSharedType).FullName); - object instance = Activator.CreateInstance(alcType); + Type alcType = alcAssembly.GetType(typeof(InvalidCastSharedType).FullName!, throwOnError: true)!; + object instance = Activator.CreateInstance(alcType)!; // Cast directly to InvalidCastSharedType from the Default ALC. var ice = Assert.Throws(() => @@ -306,9 +306,9 @@ public static void InvalidCastException_GenericTypeArg_DifferentALC_ShowsAssembl // The outer type (StrongBox) is from CoreLib (same in all contexts), // but the generic argument comes from a different ALC. - Type alcType = alcAssembly.GetType(typeof(InvalidCastSharedType).FullName); + Type alcType = alcAssembly.GetType(typeof(InvalidCastSharedType).FullName!, throwOnError: true)!; Type boxType = typeof(StrongBox<>).MakeGenericType(alcType); - object instance = Activator.CreateInstance(boxType); + object instance = Activator.CreateInstance(boxType)!; var ice = Assert.Throws(() => { From 3246134c5d526ca7d4ac82079411d47909f3873d Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Wed, 25 Mar 2026 17:32:44 -0700 Subject: [PATCH 20/25] Apply suggestions from code review Co-authored-by: Elinor Fung --- .../System.Runtime.Loader/tests/AssemblyLoadContextTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs index 250e494faa550f..446d844f0d493f 100644 --- a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs @@ -315,10 +315,10 @@ public static void InvalidCastException_GenericTypeArg_DifferentALC_ShowsAssembl StrongBox _ = (StrongBox)instance; }); - // The message should include the full generic type names with the differing argument + // The message should include the types with the differing generic argument types // and the ALC context names. Assert.Contains(nameof(StrongBox), ice.Message); - Assert.Contains("generic argument '", ice.Message); + Assert.Contains($"generic argument '{nameof(InvalidCastSharedType)}", ice.Message); Assert.Contains("Default", ice.Message); Assert.Contains("TestALC", ice.Message); } From 26828023246bce76b2e72343887ae61c9d3ad300 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Fri, 27 Mar 2026 11:05:37 -0700 Subject: [PATCH 21/25] Apply suggestion from @elinor-fung --- .../System.Runtime.Loader/tests/AssemblyLoadContextTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs index 446d844f0d493f..31af15049c26ec 100644 --- a/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/AssemblyLoadContextTest.cs @@ -318,7 +318,7 @@ public static void InvalidCastException_GenericTypeArg_DifferentALC_ShowsAssembl // The message should include the types with the differing generic argument types // and the ALC context names. Assert.Contains(nameof(StrongBox), ice.Message); - Assert.Contains($"generic argument '{nameof(InvalidCastSharedType)}", ice.Message); + Assert.Contains($"generic argument '{typeof(InvalidCastSharedType).FullName}", ice.Message); Assert.Contains("Default", ice.Message); Assert.Contains("TestALC", ice.Message); } From b6399cae40294c7c7e834ccc0a167fb0e4910170 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Fri, 27 Mar 2026 19:24:01 -0700 Subject: [PATCH 22/25] Add depth limit and defensive asserts to FindFirstDifferingGenericArgument - Add depth counter to FindFirstDifferingGenericArgument to bound recursion for deeply nested generic types - Add _ASSERTE null checks for GetAssembly()/GetPEAssembly() in the generic arg code path, matching the pattern used for outer types Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/vm/excep.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index 64144c766bcb79..591e45db500f4e 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -10196,10 +10196,14 @@ VOID GetGenericArgAssemblyDetailInfo(SString &sType, } static BOOL FindFirstDifferingGenericArgument(TypeHandle thFrom, TypeHandle thTo, - TypeHandle *pthArgFrom, TypeHandle *pthArgTo) + TypeHandle *pthArgFrom, TypeHandle *pthArgTo, + DWORD depth = 0) { WRAPPER_NO_CONTRACT; + if (depth > 8) + return FALSE; + Instantiation instFrom = thFrom.GetInstantiation(); Instantiation instTo = thTo.GetInstantiation(); @@ -10215,7 +10219,7 @@ static BOOL FindFirstDifferingGenericArgument(TypeHandle thFrom, TypeHandle thTo Module *pModTo = instTo[i].GetModule(); if (pModFrom != NULL && pModTo != NULL && pModFrom == pModTo) { - if (FindFirstDifferingGenericArgument(instFrom[i], instTo[i], pthArgFrom, pthArgTo)) + if (FindFirstDifferingGenericArgument(instFrom[i], instTo[i], pthArgFrom, pthArgTo, depth + 1)) return TRUE; } @@ -10279,8 +10283,17 @@ VOID CheckAndThrowSameTypeAndAssemblyInvalidCastException(TypeHandle thCastFrom, StackSString sGenericArgName; thDifferingArgFrom.GetName(sGenericArgName); - PEAssembly *pPEAssemblyArgFrom = pModuleArgFrom->GetAssembly()->GetPEAssembly(); - PEAssembly *pPEAssemblyArgTo = pModuleArgTo->GetAssembly()->GetPEAssembly(); + Assembly *pAssemblyArgFrom = pModuleArgFrom->GetAssembly(); + Assembly *pAssemblyArgTo = pModuleArgTo->GetAssembly(); + + _ASSERTE(pAssemblyArgFrom != NULL); + _ASSERTE(pAssemblyArgTo != NULL); + + PEAssembly *pPEAssemblyArgFrom = pAssemblyArgFrom->GetPEAssembly(); + PEAssembly *pPEAssemblyArgTo = pAssemblyArgTo->GetPEAssembly(); + + _ASSERTE(pPEAssemblyArgFrom != NULL); + _ASSERTE(pPEAssemblyArgTo != NULL); StackSString sArgAssemblyFromDisplayName; StackSString sArgAssemblyToDisplayName; From 24321ba52fd7ae9a021c9ea27087f79c14b49933 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 21:40:00 +0000 Subject: [PATCH 23/25] Move format strings to resource file, make helpers static, use precise contracts Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/b5ad0db3-db7f-457d-898c-222b8da6c989 Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> --- src/coreclr/dlls/mscorrc/mscorrc.rc | 4 ++ src/coreclr/dlls/mscorrc/resource.h | 4 ++ src/coreclr/vm/excep.cpp | 92 +++++++++++++++++------------ 3 files changed, 61 insertions(+), 39 deletions(-) diff --git a/src/coreclr/dlls/mscorrc/mscorrc.rc b/src/coreclr/dlls/mscorrc/mscorrc.rc index 67962014926b63..724394d9911bb2 100644 --- a/src/coreclr/dlls/mscorrc/mscorrc.rc +++ b/src/coreclr/dlls/mscorrc/mscorrc.rc @@ -397,6 +397,10 @@ BEGIN IDS_EE_CANNOTCAST "Unable to cast object of type '%1' to type '%2'." IDS_EE_CANNOTCASTSAME "[A]%1 cannot be cast to [B]%2. %3. %4." + IDS_EE_CANNOTCASTSAME_DETAIL_BYTE_ARRAY "Type %1 originates from '%2' in the context '%3' in a byte array" + IDS_EE_CANNOTCASTSAME_DETAIL_LOCATION "Type %1 originates from '%2' in the context '%3' at location '%4'" + IDS_EE_CANNOTCASTSAME_GENARG_BYTE_ARRAY "Type %1 has a generic argument '%2' that originates from '%3' in the context '%4' in a byte array" + IDS_EE_CANNOTCASTSAME_GENARG_LOCATION "Type %1 has a generic argument '%2' that originates from '%3' in the context '%4' at location '%5'" IDS_EE_INVALID_VT_FOR_CUSTOM_MARHALER "Type of the VARIANT specified for a parameter with a custom marshaler is not supported by the custom marshaler." IDS_EE_BAD_COMEXTENDS_CLASS "Types extending from COM objects should override all methods of an interface implemented by the base COM class." IDS_EE_MARSHAL_UNMAPPABLE_CHAR "Cannot marshal: Encountered unmappable character." diff --git a/src/coreclr/dlls/mscorrc/resource.h b/src/coreclr/dlls/mscorrc/resource.h index 542e8cfbba4b77..9906a03515c1f3 100644 --- a/src/coreclr/dlls/mscorrc/resource.h +++ b/src/coreclr/dlls/mscorrc/resource.h @@ -523,3 +523,7 @@ #define IDS_EE_NDIRECT_DISABLEDMARSHAL_LCID 0x264E #define IDS_EE_NDIRECT_DISABLEDMARSHAL_PRESERVESIG 0x264F #define IDS_EE_NDIRECT_DISABLEDMARSHAL_VARARGS 0x2650 +#define IDS_EE_CANNOTCASTSAME_DETAIL_BYTE_ARRAY 0x2651 +#define IDS_EE_CANNOTCASTSAME_DETAIL_LOCATION 0x2652 +#define IDS_EE_CANNOTCASTSAME_GENARG_BYTE_ARRAY 0x2653 +#define IDS_EE_CANNOTCASTSAME_GENARG_LOCATION 0x2654 diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index 591e45db500f4e..bb0dccda5717c6 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -10130,69 +10130,83 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(EXCEPINFO *pExcepInfo) // Throw an InvalidCastException //========================================================================== -VOID GetAssemblyDetailInfo(SString &sType, - SString &sAssemblyDisplayName, - PEAssembly *pPEAssembly, - SString &sAssemblyDetailInfo) +static VOID GetAssemblyDetailInfo(SString &sType, + SString &sAssemblyDisplayName, + PEAssembly *pPEAssembly, + SString &sAssemblyDetailInfo) { - WRAPPER_NO_CONTRACT; - - SString detailsUtf8; + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; SString sAlcName; pPEAssembly->GetAssemblyBinder()->GetNameForDiagnostics(sAlcName); SString assemblyPath{ pPEAssembly->GetPath() }; + + SString resStr; + SString formatted; if (assemblyPath.IsEmpty()) { - detailsUtf8.Printf("Type %s originates from '%s' in the context '%s' in a byte array", - sType.GetUTF8(), - sAssemblyDisplayName.GetUTF8(), - sAlcName.GetUTF8()); + if (resStr.LoadResource(IDS_EE_CANNOTCASTSAME_DETAIL_BYTE_ARRAY)) + { + formatted.FormatMessage(FORMAT_MESSAGE_FROM_STRING, (LPCWSTR)resStr, 0, 0, + sType, sAssemblyDisplayName, sAlcName); + sAssemblyDetailInfo.Append(formatted); + } } else { - detailsUtf8.Printf("Type %s originates from '%s' in the context '%s' at location '%s'", - sType.GetUTF8(), - sAssemblyDisplayName.GetUTF8(), - sAlcName.GetUTF8(), - assemblyPath.GetUTF8()); + if (resStr.LoadResource(IDS_EE_CANNOTCASTSAME_DETAIL_LOCATION)) + { + formatted.FormatMessage(FORMAT_MESSAGE_FROM_STRING, (LPCWSTR)resStr, 0, 0, + sType, sAssemblyDisplayName, sAlcName, assemblyPath); + sAssemblyDetailInfo.Append(formatted); + } } - - sAssemblyDetailInfo.Append(detailsUtf8.GetUnicode()); } -VOID GetGenericArgAssemblyDetailInfo(SString &sType, - SString &sGenericArgName, - SString &sAssemblyDisplayName, - PEAssembly *pPEAssembly, - SString &sAssemblyDetailInfo) +static VOID GetGenericArgAssemblyDetailInfo(SString &sType, + SString &sGenericArgName, + SString &sAssemblyDisplayName, + PEAssembly *pPEAssembly, + SString &sAssemblyDetailInfo) { - WRAPPER_NO_CONTRACT; - - SString detailsUtf8; + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; SString sAlcName; pPEAssembly->GetAssemblyBinder()->GetNameForDiagnostics(sAlcName); SString assemblyPath{ pPEAssembly->GetPath() }; + + SString resStr; + SString formatted; if (assemblyPath.IsEmpty()) { - detailsUtf8.Printf("Type %s has a generic argument '%s' that originates from '%s' in the context '%s' in a byte array", - sType.GetUTF8(), - sGenericArgName.GetUTF8(), - sAssemblyDisplayName.GetUTF8(), - sAlcName.GetUTF8()); + if (resStr.LoadResource(IDS_EE_CANNOTCASTSAME_GENARG_BYTE_ARRAY)) + { + formatted.FormatMessage(FORMAT_MESSAGE_FROM_STRING, (LPCWSTR)resStr, 0, 0, + sType, sGenericArgName, sAssemblyDisplayName, sAlcName); + sAssemblyDetailInfo.Append(formatted); + } } else { - detailsUtf8.Printf("Type %s has a generic argument '%s' that originates from '%s' in the context '%s' at location '%s'", - sType.GetUTF8(), - sGenericArgName.GetUTF8(), - sAssemblyDisplayName.GetUTF8(), - sAlcName.GetUTF8(), - assemblyPath.GetUTF8()); + if (resStr.LoadResource(IDS_EE_CANNOTCASTSAME_GENARG_LOCATION)) + { + formatted.FormatMessage(FORMAT_MESSAGE_FROM_STRING, (LPCWSTR)resStr, 0, 0, + sType, sGenericArgName, sAssemblyDisplayName, sAlcName, assemblyPath); + sAssemblyDetailInfo.Append(formatted); + } } - - sAssemblyDetailInfo.Append(detailsUtf8.GetUnicode()); } static BOOL FindFirstDifferingGenericArgument(TypeHandle thFrom, TypeHandle thTo, From 57bb54fce83f95502e9840d4494efbdaef7eeaea Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Wed, 1 Apr 2026 14:14:29 -0700 Subject: [PATCH 24/25] Fix contract --- src/coreclr/vm/excep.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index bb0dccda5717c6..6dc09ff2854727 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -10138,7 +10138,7 @@ static VOID GetAssemblyDetailInfo(SString &sType, CONTRACTL { THROWS; - GC_NOTRIGGER; + GC_TRIGGERS; MODE_ANY; } CONTRACTL_END; @@ -10178,7 +10178,7 @@ static VOID GetGenericArgAssemblyDetailInfo(SString &sType, CONTRACTL { THROWS; - GC_NOTRIGGER; + GC_TRIGGERS; MODE_ANY; } CONTRACTL_END; From 533df113713600d653406a4c0e8df28508abce5c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Apr 2026 23:24:49 +0000 Subject: [PATCH 25/25] Replace CONTRACTL blocks with STANDARD_VM_CONTRACT in both helper functions Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/1bea2ed5-48c1-4f25-9f38-debb646a6433 Co-authored-by: elinor-fung <47805090+elinor-fung@users.noreply.github.com> --- src/coreclr/vm/excep.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index 6dc09ff2854727..57e69ebec1fc26 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -10135,13 +10135,7 @@ static VOID GetAssemblyDetailInfo(SString &sType, PEAssembly *pPEAssembly, SString &sAssemblyDetailInfo) { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; + STANDARD_VM_CONTRACT; SString sAlcName; pPEAssembly->GetAssemblyBinder()->GetNameForDiagnostics(sAlcName); @@ -10175,13 +10169,7 @@ static VOID GetGenericArgAssemblyDetailInfo(SString &sType, PEAssembly *pPEAssembly, SString &sAssemblyDetailInfo) { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; + STANDARD_VM_CONTRACT; SString sAlcName; pPEAssembly->GetAssemblyBinder()->GetNameForDiagnostics(sAlcName);