Skip to content

Comments

Fix LoadExactInterfaceMap for sub-interfaces with complex type arguments under special marker parents#124684

Open
davidwrighton wants to merge 3 commits intodotnet:mainfrom
davidwrighton:fix_124369
Open

Fix LoadExactInterfaceMap for sub-interfaces with complex type arguments under special marker parents#124684
davidwrighton wants to merge 3 commits intodotnet:mainfrom
davidwrighton:fix_124369

Conversation

@davidwrighton
Copy link
Member

Summary

When pNewIntfMT is a special marker type and its sub-interface in the interface map has an exact instantiation containing complex type arguments (e.g. IList<T> rather than bare T), the previous code in LoadExactInterfaceMap would incorrectly fall through to the old case 4 logic. This checked EligibleForSpecialMarkerTypeUsage against pMT rather than pNewIntfMT, which could treat a sub-interface still containing unresolved generic variables as either eligible for special marker substitution or as an exact match — both incorrect.

Fix

The old case 4 (exact instantiation) is split into three cases to correctly handle the situation where pNewIntfMT is itself a special marker type:

  • Case 4: The sub-interface's instantiation is eligible for special marker usage relative to pNewIntfMT (e.g. ILayer1<T> where T matches pNewIntfMT's type parameter). Insert the special marker type.
  • Case 5: The sub-interface has generic variables that don't match pNewIntfMT's type parameter (e.g. ILayer1<IList<T>>). Since resolving this requires a full deep substitution, and this is a rare scenario, we fall back to the retry-with-exact-interfaces pathway which sets MayHaveOpenInterfacesInInterfaceMap and disables the special marker optimization for this type.
  • Case 6: The sub-interface is fully concrete (no generic variables) or pNewIntfMT is not a special marker type. Falls through to the existing pMT-based eligibility check, which is correct in these situations.

A regression test is added covering all 8 combinations of pre-loading the 3 interface layers' generic type definitions before constructing the concrete class, to exercise the various orderings that lead to different code paths through the special marker type logic.

Fixes #124369

davidwrighton and others added 3 commits February 20, 2026 14:45
…nts under special marker parents

When pNewIntfMT is a special marker type and its sub-interface has an
exact instantiation containing complex type arguments (e.g. IList(Of T)
rather than bare T), the previous code would fall through to case 4
which checked EligibleForSpecialMarkerTypeUsage against pMT. This could
incorrectly treat the sub-interface as an exact match when it still
contains unresolved generic variables.

Split old case 4 into three new cases:
- Case 4: pNewIntfMT is a special marker type and the sub-interface's
  instantiation is eligible for special marker usage relative to
  pNewIntfMT (e.g. ILayer1(Of T) where T matches). Insert the marker.
- Case 5: pNewIntfMT is a special marker type but the sub-interface has
  generic variables that don't match (e.g. ILayer1(Of IList(Of T))).
  Trigger retry with exact interfaces since full substitution is needed.
- Case 6: The sub-interface is fully concrete or pNewIntfMT is not a
  special marker. Fall through to the existing pMT-based eligibility
  check.

Add regression tests covering all 8 combinations of pre-loading the
3 interface layers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes CoreCLR interface-map exact-loading for the case where a special marker parent interface contains a sub-interface entry that is an exact instantiation with more complex type arguments (e.g., IList<T>), preventing incorrect eligibility checks and ensuring the algorithm falls back to the exact-interface retry path when deep substitution would be required.

Changes:

  • Split the prior “exact instantiation” handling in LoadExactInterfaceMap into additional sub-cases to correctly handle special-marker parents and open generic variables.
  • Add a VB regression test suite (with 8 preload-order combinations) to exercise the special marker interface map logic and validate the fix.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/coreclr/vm/methodtablebuilder.cpp Refines LoadExactInterfaceMap handling for exact sub-interfaces under special marker parents, including a controlled fallback path.
src/tests/Loader/classloader/regressions/GitHub_124369/GitHub_124369.vb Adds VB regression coverage for the reported failure mode across multiple preload orderings and interface layering shapes.
src/tests/Loader/classloader/regressions/GitHub_124369/GitHub_124369.vbproj Adds the test project definition for the new VB regression test.

Public Class GitHub_124369

' Test the scenario where the implied interface is in the interface map of a containing interface as a special marker type, and the containing interface itself is ALSO a special marker type.
' The critical path is that when establishing the interface map for ILayer3_1(Of T) we find read ILayer1_1(Of T) as a special marker type member of ILayer2_1(Of T), and the ILayer2_1(Of T) itself is a special marker type.
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor grammar: “we find read ILayer…” appears to have an extra word (“read”) that makes the sentence confusing. Consider removing it so the comment describes the critical path clearly.

Suggested change
' The critical path is that when establishing the interface map for ILayer3_1(Of T) we find read ILayer1_1(Of T) as a special marker type member of ILayer2_1(Of T), and the ILayer2_1(Of T) itself is a special marker type.
' The critical path is that when establishing the interface map for ILayer3_1(Of T) we find ILayer1_1(Of T) as a special marker type member of ILayer2_1(Of T), and the ILayer2_1(Of T) itself is a special marker type.

Copilot uses AI. Check for mistakes.
Comment on lines +9838 to 9851
// 2. It is a special marker type, AND pNewItfMT is a special marker type. Compute the exact instantiation as containing entirely a list of
// types corresponding to calling GetSpecialInstantiationType on pMT (This rule works based on the current behavior of
// GetSpecialInstantiationType where it treats all interfaces the same)
// 3. It is a special marker type, but pNewItfMT is NOT a special marker type. Compute the exact instantiation as containing entirely a list
// of types corresponding to calling GetSpecialInstantiationType on pNewItfMT
// 4. It is an exact instantiation, but pNewIntfMT was a special marker type, and the exact instantiation type found here could have been a
// special marker type. This should produce a result equivalent to case 2 (the special marker type)
// 5. It is an exact instantiation, but pNewIntfMT was a special marker type, and the exact instantiation type is NOT one which would have
// been on the exact instantiation of pNewItfMT if it were not a special marker type. In theory we could reconstruct this, but this is a
// rare scenario, so we just fallback to the retry with exact interfaces pathway
// 6. It is an exact instantiation, and pNewIntfMT is NOT a special marker type, compute the result and insert either a special marker or
// the exact instantiation already found.
//
// NOTE: pItfPossiblyApprox must not be considered a special marker type if pNewItfMT has the MayHaveOpenInterfacesInInterfaceMap flag set
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The updated case list comment uses both pNewItfMT and pNewIntfMT to refer to the same variable, and one wrapped line is mis-indented. Please normalize the name (likely pNewIntfMT everywhere) and reflow the comment so it’s unambiguous.

Suggested change
// 2. It is a special marker type, AND pNewItfMT is a special marker type. Compute the exact instantiation as containing entirely a list of
// types corresponding to calling GetSpecialInstantiationType on pMT (This rule works based on the current behavior of
// GetSpecialInstantiationType where it treats all interfaces the same)
// 3. It is a special marker type, but pNewItfMT is NOT a special marker type. Compute the exact instantiation as containing entirely a list
// of types corresponding to calling GetSpecialInstantiationType on pNewItfMT
// 4. It is an exact instantiation, but pNewIntfMT was a special marker type, and the exact instantiation type found here could have been a
// special marker type. This should produce a result equivalent to case 2 (the special marker type)
// 5. It is an exact instantiation, but pNewIntfMT was a special marker type, and the exact instantiation type is NOT one which would have
// been on the exact instantiation of pNewItfMT if it were not a special marker type. In theory we could reconstruct this, but this is a
// rare scenario, so we just fallback to the retry with exact interfaces pathway
// 6. It is an exact instantiation, and pNewIntfMT is NOT a special marker type, compute the result and insert either a special marker or
// the exact instantiation already found.
//
// NOTE: pItfPossiblyApprox must not be considered a special marker type if pNewItfMT has the MayHaveOpenInterfacesInInterfaceMap flag set
// 2. It is a special marker type, AND pNewIntfMT is a special marker type. Compute the exact instantiation as containing entirely a list of
// types corresponding to calling GetSpecialInstantiationType on pMT (This rule works based on the current behavior of
// GetSpecialInstantiationType where it treats all interfaces the same)
// 3. It is a special marker type, but pNewIntfMT is NOT a special marker type. Compute the exact instantiation as containing entirely a list
// of types corresponding to calling GetSpecialInstantiationType on pNewIntfMT
// 4. It is an exact instantiation, but pNewIntfMT was a special marker type, and the exact instantiation type found here could have been a
// special marker type. This should produce a result equivalent to case 2 (the special marker type)
// 5. It is an exact instantiation, but pNewIntfMT was a special marker type, and the exact instantiation type is NOT one which would have
// been on the exact instantiation of pNewIntfMT if it were not a special marker type. In theory we could reconstruct this, but this is a
// rare scenario, so we just fallback to the retry with exact interfaces pathway
// 6. It is an exact instantiation, and pNewIntfMT is NOT a special marker type, compute the result and insert either a special marker or
// the exact instantiation already found.
//
// NOTE: pItfPossiblyApprox must not be considered a special marker type if pNewIntfMT has the MayHaveOpenInterfacesInInterfaceMap flag set

Copilot uses AI. Check for mistakes.
{
// case 4 (We have an exact interface)
if (ClassLoader::EligibleForSpecialMarkerTypeUsage(pItfPossiblyApprox->GetInstantiation(), pMT))
// case 4 or 5 (We have an exact interface)
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment says “case 4 or 5” but the code below also handles case 6 when pItfToInsert remains null. Consider updating the comment to reflect cases 4–6 to avoid confusion during future maintenance.

Suggested change
// case 4 or 5 (We have an exact interface)
// case 4, 5, or 6 (We have an exact interface)

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +20
' This is a variant of GitHub_123254 test which tests the situations where various of the interfaces
' types have had their open generic type loaded, and the interfaces examined
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor grammar/clarity: the introductory comment reads a bit awkwardly (e.g., “various of the interfaces types”). Consider rephrasing to improve readability since this file is primarily explanatory for a regression scenario.

Suggested change
' This is a variant of GitHub_123254 test which tests the situations where various of the interfaces
' types have had their open generic type loaded, and the interfaces examined
' This is a variant of the GitHub_123254 test, which covers situations where various interface
' types have had their open generic type loaded and the resulting interfaces examined.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

VB.NET program using .NET runtime 10.0.3 throws EntryPointNotFoundException

1 participant