From 9b69ad2add9a7935253c9da4ab51366f8434b140 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Thu, 4 Feb 2021 13:25:21 +0100 Subject: [PATCH] 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/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/vm/class.cpp b/src/coreclr/vm/class.cpp index f39e1f23e96516..9665f1d9017d70 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/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 + + + + +