From e684d9066b8b3bec91a63d438a106059fb416eb5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 23:33:10 +0000 Subject: [PATCH 1/2] Initial plan From 0ec6be6c49f96541a84261a9b91283c3936bbfb0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Apr 2026 00:24:47 +0000 Subject: [PATCH 2/2] Fix: Skip constraint checks for generic variable instantiations in NewInstantiatedMethodDesc Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/9fad8273-85b4-4d8a-94f7-8b35c17735ac Co-authored-by: davidwrighton <10779849+davidwrighton@users.noreply.github.com> --- src/coreclr/vm/genmeth.cpp | 11 +++- .../TypeLoadWithGenericVars.cs | 50 +++++++++++++++++++ .../TypeLoadWithGenericVars.csproj | 11 ++++ 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/tests/Loader/classloader/generics/Constraints/Regressions/TypeLoadWithGenericVars/TypeLoadWithGenericVars.cs create mode 100644 src/tests/Loader/classloader/generics/Constraints/Regressions/TypeLoadWithGenericVars/TypeLoadWithGenericVars.csproj diff --git a/src/coreclr/vm/genmeth.cpp b/src/coreclr/vm/genmeth.cpp index 62f413ada24e67..300e2873682764 100644 --- a/src/coreclr/vm/genmeth.cpp +++ b/src/coreclr/vm/genmeth.cpp @@ -474,10 +474,19 @@ InstantiatedMethodDesc::NewInstantiatedMethodDesc(MethodTable *pExactMT, // The canonical instantiation is exempt from constraint checks. It's used as the basis // for all other reference instantiations so we can't not load it. The Canon type is // not visible to users so it can't be abused. + // + // Instantiations containing generic variables (type parameters) are also exempt. + // Such instantiations arise during JIT access checks when the caller is a generic + // method and the EE resolves method specs using the caller's formal type parameters. + // Constraint checking for these instantiations would unnecessarily load types + // instantiated over the type variables (e.g. IList). The actual constraint + // check will happen when the method is instantiated with concrete types. BOOL fExempt = TypeHandle::IsCanonicalSubtypeInstantiation(methodInst) || - TypeHandle::IsCanonicalSubtypeInstantiation(pNewMD->GetClassInstantiation()); + TypeHandle::IsCanonicalSubtypeInstantiation(pNewMD->GetClassInstantiation()) || + MethodTable::ComputeContainsGenericVariables(methodInst) || + MethodTable::ComputeContainsGenericVariables(pNewMD->GetClassInstantiation()); if (!fExempt) { diff --git a/src/tests/Loader/classloader/generics/Constraints/Regressions/TypeLoadWithGenericVars/TypeLoadWithGenericVars.cs b/src/tests/Loader/classloader/generics/Constraints/Regressions/TypeLoadWithGenericVars/TypeLoadWithGenericVars.cs new file mode 100644 index 00000000000000..5084fdc64831d8 --- /dev/null +++ b/src/tests/Loader/classloader/generics/Constraints/Regressions/TypeLoadWithGenericVars/TypeLoadWithGenericVars.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Regression test: access checks triggered by the JIT for generic methods with +// constraints should not unnecessarily load types instantiated over type variables. +// The JIT uses the typical method definition (with formal type params) when doing +// security checks for generic callers, which was triggering constraint checks that +// loaded types like IList where TMethod is a type variable. + +using System; +using System.Collections.Generic; +using Xunit; + +public class TypeLoadWithGenericVars +{ + static void Method() where TMethod1_1 : IList + { + Method2(); + } + + static void Method2() where TMethod2_1 : IList + { + } + + static void MethodA() + where T1 : IList + where T2 : IList + { + MethodB(); + } + + static void MethodB() + where U1 : IList + where U2 : IList + { + } + + [Fact] + public static void TestEntryPoint() + { + // Call with concrete types that satisfy the constraints. + // The JIT will use the typical method definition for access checks, + // which previously caused unnecessary loading of IList, etc. + Method, int>(); + Method(); + + // Test with chained generic constraints + MethodA>, List, int>(); + } +} diff --git a/src/tests/Loader/classloader/generics/Constraints/Regressions/TypeLoadWithGenericVars/TypeLoadWithGenericVars.csproj b/src/tests/Loader/classloader/generics/Constraints/Regressions/TypeLoadWithGenericVars/TypeLoadWithGenericVars.csproj new file mode 100644 index 00000000000000..30d4804022360c --- /dev/null +++ b/src/tests/Loader/classloader/generics/Constraints/Regressions/TypeLoadWithGenericVars/TypeLoadWithGenericVars.csproj @@ -0,0 +1,11 @@ + + + 1 + + + + + + + +