Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using a default method on an interface to implement a static virtual interface method leads to memory corruption #107754

Closed
davidwrighton opened this issue Sep 12, 2024 · 0 comments · Fixed by #107763
Labels
in-pr There is an active PR which will close this issue when it is merged needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners

Comments

@davidwrighton
Copy link
Member

Description

There is a bug in the computation of static virtual method targets in the presence of variant dispatch and default interface methods that leads to unsafe memory usage.

Reproduction Steps

Run the following program. During the JIT of M<U> there is access to the GC heap that is not done in cooperative mode. This can be observed easily by using the check or debug builds of coreclr.

using System.Runtime.CompilerServices;

namespace VariantStaticVirtualConstraintCheck
{
    interface IStaticConstraint<in T>
    {
        public abstract static void M();
    }

    interface IStaticConstraintDefaultImpl<in T> : IStaticConstraint<T>
    {
        static void IStaticConstraint<T>.M() { Console.WriteLine("Implementation"); }
    }

    interface IConstraintCheck<U, W> where U : IStaticConstraint<W>
    {
    }

    struct StructThatImplementsConstraint : IStaticConstraintDefaultImpl<object>
    {
    }

    internal class Program
    {
        [MethodImpl(MethodImplOptions.NoInlining)]
        static void M<U>() where U: IStaticConstraint<string>
        {
            U.M();
        }

        static void Main(string[] args)
        {
            Console.WriteLine(typeof(IConstraintCheck<StructThatImplementsConstraint, string>));
            M<StructThatImplementsConstraint>();
        }
    }
}

Expected behavior

Program prints something like

VariantStaticVirtualConstraintCheck.IConstraintCheck`2[VariantStaticVirtualConstraintCheck.StructThatImplementsConstraint,System.String]
NonDefault Implementation

Actual behavior

Under a check or debug build of coreclr, the result looks more like

VariantStaticVirtualConstraintCheck.IConstraintCheck`2[VariantStaticVirtualConstraintCheck.StructThatImplementsConstraint,System.String]

Assert failure(PID 44276 [0x0000acf4], Thread: 7224 [0x1c38]): CONTRACT VIOLATION by MethodTable::CanCastTo at "C:\git2\runtime\src\coreclr\vm\methodtable.cpp":1383

MODE_COOPERATIVE encountered while thread is in preemptive state.

                        CONTRACT in MethodTable::CanCastTo at "C:\git2\runtime\src\coreclr\vm\methodtable.cpp":1383
                        CONTRACT in MethodTable::TryResolveVirtualStaticMethodOnThisType at "C:\git2\runtime\src\coreclr\vm\methodtable.cpp":7994
                        CONTRACT in MethodTable::FindDefaultInterfaceImplementation at "C:\git2\runtime\src\coreclr\vm\methodtable.cpp":5547
                        CONTRACT in MethodTable::ResolveVirtualStaticMethod at "C:\git2\runtime\src\coreclr\vm\methodtable.cpp":7831
                        CONTRACT in MethodTable::TryResolveConstraintMethodApprox at "C:\git2\runtime\src\coreclr\vm\methodtable.cpp":8214
VIOLATED-->  CONTRACT in CEEInfo::getCallInfo at "C:\git2\runtime\src\coreclr\vm\jitinterface.cpp":4892
                        GCX_PREEMP in invokeCompileMethod at "C:\git2\runtime\src\coreclr\vm\jitinterface.cpp":12558
                        CONTRACT in invokeCompileMethod at "C:\git2\runtime\src\coreclr\vm\jitinterface.cpp":12553
                        GCX_COOP in UnsafeJitFunction at "C:\git2\runtime\src\coreclr\vm\jitinterface.cpp":12991
                        CONTRACT in UnsafeJitFunction at "C:\git2\runtime\src\coreclr\vm\jitinterface.cpp":12825
                        CONTRACT in MethodDesc::JitCompileCodeLocked at "C:\git2\runtime\src\coreclr\vm\prestub.cpp":927
                        CONTRACT in MethodDesc::JitCompileCodeLockedEventWrapper at "C:\git2\runtime\src\coreclr\vm\prestub.cpp":759
                        CONTRACT in MethodDesc::JitCompileCode at "C:\git2\runtime\src\coreclr\vm\prestub.cpp":592
                        CONTRACT in MethodDesc::PrepareILBasedCode at "C:\git2\runtime\src\coreclr\vm\prestub.cpp":344
                        CONTRACT in MethodDesc::PrepareCode at "C:\git2\runtime\src\coreclr\vm\prestub.cpp":314
                        CONTRACT in CodeVersionManager::PublishVersionableCodeIfNecessary at "C:\git2\runtime\src\coreclr\vm\codeversion.cpp":1688
                        CONTRACT in MethodDesc::DoPrestub at "C:\git2\runtime\src\coreclr\vm\prestub.cpp":2774
                        GCX_PREEMP_THREAD_EXISTS in PreStubWorker at "C:\git2\runtime\src\coreclr\vm\prestub.cpp":2696
                        CONTRACT in MethodDescCallSite::CallTargetWorker at "C:\git2\runtime\src\coreclr\vm\callhelpers.cpp":307
                        GCX_COOP in Assembly::ExecuteMainMethod at "C:\git2\runtime\src\coreclr\vm\assembly.cpp":1363
                        ...



CORECLR! CONTRACT_ASSERT + 0x3D1 (0x00007fff`cb09ee91)
CORECLR! EEContract::DoChecks + 0x250 (0x00007fff`cb5bb140)
CORECLR! MethodTable::CanCastTo + 0x404 (0x00007fff`cb37edf4)
CORECLR! MethodTable::TryResolveVirtualStaticMethodOnThisType + 0x592 (0x00007fff`cb3a8262)
CORECLR! `anonymous namespace'::TryGetCandidateImplementation + 0x484 (0x00007fff`cb3a71d4)
CORECLR! MethodTable::FindDefaultInterfaceImplementation + 0xA07 (0x00007fff`cb38b147)
CORECLR! MethodTable::ResolveVirtualStaticMethod + 0x657 (0x00007fff`cb3a3957)
CORECLR! MethodTable::TryResolveConstraintMethodApprox + 0x286 (0x00007fff`cb3a7586)
CORECLR! CEEInfo::getCallInfo + 0x841 (0x00007fff`cb2f7e21)
CLRJIT! Compiler::eeGetCallInfo + 0x76 (0x00007fff`c0bf9e16)
    File: C:\git2\runtime\src\coreclr\vm\methodtable.cpp:1383

Regression?

No

Known Workarounds

No response

Configuration

No response

Other information

No response

@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Sep 12, 2024
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Sep 12, 2024
davidwrighton added a commit to davidwrighton/runtime that referenced this issue Sep 12, 2024
- Use `TypeHandle::CanCastTo` instead of `MethodTable::CanCastTo`
  - The issue is that the `MethodTable` api requires cooperative mode, and the `TypeHandle` supports either mode

Fixes dotnet#107754
@dotnet-policy-service dotnet-policy-service bot added the in-pr There is an active PR which will close this issue when it is merged label Sep 12, 2024
davidwrighton added a commit that referenced this issue Sep 13, 2024
- Use `TypeHandle::CanCastTo` instead of `MethodTable::CanCastTo`
  - The issue is that the `MethodTable` api requires cooperative mode, and the `TypeHandle` supports either mode

Fixes #107754
@dotnet-policy-service dotnet-policy-service bot removed the untriaged New issue has not been triaged by the area owner label Sep 13, 2024
github-actions bot pushed a commit that referenced this issue Sep 13, 2024
- Use `TypeHandle::CanCastTo` instead of `MethodTable::CanCastTo`
  - The issue is that the `MethodTable` api requires cooperative mode, and the `TypeHandle` supports either mode

Fixes #107754
jeffschwMSFT added a commit that referenced this issue Sep 13, 2024
- Use `TypeHandle::CanCastTo` instead of `MethodTable::CanCastTo`
  - The issue is that the `MethodTable` api requires cooperative mode, and the `TypeHandle` supports either mode

Fixes #107754

Co-authored-by: David Wrighton <davidwr@microsoft.com>
Co-authored-by: Jeff Schwartz <jeffschw@microsoft.com>
jtschuster pushed a commit to jtschuster/runtime that referenced this issue Sep 17, 2024
…07763)

- Use `TypeHandle::CanCastTo` instead of `MethodTable::CanCastTo`
  - The issue is that the `MethodTable` api requires cooperative mode, and the `TypeHandle` supports either mode

Fixes dotnet#107754
sirntar pushed a commit to sirntar/runtime that referenced this issue Sep 30, 2024
…07763)

- Use `TypeHandle::CanCastTo` instead of `MethodTable::CanCastTo`
  - The issue is that the `MethodTable` api requires cooperative mode, and the `TypeHandle` supports either mode

Fixes dotnet#107754
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in-pr There is an active PR which will close this issue when it is merged needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant