summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/ItaniumCXXABI.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CodeGen/ItaniumCXXABI.cpp')
-rw-r--r--clang/lib/CodeGen/ItaniumCXXABI.cpp87
1 files changed, 82 insertions, 5 deletions
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index d855afab22e..8dd94e49556 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -622,13 +622,53 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
VTableOffset = Builder.CreateTrunc(VTableOffset, CGF.Int32Ty);
VTableOffset = Builder.CreateZExt(VTableOffset, CGM.PtrDiffTy);
}
- VTable = Builder.CreateGEP(VTable, VTableOffset);
+ // Compute the address of the virtual function pointer.
+ llvm::Value *VFPAddr = Builder.CreateGEP(VTable, VTableOffset);
+
+ // Check the address of the function pointer if CFI on member function
+ // pointers is enabled.
+ llvm::Constant *CheckSourceLocation;
+ llvm::Constant *CheckTypeDesc;
+ bool ShouldEmitCFICheck = CGF.SanOpts.has(SanitizerKind::CFIMFCall) &&
+ CGM.HasHiddenLTOVisibility(RD);
+ if (ShouldEmitCFICheck) {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
+
+ CheckSourceLocation = CGF.EmitCheckSourceLocation(E->getLocStart());
+ CheckTypeDesc = CGF.EmitCheckTypeDescriptor(QualType(MPT, 0));
+ llvm::Constant *StaticData[] = {
+ llvm::ConstantInt::get(CGF.Int8Ty, CodeGenFunction::CFITCK_VMFCall),
+ CheckSourceLocation,
+ CheckTypeDesc,
+ };
+
+ llvm::Metadata *MD =
+ CGM.CreateMetadataIdentifierForVirtualMemPtrType(QualType(MPT, 0));
+ llvm::Value *TypeId = llvm::MetadataAsValue::get(CGF.getLLVMContext(), MD);
+
+ llvm::Value *TypeTest = Builder.CreateCall(
+ CGM.getIntrinsic(llvm::Intrinsic::type_test), {VFPAddr, TypeId});
+
+ if (CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIMFCall)) {
+ CGF.EmitTrapCheck(TypeTest);
+ } else {
+ llvm::Value *AllVtables = llvm::MetadataAsValue::get(
+ CGM.getLLVMContext(),
+ llvm::MDString::get(CGM.getLLVMContext(), "all-vtables"));
+ llvm::Value *ValidVtable = Builder.CreateCall(
+ CGM.getIntrinsic(llvm::Intrinsic::type_test), {VTable, AllVtables});
+ CGF.EmitCheck(std::make_pair(TypeTest, SanitizerKind::CFIMFCall),
+ SanitizerHandler::CFICheckFail, StaticData,
+ {VTable, ValidVtable});
+ }
+
+ FnVirtual = Builder.GetInsertBlock();
+ }
// Load the virtual function to call.
- VTable = Builder.CreateBitCast(VTable, FTy->getPointerTo()->getPointerTo());
- llvm::Value *VirtualFn =
- Builder.CreateAlignedLoad(VTable, CGF.getPointerAlign(),
- "memptr.virtualfn");
+ VFPAddr = Builder.CreateBitCast(VFPAddr, FTy->getPointerTo()->getPointerTo());
+ llvm::Value *VirtualFn = Builder.CreateAlignedLoad(
+ VFPAddr, CGF.getPointerAlign(), "memptr.virtualfn");
CGF.EmitBranch(FnEnd);
// In the non-virtual path, the function pointer is actually a
@@ -637,6 +677,43 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
llvm::Value *NonVirtualFn =
Builder.CreateIntToPtr(FnAsInt, FTy->getPointerTo(), "memptr.nonvirtualfn");
+ // Check the function pointer if CFI on member function pointers is enabled.
+ if (ShouldEmitCFICheck) {
+ CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+ if (RD->hasDefinition()) {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
+
+ llvm::Constant *StaticData[] = {
+ llvm::ConstantInt::get(CGF.Int8Ty, CodeGenFunction::CFITCK_NVMFCall),
+ CheckSourceLocation,
+ CheckTypeDesc,
+ };
+
+ llvm::Value *Bit = Builder.getFalse();
+ llvm::Value *CastedNonVirtualFn =
+ Builder.CreateBitCast(NonVirtualFn, CGF.Int8PtrTy);
+ for (const CXXRecordDecl *Base : CGM.getMostBaseClasses(RD)) {
+ llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(
+ getContext().getMemberPointerType(
+ MPT->getPointeeType(),
+ getContext().getRecordType(Base).getTypePtr()));
+ llvm::Value *TypeId =
+ llvm::MetadataAsValue::get(CGF.getLLVMContext(), MD);
+
+ llvm::Value *TypeTest =
+ Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::type_test),
+ {CastedNonVirtualFn, TypeId});
+ Bit = Builder.CreateOr(Bit, TypeTest);
+ }
+
+ CGF.EmitCheck(std::make_pair(Bit, SanitizerKind::CFIMFCall),
+ SanitizerHandler::CFICheckFail, StaticData,
+ {CastedNonVirtualFn, llvm::UndefValue::get(CGF.IntPtrTy)});
+
+ FnNonVirtual = Builder.GetInsertBlock();
+ }
+ }
+
// We're done.
CGF.EmitBlock(FnEnd);
llvm::PHINode *CalleePtr = Builder.CreatePHI(FTy->getPointerTo(), 2);
OpenPOWER on IntegriCloud