From 43a8b88b509413c78ebfaf44ba4ac5111e4ecf60 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Sat, 6 Feb 2021 00:06:38 +0100 Subject: [PATCH] [Release/5.0] Fix covariant returns when overriding method of non-parent ancestor There is a problem in the ClassLoader::ValidateMethodsWithCovariantReturnTypes that results in failed verification of valid override in case the return type of the method being overriden is generic in canonical form and it is defined in an ancestor class that is not the parent. The problem is that we attempt to use instantiation of the parent class instead of the ancestor class that contains definition of the method being overriden. This change fixes it by locating the proper ancestor MethodTable and using it. --- src/coreclr/src/vm/class.cpp | 6 +++ .../coreclr/GitHub_45053/test45053.cs | 39 +++++++++++++++++++ .../coreclr/GitHub_45053/test45053.csproj | 10 +++++ 3 files changed, 55 insertions(+) create mode 100644 src/tests/Regressions/coreclr/GitHub_45053/test45053.cs create mode 100644 src/tests/Regressions/coreclr/GitHub_45053/test45053.csproj diff --git a/src/coreclr/src/vm/class.cpp b/src/coreclr/src/vm/class.cpp index 0f398b93c6cce2..e8b39c00b606d3 100644 --- a/src/coreclr/src/vm/class.cpp +++ b/src/coreclr/src/vm/class.cpp @@ -1169,6 +1169,12 @@ void ClassLoader::ValidateMethodsWithCovariantReturnTypes(MethodTable* pMT) if (!pMD->RequiresCovariantReturnTypeChecking() && !pParentMD->RequiresCovariantReturnTypeChecking()) continue; + // Locate the MethodTable defining the pParentMD. + while (pParentMT->GetCanonicalMethodTable() != pParentMD->GetMethodTable()) + { + pParentMT = pParentMT->GetParentMethodTable(); + } + SigTypeContext context1(pParentMT->GetInstantiation(), pMD->GetMethodInstantiation()); MetaSig methodSig1(pParentMD); TypeHandle hType1 = methodSig1.GetReturnProps().GetTypeHandleThrowing(pParentMD->GetModule(), &context1, ClassLoader::LoadTypesFlag::LoadTypes, CLASS_LOAD_EXACTPARENTS); diff --git a/src/tests/Regressions/coreclr/GitHub_45053/test45053.cs b/src/tests/Regressions/coreclr/GitHub_45053/test45053.cs new file mode 100644 index 00000000000000..1c093f6ee29248 --- /dev/null +++ b/src/tests/Regressions/coreclr/GitHub_45053/test45053.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; + +public abstract class T +{ + public abstract TR GetA(); +} + +// This abstract causes the error - not overriding the base method cause the runtime to crash +public abstract class TA : T { } + +// This works +// public abstract class TA : T +// { +// // Overriding in between fixes the problem +// public override A GetA() => new (); +// } + + // Overriden here, in the grandson +public class TB : TA +{ + public override B GetA() => new (); +} +public class A { } + +public class B : A { } + +class Program +{ + static int Main() + { + System.Console.WriteLine((new TB() as T).GetA().GetType().FullName); + + return 100; + } +} diff --git a/src/tests/Regressions/coreclr/GitHub_45053/test45053.csproj b/src/tests/Regressions/coreclr/GitHub_45053/test45053.csproj new file mode 100644 index 00000000000000..89a08fc082a41a --- /dev/null +++ b/src/tests/Regressions/coreclr/GitHub_45053/test45053.csproj @@ -0,0 +1,10 @@ + + + Exe + BuildAndRun + 1 + + + + +