Skip to content

Commit

Permalink
Fix memory corruption bug in virtual static method dispatch (#107776)
Browse files Browse the repository at this point in the history
- 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>
  • Loading branch information
3 people authored Sep 13, 2024
1 parent 15ef393 commit 2081c29
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 3 deletions.
13 changes: 10 additions & 3 deletions src/coreclr/vm/methodtable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7868,8 +7868,9 @@ MethodTable::ResolveVirtualStaticMethod(
ClassLoadLevel level)
{
CONTRACTL{
THROWS;
GC_TRIGGERS;
MODE_ANY;
THROWS;
GC_TRIGGERS;
} CONTRACTL_END;

bool verifyImplemented = (resolveVirtualStaticMethodFlags & ResolveVirtualStaticMethodFlags::VerifyImplemented) != ResolveVirtualStaticMethodFlags::None;
Expand Down Expand Up @@ -8029,6 +8030,12 @@ MethodTable::ResolveVirtualStaticMethod(
MethodDesc*
MethodTable::TryResolveVirtualStaticMethodOnThisType(MethodTable* pInterfaceType, MethodDesc* pInterfaceMD, ResolveVirtualStaticMethodFlags resolveVirtualStaticMethodFlags, ClassLoadLevel level)
{
CONTRACTL{
MODE_ANY;
THROWS;
GC_TRIGGERS;
} CONTRACTL_END;

bool instantiateMethodParameters = (resolveVirtualStaticMethodFlags & ResolveVirtualStaticMethodFlags::InstantiateResultOverFinalMethodDesc) != ResolveVirtualStaticMethodFlags::None;
bool allowVariance = (resolveVirtualStaticMethodFlags & ResolveVirtualStaticMethodFlags::AllowVariantMatches) != ResolveVirtualStaticMethodFlags::None;
bool verifyImplemented = (resolveVirtualStaticMethodFlags & ResolveVirtualStaticMethodFlags::VerifyImplemented) != ResolveVirtualStaticMethodFlags::None;
Expand Down Expand Up @@ -8084,7 +8091,7 @@ MethodTable::TryResolveVirtualStaticMethodOnThisType(MethodTable* pInterfaceType
{
// Allow variant, but not equivalent interface match
if (!pInterfaceType->HasSameTypeDefAs(pInterfaceMT) ||
!pInterfaceMT->CanCastTo(pInterfaceType, NULL))
!TypeHandle(pInterfaceMT).CanCastTo(pInterfaceType, NULL))
{
continue;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.CompilerServices;
using Xunit;

// This test comes from https://github.com/dotnet/runtime/issues/107754

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

interface IStaticConstraintDefaultImpl<in T> : IStaticConstraint<T>
{
static void IStaticConstraint<T>.M() { }
}

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

struct StructThatImplementsConstraint : IStaticConstraintDefaultImpl<object>
{
}

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

[Fact]
public static void RunTest()
{
System.Console.WriteLine(typeof(IConstraintCheck<StructThatImplementsConstraint, string>));
M<StructThatImplementsConstraint>();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<DebugType>Full</DebugType>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileName).cs" />
</ItemGroup>
</Project>

0 comments on commit 2081c29

Please sign in to comment.