Author: pcc Date: Wed Dec 13 13:53:04 2017 New Revision: 320638 URL: http://llvm.org/viewvc/llvm-project?rev=320638&view=rev Log: IRGen: When performing CFI checks, load vtable pointer from vbase when necessary.
Under the Microsoft ABI, it is possible for an object not to have a virtual table pointer of its own if all of its virtual functions were introduced by virtual bases. In that case, we need to load the vtable pointer from one of the virtual bases and perform the type check using its type. Differential Revision: https://reviews.llvm.org/D41036 Added: cfe/trunk/test/CodeGenCXX/cfi-ms-vbase-derived-cast.cpp cfe/trunk/test/CodeGenCXX/cfi-ms-vbase-nvcall.cpp Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h cfe/trunk/lib/CodeGen/CGClass.cpp cfe/trunk/lib/CodeGen/CGExprCXX.cpp cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=320638&r1=320637&r2=320638&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCXXABI.h (original) +++ cfe/trunk/lib/CodeGen/CGCXXABI.h Wed Dec 13 13:53:04 2017 @@ -582,6 +582,13 @@ public: /// Emit a single constructor/destructor with the given type from a C++ /// constructor Decl. virtual void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) = 0; + + /// Load a vtable from This, an object of polymorphic type RD, or from one of + /// its virtual bases if it does not have its own vtable. Returns the vtable + /// and the class from which the vtable was loaded. + virtual std::pair<llvm::Value *, const CXXRecordDecl *> + LoadVTablePtr(CodeGenFunction &CGF, Address This, + const CXXRecordDecl *RD) = 0; }; // Create an instance of a C++ ABI class: Modified: cfe/trunk/lib/CodeGen/CGClass.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=320638&r1=320637&r2=320638&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGClass.cpp (original) +++ cfe/trunk/lib/CodeGen/CGClass.cpp Wed Dec 13 13:53:04 2017 @@ -2627,8 +2627,9 @@ void CodeGenFunction::EmitVTablePtrCheck EmitBlock(CheckBlock); } - llvm::Value *VTable = - GetVTablePtr(Address(Derived, getPointerAlign()), Int8PtrTy, ClassDecl); + llvm::Value *VTable; + std::tie(VTable, ClassDecl) = CGM.getCXXABI().LoadVTablePtr( + *this, Address(Derived, getPointerAlign()), ClassDecl); EmitVTablePtrCheck(ClassDecl, VTable, TCK, Loc); Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=320638&r1=320637&r2=320638&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Wed Dec 13 13:53:04 2017 @@ -368,9 +368,11 @@ RValue CodeGenFunction::EmitCXXMemberOrO } else { if (SanOpts.has(SanitizerKind::CFINVCall) && MD->getParent()->isDynamicClass()) { - llvm::Value *VTable = GetVTablePtr(This, Int8PtrTy, MD->getParent()); - EmitVTablePtrCheckForCall(MD->getParent(), VTable, CFITCK_NVCall, - CE->getLocStart()); + llvm::Value *VTable; + const CXXRecordDecl *RD; + std::tie(VTable, RD) = + CGM.getCXXABI().LoadVTablePtr(*this, This, MD->getParent()); + EmitVTablePtrCheckForCall(RD, VTable, CFITCK_NVCall, CE->getLocStart()); } if (getLangOpts().AppleKext && MD->isVirtual() && HasQualifier) Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=320638&r1=320637&r2=320638&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Wed Dec 13 13:53:04 2017 @@ -389,6 +389,10 @@ public: void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override; + std::pair<llvm::Value *, const CXXRecordDecl *> + LoadVTablePtr(CodeGenFunction &CGF, Address This, + const CXXRecordDecl *RD) override; + private: bool hasAnyUnusedVirtualInlineFunction(const CXXRecordDecl *RD) const { const auto &VtableLayout = @@ -4041,3 +4045,9 @@ ItaniumCXXABI::emitTerminateForUnexpecte } return CGF.EmitNounwindRuntimeCall(CGF.CGM.getTerminateFn()); } + +std::pair<llvm::Value *, const CXXRecordDecl *> +ItaniumCXXABI::LoadVTablePtr(CodeGenFunction &CGF, Address This, + const CXXRecordDecl *RD) { + return {CGF.GetVTablePtr(This, CGM.Int8PtrTy, RD), RD}; +} Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=320638&r1=320637&r2=320638&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Wed Dec 13 13:53:04 2017 @@ -578,7 +578,7 @@ private: return GetVBaseOffsetFromVBPtr(CGF, Base, VBPOffset, VBTOffset, VBPtr); } - std::pair<Address, llvm::Value *> + std::tuple<Address, llvm::Value *, const CXXRecordDecl *> performBaseAdjustment(CodeGenFunction &CGF, Address Value, QualType SrcRecordTy); @@ -745,6 +745,10 @@ public: llvm::GlobalVariable *getThrowInfo(QualType T) override; + std::pair<llvm::Value *, const CXXRecordDecl *> + LoadVTablePtr(CodeGenFunction &CGF, Address This, + const CXXRecordDecl *RD) override; + private: typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy; typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalVariable *> VTablesMapTy; @@ -926,7 +930,7 @@ void MicrosoftCXXABI::emitBeginCatch(Cod /// We need to perform a generic polymorphic operation (like a typeid /// or a cast), which requires an object with a vfptr. Adjust the /// address to point to an object with a vfptr. -std::pair<Address, llvm::Value *> +std::tuple<Address, llvm::Value *, const CXXRecordDecl *> MicrosoftCXXABI::performBaseAdjustment(CodeGenFunction &CGF, Address Value, QualType SrcRecordTy) { Value = CGF.Builder.CreateBitCast(Value, CGF.Int8PtrTy); @@ -937,7 +941,8 @@ MicrosoftCXXABI::performBaseAdjustment(C // covers non-virtual base subobjects: a class with its own virtual // functions would be a candidate to be a primary base. if (Context.getASTRecordLayout(SrcDecl).hasExtendableVFPtr()) - return std::make_pair(Value, llvm::ConstantInt::get(CGF.Int32Ty, 0)); + return std::make_tuple(Value, llvm::ConstantInt::get(CGF.Int32Ty, 0), + SrcDecl); // Okay, one of the vbases must have a vfptr, or else this isn't // actually a polymorphic class. @@ -956,7 +961,7 @@ MicrosoftCXXABI::performBaseAdjustment(C llvm::Value *Ptr = CGF.Builder.CreateInBoundsGEP(Value.getPointer(), Offset); CharUnits VBaseAlign = CGF.CGM.getVBaseAlignment(Value.getAlignment(), SrcDecl, PolymorphicBase); - return std::make_pair(Address(Ptr, VBaseAlign), Offset); + return std::make_tuple(Address(Ptr, VBaseAlign), Offset, PolymorphicBase); } bool MicrosoftCXXABI::shouldTypeidBeNullChecked(bool IsDeref, @@ -987,7 +992,7 @@ llvm::Value *MicrosoftCXXABI::EmitTypeid QualType SrcRecordTy, Address ThisPtr, llvm::Type *StdTypeInfoPtrTy) { - std::tie(ThisPtr, std::ignore) = + std::tie(ThisPtr, std::ignore, std::ignore) = performBaseAdjustment(CGF, ThisPtr, SrcRecordTy); auto Typeid = emitRTtypeidCall(CGF, ThisPtr.getPointer()).getInstruction(); return CGF.Builder.CreateBitCast(Typeid, StdTypeInfoPtrTy); @@ -1011,7 +1016,8 @@ llvm::Value *MicrosoftCXXABI::EmitDynami CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType()); llvm::Value *Offset; - std::tie(This, Offset) = performBaseAdjustment(CGF, This, SrcRecordTy); + std::tie(This, Offset, std::ignore) = + performBaseAdjustment(CGF, This, SrcRecordTy); llvm::Value *ThisPtr = This.getPointer(); Offset = CGF.Builder.CreateTrunc(Offset, CGF.Int32Ty); @@ -1037,7 +1043,8 @@ llvm::Value * MicrosoftCXXABI::EmitDynamicCastToVoid(CodeGenFunction &CGF, Address Value, QualType SrcRecordTy, QualType DestTy) { - std::tie(Value, std::ignore) = performBaseAdjustment(CGF, Value, SrcRecordTy); + std::tie(Value, std::ignore, std::ignore) = + performBaseAdjustment(CGF, Value, SrcRecordTy); // PVOID __RTCastToVoid( // PVOID inptr) @@ -4244,3 +4251,11 @@ void MicrosoftCXXABI::emitThrow(CodeGenF }; CGF.EmitNoreturnRuntimeCallOrInvoke(getThrowFn(), Args); } + +std::pair<llvm::Value *, const CXXRecordDecl *> +MicrosoftCXXABI::LoadVTablePtr(CodeGenFunction &CGF, Address This, + const CXXRecordDecl *RD) { + std::tie(This, std::ignore, RD) = + performBaseAdjustment(CGF, This, QualType(RD->getTypeForDecl(), 0)); + return {CGF.GetVTablePtr(This, CGM.Int8PtrTy, RD), RD}; +} Added: cfe/trunk/test/CodeGenCXX/cfi-ms-vbase-derived-cast.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cfi-ms-vbase-derived-cast.cpp?rev=320638&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/cfi-ms-vbase-derived-cast.cpp (added) +++ cfe/trunk/test/CodeGenCXX/cfi-ms-vbase-derived-cast.cpp Wed Dec 13 13:53:04 2017 @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -flto -flto-unit -emit-llvm -o - -triple=x86_64-pc-win32 %s -fsanitize=cfi-derived-cast -fsanitize-trap=cfi-derived-cast | FileCheck %s + +struct foo { + virtual ~foo() {} + virtual void f() = 0; +}; + +template <typename T> +struct bar : virtual public foo { + void f() { + // CHECK: define{{.*}}@"\01?f@?$bar@Ubaz@@@@UEAAXXZ" + // Load "this", vbtable, vbase offset and vtable. + // CHECK: load + // CHECK: load + // CHECK: load + // CHECK: load + // CHECK: @llvm.type.test{{.*}}!"?AUfoo@@" + static_cast<T&>(*this); + } +}; + +struct baz : public bar<baz> { + virtual ~baz() {} +}; + +int main() { + baz *z = new baz; + z->f(); +} Added: cfe/trunk/test/CodeGenCXX/cfi-ms-vbase-nvcall.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cfi-ms-vbase-nvcall.cpp?rev=320638&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/cfi-ms-vbase-nvcall.cpp (added) +++ cfe/trunk/test/CodeGenCXX/cfi-ms-vbase-nvcall.cpp Wed Dec 13 13:53:04 2017 @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -flto -flto-unit -emit-llvm -o - -triple=x86_64-pc-win32 %s -fsanitize=cfi-nvcall -fsanitize-trap=cfi-nvcall | FileCheck %s + +struct foo { + virtual ~foo() {} + virtual void f() = 0; +}; + +template <typename T> +struct bar : virtual public foo { + void f() {} +}; + +struct baz : public bar<baz> { + virtual ~baz() {} + void g() {} +}; + +void f(baz *z) { + // CHECK: define{{.*}}@"\01?f@@YAXPEAUbaz@@@Z" + // Load z, vbtable, vbase offset and vtable. + // CHECK: load + // CHECK: load + // CHECK: load + // CHECK: load + // CHECK: @llvm.type.test{{.*}}!"?AUfoo@@" + z->g(); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits