From fd360ff58a8a6902a601af60e2208fbcfc2ac0ca Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Wed, 12 May 2021 15:56:44 -0700 Subject: [PATCH] Fix issue where variance checking uses an unsafe contract by being more strict in what we accept while verifying the type --- src/coreclr/vm/methodtable.cpp | 24 +++++++++++++++++++----- src/coreclr/vm/methodtable.h | 2 +- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index d39cc37f4ebb49..1d9a614a2cd293 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -9189,7 +9189,7 @@ MethodDesc *MethodTable::GetDefaultConstructor(BOOL forceBoxedEntryPoint /* = FA //========================================================================================== // Finds the (non-unboxing) MethodDesc that implements the interface virtual static method pInterfaceMD. MethodDesc * -MethodTable::ResolveVirtualStaticMethod(MethodTable* pInterfaceType, MethodDesc* pInterfaceMD, BOOL allowNullResult, BOOL checkDuplicates) +MethodTable::ResolveVirtualStaticMethod(MethodTable* pInterfaceType, MethodDesc* pInterfaceMD, BOOL allowNullResult, BOOL checkDuplicates, BOOL allowVariantMatches) { if (!pInterfaceMD->IsSharedByGenericMethodInstantiations() && !pInterfaceType->IsSharedByGenericInstantiations()) { @@ -9225,7 +9225,7 @@ MethodTable::ResolveVirtualStaticMethod(MethodTable* pInterfaceType, MethodDesc* return pMD; } - if (pInterfaceType->HasVariance()) + if (pInterfaceType->HasVariance() || pInterfaceType->HasTypeEquivalence()) { // Variant interface dispatch MethodTable::InterfaceMapIterator it = IterateInterfaceMap(); @@ -9240,12 +9240,26 @@ MethodTable::ResolveVirtualStaticMethod(MethodTable* pInterfaceType, MethodDesc* if (!it.GetInterface()->HasSameTypeDefAs(pInterfaceType)) { // Variance matches require a typedef match + // Equivalence isn't sufficient, and is uninteresting as equivalent interfaces cannot have static virtuals. continue; } - if (it.GetInterface()->CanCastTo(pInterfaceType, NULL)) + BOOL equivalentOrVariantCompatible; + + if (allowVariantMatches) + { + equivalentOrVariantCompatible = it.GetInterface()->CanCastTo(pInterfaceType, NULL); + } + else + { + // When performing override checking to ensure that a concrete type is valid, require the implementation + // actually implement the exact or equivalent interface. + equivalentOrVariantCompatible = it.GetInterface()->IsEquivalentTo(pInterfaceType, NULL); + } + + if (equivalentOrVariantCompatible) { - // Variant matching interface found + // Variant or equivalent matching interface found // Attempt to resolve on variance matched interface pMD = pMT->TryResolveVirtualStaticMethodOnThisType(it.GetInterface(), pInterfaceMD, checkDuplicates); if (pMD != nullptr) @@ -9406,7 +9420,7 @@ MethodTable::VerifyThatAllVirtualStaticMethodsAreImplemented() MethodDesc *pMD = it.GetMethodDesc(); if (pMD->IsVirtual() && pMD->IsStatic() && - !ResolveVirtualStaticMethod(pInterfaceMT, pMD, /* allowNullResult */ TRUE, /* checkDuplicates */ TRUE)) + !ResolveVirtualStaticMethod(pInterfaceMT, pMD, /* allowNullResult */ TRUE, /* checkDuplicates */ TRUE, /* allowVariantMatches */ FALSE)) { IMDInternalImport* pInternalImport = GetModule()->GetMDImport(); GetModule()->GetAssembly()->ThrowTypeLoadException(pInternalImport, GetCl(), pMD->GetName(), IDS_CLASSLOAD_STATICVIRTUAL_NOTIMPL); diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index b3d2aa48601079..e55fd35d5c96c2 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -2282,7 +2282,7 @@ class MethodTable // Resolve virtual static interface method pInterfaceMD on this type. - MethodDesc *ResolveVirtualStaticMethod(MethodTable* pInterfaceType, MethodDesc* pInterfaceMD, BOOL allowNullResult, BOOL checkDuplicates = FALSE); + MethodDesc *ResolveVirtualStaticMethod(MethodTable* pInterfaceType, MethodDesc* pInterfaceMD, BOOL allowNullResult, BOOL checkDuplicates = FALSE, BOOL allowVariantMatches = TRUE); // Try a partial resolve of the constraint call, up to generic code sharing. //