Skip to content

ILVerify: allow family access through implemented interfaces - #136176

Merged
jkotas merged 1 commit into
dotnet:mainfrom
pcshrosbree:fix/ilverify-family-access-interfaces
Oct 21, 2026
Merged

jkotas merged 1 commit into
dotnet:mainfrom
pcshrosbree:fix/ilverify-family-access-interfaces

Conversation

@pcshrosbree

Copy link
Copy Markdown
Contributor

TL;DR: ILVerify rejects calls to protected interface members from types that implement those interfaces, although the runtime allows the calls. This PR makes the access check accept them, as the runtime does. The fix is 12 lines plus seven IL tests. Scans of the shared framework and four sets of NuGet packages found changes only in methods affected by these access errors.

Fixes #136175

Change

CanAccessFamily in AccessVerificationHelpers.cs looked for the target's type definition only among the current type's base types. When the target is an interface, it now looks among the current type's RuntimeInterfaces instead, and compares type definitions. This matches the runtime: ClassLoader::CanAccessFamily searches the caller's interface map by type definition, so any instantiation of a generic interface counts. RuntimeInterfaces includes interfaces inherited from base classes and from other interfaces. The existing loop over enclosing types covers nested types.

The check that a protected instance member is accessed through an instance of the current type runs first, as before. The runtime does not make that check, but ILVerify already applies it to classes, and this change keeps it for interfaces too.

Tests

Seven methods in ILTests/AccessTests.il, each for one rule:

Test Shape Expected
Call.FamilyStaticOfOtherInstantiation struct implementing IFamilyMembers<Self> calls IFamilyMembers<T>'s protected static method through constrained. (the Int32.CreateChecked shape) valid
Call.FamilyStaticOfInterfaceOfBaseClass class whose base class implements the interface valid
Call.FamilyStaticFromNestedType type nested in a class that implements the interface valid
Call.FamilyInstanceOfBaseInterface default method of a derived interface calls a protected instance method on this valid
Call.FamilyStaticFromUnrelatedType class that implements no interface MethodAccess
Call.FamilyStaticFromOtherInterface class that implements only an unrelated interface MethodAccess
Call.FamilyInstanceThroughOtherImplementer implementing class calls a protected instance method through an instance of another implementing class MethodAccess
  • The four valid tests fail on main with MethodAccess. The three invalid tests pass on main and with this change.
  • ILVerification.Tests passes 535 of 535 in Release and in Debug.
  • I tested six deliberately broken versions of the new code. Each made the tests written for it fail:
    • drop the interface branch;
    • compare instantiated types instead of type definitions;
    • use only the interfaces a type declares itself;
    • accept any implemented interface;
    • accept every caller;
    • check interfaces before the instance rule.
  • I also ran each shape on .NET 10.0.12. The four valid shapes run. The unrelated and other-interface shapes throw MethodAccessException. The other-implementer shape passes the runtime's access check, which does not check the instance, and then throws NullReferenceException for its null receiver.

Measured impact

I scanned with ILVerify built from main and from this branch. The inputs were the shared framework (Microsoft.NETCore.App 10.0.12, 130,146 method bodies) and 388,490 method bodies from four sets of NuGet packages.

  • Verification mode, comparing main with this branch. The only package that changes is DotNext 6.10.0. It loses 51 of its 52 MethodAccess errors, in 41 methods, and 38 of those methods now verify. The remaining error is an ldvirtftn of Object.Finalize, which is not an interface member. One method, InlineBufferWriter<T>.GetBuffer, now reports ReturnPtrToStack at its ret. The MethodAccess error had stopped ILVerify in the method's first block, before it reached the block containing that ret. The framework results do not change, because the 57 framework calls are in methods that fail earlier with InitLocals.
  • Validation-only mode (ILVerify: add a validation-only mode #136169, with this change applied on its head). The 57 framework MethodAccess errors go away, in CreateChecked, CreateSaturating and CreateTruncating of 19 numeric types (51 in System.Private.CoreLib, 6 in System.Runtime.Numerics). Those 57 methods now pass. DotNext loses the same 51 errors, and 41 of its methods now pass.
  • Nothing else changes in either mode.

Note

This PR was prepared with AI assistance (Anthropic Claude and OpenAI Codex), under my direction. I reviewed it before posting.

The ECMA-335 augments for default interface methods let a type that
implements an interface access the interface's protected members. The
runtime enforces this in ClassLoader::CanAccessFamily: when the target
is an interface, access is granted if the caller, or a type that
encloses it, has an interface with the same type definition in its
interface map. Any instantiation of a generic interface counts.

ILVerify's CanAccessFamily only walked base classes, so it reported
MethodAccess for these calls. One example is
Int32.CreateChecked<TOther>, which calls the protected static abstract
method INumberBase<TOther>.TryConvertToChecked.

When the target is an interface, look for its type definition among
the runtime interfaces of the current type. The rule that a protected
instance member is accessed through an instance of the current type
is unchanged.
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Oct 20, 2026
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke
See info in area-owners.md if you want to be subscribed.

@jkotas jkotas added area-Tools-ILVerification Issues related to ilverify tool and IL verification in general and removed area-VM-coreclr labels Oct 20, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @dotnet/jit-contrib
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The focused implementation preserves existing restrictions, has targeted regression coverage, and has no unresolved findings.

No open issues 🎉

What changed in this PR

Fixes ILVerify’s rejection of protected interface-member calls from implementing types, aligning interface eligibility with the runtime.

Changes:

  • Checks implemented interfaces by type definition, including different generic instantiations.
  • Preserves existing protected-instance receiver restrictions.
  • Adds seven positive and negative IL regression tests.

Builds and tests were not rerun during this review.

File Description
src/​coreclr/​tools/​ILVerification/​AccessVerificationHelpers.cs Adds interface-aware family-access checks.
src/​coreclr/​tools/​ILVerification.Tests/​ILTests/​AccessTests.il Covers generic, inherited, nested, and rejected access scenarios.

Review effort: Balanced

@jkotas

jkotas commented Oct 21, 2026

Copy link
Copy Markdown
Member

/ba-g opened #136205 on the test failure

@jkotas
jkotas merged commit b3c0988 into dotnet:main Oct 21, 2026
138 of 141 checks passed
@pcshrosbree

Copy link
Copy Markdown
Contributor Author

Thank you for the review and merge!

@pcshrosbree
pcshrosbree deleted the fix/ilverify-family-access-interfaces branch October 21, 2026 07:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-Tools-ILVerification Issues related to ilverify tool and IL verification in general community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ILVerify reports MethodAccess when a type calls a protected member of an interface it implements

3 participants