Skip to content

[SIL] Verify that the method referenced in {Class,Super}MethodInsts appears in the class vtable. #19025

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

Merged
merged 1 commit into from
Aug 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 additions & 1 deletion lib/SIL/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILOpenedArchetypesTracker.h"
#include "swift/SIL/SILVTable.h"
#include "swift/SIL/SILVTableVisitor.h"
#include "swift/SIL/SILVisitor.h"
#include "swift/SIL/BasicBlockUtils.h"
#include "swift/SIL/TypeLowering.h"
Expand Down Expand Up @@ -2554,7 +2555,56 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
F.getASTContext());
return SILType::getPrimitiveObjectType(fnTy);
}


/// Visitor class that checks whether a given decl ref has an entry in the
/// class's vtable.
class VerifyClassMethodVisitor
: public SILVTableVisitor<VerifyClassMethodVisitor>
{
public:
SILDeclRef MethodToSee;
bool Seen = false;

VerifyClassMethodVisitor(ClassDecl *theClass,
SILDeclRef method)
: MethodToSee(method)
{
addVTableEntries(theClass);
}

bool methodMatches(SILDeclRef method) {
auto methodToCheck = MethodToSee;
do {
if (method == methodToCheck) {
return true;
}
} while ((methodToCheck = methodToCheck.getNextOverriddenVTableEntry()));

return false;
}

void addMethod(SILDeclRef method) {
if (Seen)
return;
if (methodMatches(method))
Seen = true;
}

void addMethodOverride(SILDeclRef base, SILDeclRef derived) {
if (Seen)
return;
// The derived method should already have been checked.
// Test against the overridden base.
if (methodMatches(base))
Seen = true;
}


void addPlaceholder(MissingMemberDecl *) {
/* no-op */
}
};

void checkClassMethodInst(ClassMethodInst *CMI) {
auto member = CMI->getMember();
auto overrideTy = TC.getConstantOverrideType(member);
Expand All @@ -2577,6 +2627,13 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
"foreign method cannot be dispatched natively");
require(!isa<ExtensionDecl>(member.getDecl()->getDeclContext()),
"extension method cannot be dispatched natively");

// The method ought to appear in the class vtable.
require(VerifyClassMethodVisitor(
operandType.getASTType()->getMetatypeInstanceType()
->getClassOrBoundGenericClass(),
member).Seen,
"method does not appear in the class's vtable");
}

void checkSuperMethodInst(SuperMethodInst *CMI) {
Expand Down Expand Up @@ -2607,6 +2664,13 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {

require(methodClass->getClassOrBoundGenericClass(),
"super_method must look up a class method");

// The method ought to appear in the class vtable.
require(VerifyClassMethodVisitor(
operandType.getASTType()->getMetatypeInstanceType()
->getClassOrBoundGenericClass(),
member).Seen,
"method does not appear in the class's vtable");
}

void checkObjCMethodInst(ObjCMethodInst *OMI) {
Expand Down
4 changes: 3 additions & 1 deletion test/SIL/Parser/undef.sil
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ class C {
@objc func fn() { }
}

class D : C, P, ClassP { }
class D : C, P, ClassP {
override func fn() { }
}

struct S {
let x : ()
Expand Down
2 changes: 1 addition & 1 deletion test/SIL/ownership-verifier/use_verifier.sil
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ struct TupleContainingNonTrivialStruct {

class SuperKlass {
func d() {}
static func f() {}
class func f() {}
}
class SubKlass : SuperKlass {}
class X {
Expand Down