From dfcc8c61baefc95098070edfe5e9f4683edb86a5 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Thu, 9 Jul 2015 19:56:14 +0000 Subject: [PATCH] CFI: Emit correct bit set information if RTTI is disabled under MS ABI. We were previously creating bit set entries at virtual table offset sizeof(void*) unconditionally under the Microsoft C++ ABI. This is incorrect if RTTI data is disabled; in that case the "address point" is at offset 0. This change modifies bit set emission to take into account whether RTTI data is being emitted. Also make a start on a blacklisting scheme for records. Differential Revision: http://reviews.llvm.org/D11048 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@241845 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGClass.cpp | 3 +-- lib/CodeGen/CGVTables.cpp | 8 ++++++-- lib/CodeGen/CodeGenModule.h | 4 ++++ lib/CodeGen/MicrosoftCXXABI.cpp | 30 +++++++++++++++++++----------- test/CodeGenCXX/cfi-ms-rtti.cpp | 12 ++++++++++++ 5 files changed, 42 insertions(+), 15 deletions(-) create mode 100644 test/CodeGenCXX/cfi-ms-rtti.cpp diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 145a0e6754..f2feb8b21c 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -2207,8 +2207,7 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD, llvm::Value *VTable, CFITypeCheckKind TCK, SourceLocation Loc) { - // FIXME: Add blacklisting scheme. - if (RD->isInStdNamespace()) + if (CGM.IsCFIBlacklistedRecord(RD)) return; SanitizerScope SanScope(this); diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index 969629fb58..6493062894 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -841,6 +841,11 @@ void CodeGenModule::EmitDeferredVTables() { DeferredVTables.clear(); } +bool CodeGenModule::IsCFIBlacklistedRecord(const CXXRecordDecl *RD) { + // FIXME: Make this user configurable. + return RD->isInStdNamespace(); +} + void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable, const VTableLayout &VTLayout) { if (!LangOpts.Sanitize.has(SanitizerKind::CFIVCall) && @@ -855,8 +860,7 @@ void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable, std::vector BitsetEntries; // Create a bit set entry for each address point. for (auto &&AP : VTLayout.getAddressPoints()) { - // FIXME: Add blacklisting scheme. - if (AP.first.getBase()->isInStdNamespace()) + if (IsCFIBlacklistedRecord(AP.first.getBase())) continue; BitsetEntries.push_back(CreateVTableBitSetEntry( diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 9a295feaff..dd167a29f5 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -1126,6 +1126,10 @@ public: /// \param D Threadprivate declaration. void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D); + /// Returns whether the given record is blacklisted from control flow + /// integrity checks. + bool IsCFIBlacklistedRecord(const CXXRecordDecl *RD); + /// Emit bit set entries for the given vtable using the given layout if /// vptr CFI is enabled. void EmitVTableBitSetEntries(llvm::GlobalVariable *VTable, diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index 8d8f70f199..3433990e12 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1466,20 +1466,27 @@ void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info, llvm::NamedMDNode *BitsetsMD = CGM.getModule().getOrInsertNamedMetadata("llvm.bitsets"); - CharUnits PointerWidth = getContext().toCharUnitsFromBits( - getContext().getTargetInfo().getPointerWidth(0)); - // FIXME: Add blacklisting scheme. + // The location of the first virtual function pointer in the virtual table, + // aka the "address point" on Itanium. This is at offset 0 if RTTI is + // disabled, or sizeof(void*) if RTTI is enabled. + CharUnits AddressPoint = + getContext().getLangOpts().RTTIData + ? getContext().toCharUnitsFromBits( + getContext().getTargetInfo().getPointerWidth(0)) + : CharUnits::Zero(); if (Info->PathToBaseWithVPtr.empty()) { - BitsetsMD->addOperand( - CGM.CreateVTableBitSetEntry(VTable, PointerWidth, RD)); + if (!CGM.IsCFIBlacklistedRecord(RD)) + BitsetsMD->addOperand( + CGM.CreateVTableBitSetEntry(VTable, AddressPoint, RD)); return; } // Add a bitset entry for the least derived base belonging to this vftable. - BitsetsMD->addOperand(CGM.CreateVTableBitSetEntry( - VTable, PointerWidth, Info->PathToBaseWithVPtr.back())); + if (!CGM.IsCFIBlacklistedRecord(Info->PathToBaseWithVPtr.back())) + BitsetsMD->addOperand(CGM.CreateVTableBitSetEntry( + VTable, AddressPoint, Info->PathToBaseWithVPtr.back())); // Add a bitset entry for each derived class that is laid out at the same // offset as the least derived base. @@ -1497,14 +1504,15 @@ void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info, Offset = VBI->second.VBaseOffset; if (!Offset.isZero()) return; - BitsetsMD->addOperand( - CGM.CreateVTableBitSetEntry(VTable, PointerWidth, DerivedRD)); + if (!CGM.IsCFIBlacklistedRecord(DerivedRD)) + BitsetsMD->addOperand( + CGM.CreateVTableBitSetEntry(VTable, AddressPoint, DerivedRD)); } // Finally do the same for the most derived class. - if (Info->FullOffsetInMDC.isZero()) + if (Info->FullOffsetInMDC.isZero() && !CGM.IsCFIBlacklistedRecord(RD)) BitsetsMD->addOperand( - CGM.CreateVTableBitSetEntry(VTable, PointerWidth, RD)); + CGM.CreateVTableBitSetEntry(VTable, AddressPoint, RD)); } void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, diff --git a/test/CodeGenCXX/cfi-ms-rtti.cpp b/test/CodeGenCXX/cfi-ms-rtti.cpp new file mode 100644 index 0000000000..5203a6bb0c --- /dev/null +++ b/test/CodeGenCXX/cfi-ms-rtti.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm -o - -triple=x86_64-pc-win32 %s -fsanitize=cfi-vcall | FileCheck --check-prefix=RTTI %s +// RUN: %clang_cc1 -emit-llvm -o - -triple=x86_64-pc-win32 %s -fsanitize=cfi-vcall -fno-rtti-data | FileCheck --check-prefix=NO-RTTI %s + +struct A { + A(); + virtual void f() {} +}; + +A::A() {} + +// RTTI: !{!"A@@", [2 x i8*]* {{.*}}, i64 8} +// NO-RTTI: !{!"A@@", [1 x i8*]* {{.*}}, i64 0} -- 2.40.0