diff options
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/CGClass.cpp | 36 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 9 | ||||
-rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 16 | ||||
-rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 19 |
4 files changed, 69 insertions, 11 deletions
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index ba46541b02b..56e24840c82 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -2645,6 +2645,42 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD, {CastedVTable, ValidVtable}); } +bool CodeGenFunction::ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD) { + if (!CGM.getCodeGenOpts().WholeProgramVTables || + !SanOpts.has(SanitizerKind::CFIVCall) || + !CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIVCall) || + !CGM.HasHiddenLTOVisibility(RD)) + return false; + + std::string TypeName = RD->getQualifiedNameAsString(); + return !getContext().getSanitizerBlacklist().isBlacklistedType(TypeName); +} + +llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad( + const CXXRecordDecl *RD, llvm::Value *VTable, uint64_t VTableByteOffset) { + SanitizerScope SanScope(this); + + EmitSanitizerStatReport(llvm::SanStat_CFI_VCall); + + llvm::Metadata *MD = + CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0)); + llvm::Value *TypeId = llvm::MetadataAsValue::get(CGM.getLLVMContext(), MD); + + llvm::Value *CastedVTable = Builder.CreateBitCast(VTable, Int8PtrTy); + llvm::Value *CheckedLoad = Builder.CreateCall( + CGM.getIntrinsic(llvm::Intrinsic::type_checked_load), + {CastedVTable, llvm::ConstantInt::get(Int32Ty, VTableByteOffset), + TypeId}); + llvm::Value *CheckResult = Builder.CreateExtractValue(CheckedLoad, 1); + + EmitCheck(std::make_pair(CheckResult, SanitizerKind::CFIVCall), + "cfi_check_fail", nullptr, nullptr); + + return Builder.CreateBitCast( + Builder.CreateExtractValue(CheckedLoad, 0), + cast<llvm::PointerType>(VTable->getType())->getElementType()); +} + // FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do // quite what we want. static const Expr *skipNoOpCastsAndParens(const Expr *E) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 28ee621b31b..08051e880cb 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -1423,6 +1423,15 @@ public: void EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD, llvm::Value *VTable, SourceLocation Loc); + /// Returns whether we should perform a type checked load when loading a + /// virtual function for virtual calls to members of RD. This is generally + /// true when both vcall CFI and whole-program-vtables are enabled. + bool ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD); + + /// Emit a type checked load from the given vtable. + llvm::Value *EmitVTableTypeCheckedLoad(const CXXRecordDecl *RD, llvm::Value *VTable, + uint64_t VTableByteOffset); + /// CanDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given /// expr can be devirtualized. bool CanDevirtualizeMemberFunctionCall(const Expr *Base, diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 43d293a2c75..6051594fb00 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -1595,12 +1595,18 @@ llvm::Value *ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, auto *MethodDecl = cast<CXXMethodDecl>(GD.getDecl()); llvm::Value *VTable = CGF.GetVTablePtr(This, Ty, MethodDecl->getParent()); - CGF.EmitTypeMetadataCodeForVCall(MethodDecl->getParent(), VTable, Loc); - uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD); - llvm::Value *VFuncPtr = - CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn"); - return CGF.Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign()); + if (CGF.ShouldEmitVTableTypeCheckedLoad(MethodDecl->getParent())) { + return CGF.EmitVTableTypeCheckedLoad( + MethodDecl->getParent(), VTable, + VTableIndex * CGM.getContext().getTargetInfo().getPointerWidth(0) / 8); + } else { + CGF.EmitTypeMetadataCodeForVCall(MethodDecl->getParent(), VTable, Loc); + + llvm::Value *VFuncPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn"); + return CGF.Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign()); + } } llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall( diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index a48e084158d..31bfbf0cdfb 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1815,13 +1815,20 @@ llvm::Value *MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, MicrosoftVTableContext::MethodVFTableLocation ML = CGM.getMicrosoftVTableContext().getMethodVFTableLocation(GD); - if (CGM.getCodeGenOpts().PrepareForLTO) - CGF.EmitTypeMetadataCodeForVCall( - getClassAtVTableLocation(getContext(), GD, ML), VTable, Loc); - llvm::Value *VFuncPtr = - Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn"); - return Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign()); + if (CGF.ShouldEmitVTableTypeCheckedLoad(MethodDecl->getParent())) { + return CGF.EmitVTableTypeCheckedLoad( + getClassAtVTableLocation(getContext(), GD, ML), VTable, + ML.Index * CGM.getContext().getTargetInfo().getPointerWidth(0) / 8); + } else { + if (CGM.getCodeGenOpts().PrepareForLTO) + CGF.EmitTypeMetadataCodeForVCall( + getClassAtVTableLocation(getContext(), GD, ML), VTable, Loc); + + llvm::Value *VFuncPtr = + Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn"); + return Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign()); + } } llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall( |