r230055 - Implement Control Flow Integrity for virtual calls.

Peter Collingbourne peter at pcc.me.uk
Fri Feb 20 12:30:56 PST 2015


Author: pcc
Date: Fri Feb 20 14:30:56 2015
New Revision: 230055

URL: http://llvm.org/viewvc/llvm-project?rev=230055&view=rev
Log:
Implement Control Flow Integrity for virtual calls.

This patch introduces the -fsanitize=cfi-vptr flag, which enables a control
flow integrity scheme that checks that virtual calls take place using a vptr of
the correct dynamic type. More details in the new docs/ControlFlowIntegrity.rst
file.

It also introduces the -fsanitize=cfi flag, which is currently a synonym for
-fsanitize=cfi-vptr, but will eventually cover all CFI checks implemented
in Clang.

Differential Revision: http://reviews.llvm.org/D7424

Added:
    cfe/trunk/docs/ControlFlowIntegrity.rst
    cfe/trunk/docs/ControlFlowIntegrityDesign.rst
    cfe/trunk/test/CodeGenCXX/cfi-vptr.cpp
Modified:
    cfe/trunk/docs/UsersManual.rst
    cfe/trunk/docs/index.rst
    cfe/trunk/include/clang/AST/Mangle.h
    cfe/trunk/include/clang/Basic/Sanitizers.def
    cfe/trunk/include/clang/Driver/Driver.h
    cfe/trunk/include/clang/Driver/SanitizerArgs.h
    cfe/trunk/lib/AST/ItaniumMangle.cpp
    cfe/trunk/lib/AST/MicrosoftMangle.cpp
    cfe/trunk/lib/CodeGen/CGClass.cpp
    cfe/trunk/lib/CodeGen/CGVTables.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/CodeGen/CodeGenModule.h
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/lib/Driver/Driver.cpp
    cfe/trunk/lib/Driver/SanitizerArgs.cpp
    cfe/trunk/lib/Driver/Tools.cpp
    cfe/trunk/test/Driver/fsanitize.c

Added: cfe/trunk/docs/ControlFlowIntegrity.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/ControlFlowIntegrity.rst?rev=230055&view=auto
==============================================================================
--- cfe/trunk/docs/ControlFlowIntegrity.rst (added)
+++ cfe/trunk/docs/ControlFlowIntegrity.rst Fri Feb 20 14:30:56 2015
@@ -0,0 +1,74 @@
+======================
+Control Flow Integrity
+======================
+
+.. toctree::
+   :hidden:
+
+   ControlFlowIntegrityDesign
+
+.. contents::
+   :local:
+
+Introduction
+============
+
+Clang includes an implementation of a number of control flow integrity (CFI)
+schemes, which are designed to abort the program upon detecting certain forms
+of undefined behavior that can potentially allow attackers to subvert the
+program's control flow. These schemes have been optimized for performance,
+allowing developers to enable them in release builds.
+
+To enable Clang's available CFI schemes, use the flag ``-fsanitize=cfi``.
+As currently implemented, CFI relies on link-time optimization (LTO); the CFI
+schemes imply ``-flto``, and the linker used must support LTO, for example
+via the `gold plugin`_. To allow the checks to be implemented efficiently,
+the program must be structured such that certain object files are compiled
+with CFI enabled, and are statically linked into the program. This may
+preclude the use of shared libraries in some cases.
+
+Clang currently implements forward-edge CFI for virtual calls. More schemes
+are under development.
+
+.. _gold plugin: http://llvm.org/docs/GoldPlugin.html
+
+Forward-Edge CFI for Virtual Calls
+----------------------------------
+
+This scheme checks that virtual calls take place using a vptr of the correct
+dynamic type; that is, the dynamic type of the called object must be a
+derived class of the static type of the object used to make the call.
+This CFI scheme can be enabled on its own using ``-fsanitize=cfi-vptr``.
+
+For this scheme to work, all translation units containing the definition
+of a virtual member function (whether inline or not) must be compiled
+with ``-fsanitize=cfi-vptr`` enabled and be statically linked into the
+program. Classes in the C++ standard library (under namespace ``std``) are
+exempted from checking, and therefore programs may be linked against a
+pre-built standard library, but this may change in the future.
+
+Performance
+~~~~~~~~~~~
+
+A performance overhead of less than 1% has been measured by running the
+Dromaeo benchmark suite against an instrumented version of the Chromium
+web browser. Another good performance benchmark for this mechanism is the
+virtual-call-heavy SPEC 2006 xalancbmk.
+
+Note that this scheme has not yet been optimized for binary size; an increase
+of up to 15% has been observed for Chromium.
+
+Design
+------
+
+Please refer to the :doc:`design document<ControlFlowIntegrityDesign>`.
+
+Publications
+------------
+
+`Control-Flow Integrity: Principles, Implementations, and Applications <http://research.microsoft.com/pubs/64250/ccs05.pdf>`_.
+Martin Abadi, Mihai Budiu, Úlfar Erlingsson, Jay Ligatti.
+
+`Enforcing Forward-Edge Control-Flow Integrity in GCC & LLVM <http://www.pcc.me.uk/~peter/acad/usenix14.pdf>`_.
+Caroline Tice, Tom Roeder, Peter Collingbourne, Stephen Checkoway,
+Úlfar Erlingsson, Luis Lozano, Geoff Pike.

Added: cfe/trunk/docs/ControlFlowIntegrityDesign.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/ControlFlowIntegrityDesign.rst?rev=230055&view=auto
==============================================================================
--- cfe/trunk/docs/ControlFlowIntegrityDesign.rst (added)
+++ cfe/trunk/docs/ControlFlowIntegrityDesign.rst Fri Feb 20 14:30:56 2015
@@ -0,0 +1,59 @@
+===========================================
+Control Flow Integrity Design Documentation
+===========================================
+
+This page documents the design of the :doc:`ControlFlowIntegrity` schemes
+supported by Clang.
+
+Forward-Edge CFI for Virtual Calls
+----------------------------------
+
+This scheme works by allocating, for each static type used to make a virtual
+call, a region of read-only storage in the object file holding a bit vector
+that maps onto to the region of storage used for those virtual tables. Each
+set bit in the bit vector corresponds to the `address point`_ for a virtual
+table compatible with the static type for which the bit vector is being built.
+
+For example, consider the following three C++ classes:
+
+.. code-block:: c++
+
+  struct A {
+    virtual void f();
+  };
+
+  struct B : A {
+    virtual void f();
+  };
+
+  struct C : A {
+    virtual void f();
+  };
+
+The scheme will cause the virtual tables for A, B and C to be laid out
+consecutively:
+
+.. csv-table:: Virtual Table Layout for A, B, C
+  :header: 0, 1, 2, 3, 4, 5, 6, 7, 8
+
+  A::offset-to-top, &A::rtti, &A::f, B::offset-to-top, &B::rtti, &B::f, C::offset-to-top, &C::rtti, &C::f
+
+The bit vector for static types A, B and C will look like this:
+
+.. csv-table:: Bit Vectors for A, B, C
+  :header: Class, 0, 1, 2, 3, 4, 5, 6, 7, 8
+
+  A, 0, 0, 1, 0, 0, 1, 0, 0, 1
+  B, 0, 0, 0, 0, 0, 1, 0, 0, 0
+  C, 0, 0, 0, 0, 0, 0, 0, 0, 1
+
+To emit a virtual call, the compiler will assemble code that checks that
+the object's virtual table pointer is in-bounds and aligned and that the
+relevant bit is set in the bit vector.
+
+The compiler relies on co-operation from the linker in order to assemble
+the bit vector for the whole program. It currently does this using LLVM's
+`bit sets`_ mechanism together with link-time optimization.
+
+.. _address point: https://mentorembedded.github.io/cxx-abi/abi.html#vtable-general
+.. _bit sets: http://llvm.org/docs/BitSets.html

Modified: cfe/trunk/docs/UsersManual.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/UsersManual.rst?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/docs/UsersManual.rst (original)
+++ cfe/trunk/docs/UsersManual.rst Fri Feb 20 14:30:56 2015
@@ -957,6 +957,8 @@ are listed below.
       ``unsigned-integer-overflow`` and ``vptr``.
    -  ``-fsanitize=dataflow``: :doc:`DataFlowSanitizer`, a general data
       flow analysis.
+   -  ``-fsanitize=cfi``: :doc:`control flow integrity <ControlFlowIntegrity>`
+      checks. Implies ``-flto``.
 
    The following more fine-grained checks are also available:
 
@@ -966,6 +968,8 @@ are listed below.
       ``true`` nor ``false``.
    -  ``-fsanitize=bounds``: Out of bounds array indexing, in cases
       where the array bound can be statically determined.
+   -  ``-fsanitize=cfi-vptr``: Use of an object whose vptr is of the
+      wrong dynamic type. Implies ``-flto``.
    -  ``-fsanitize=enum``: Load of a value of an enumerated type which
       is not in the range of representable values for that enumerated
       type.

Modified: cfe/trunk/docs/index.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/index.rst?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/docs/index.rst (original)
+++ cfe/trunk/docs/index.rst Fri Feb 20 14:30:56 2015
@@ -27,6 +27,7 @@ Using Clang as a Compiler
    DataFlowSanitizer
    LeakSanitizer
    SanitizerSpecialCaseList
+   ControlFlowIntegrity
    Modules
    MSVCCompatibility
    FAQ

Modified: cfe/trunk/include/clang/AST/Mangle.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Mangle.h?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Mangle.h (original)
+++ cfe/trunk/include/clang/AST/Mangle.h Fri Feb 20 14:30:56 2015
@@ -141,6 +141,9 @@ public:
   /// across translation units so it can be used with LTO.
   virtual void mangleTypeName(QualType T, raw_ostream &) = 0;
 
+  virtual void mangleCXXVTableBitSet(const CXXRecordDecl *RD,
+                                     raw_ostream &) = 0;
+
   /// @}
 };
 

Modified: cfe/trunk/include/clang/Basic/Sanitizers.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Sanitizers.def?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Sanitizers.def (original)
+++ cfe/trunk/include/clang/Basic/Sanitizers.def Fri Feb 20 14:30:56 2015
@@ -76,6 +76,10 @@ SANITIZER("unsigned-integer-overflow", U
 // DataFlowSanitizer
 SANITIZER("dataflow", DataFlow)
 
+// Control Flow Integrity
+SANITIZER("cfi-vptr", CFIVptr)
+SANITIZER_GROUP("cfi", CFI, CFIVptr)
+
 // -fsanitize=undefined includes all the sanitizers which have low overhead, no
 // ABI or address space layout implications, and only catch undefined behavior.
 SANITIZER_GROUP("undefined", Undefined,

Modified: cfe/trunk/include/clang/Driver/Driver.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Driver.h?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/Driver.h (original)
+++ cfe/trunk/include/clang/Driver/Driver.h Fri Feb 20 14:30:56 2015
@@ -357,8 +357,8 @@ public:
   /// \p Phase on the \p Input, taking in to account arguments
   /// like -fsyntax-only or --analyze.
   std::unique_ptr<Action>
-  ConstructPhaseAction(const llvm::opt::ArgList &Args, phases::ID Phase,
-                       std::unique_ptr<Action> Input) const;
+  ConstructPhaseAction(const ToolChain &TC, const llvm::opt::ArgList &Args,
+                       phases::ID Phase, std::unique_ptr<Action> Input) const;
 
   /// BuildJobsForAction - Construct the jobs to perform for the
   /// action \p A.
@@ -402,7 +402,7 @@ public:
   /// handle this action.
   bool ShouldUseClangCompiler(const JobAction &JA) const;
 
-  bool IsUsingLTO(const llvm::opt::ArgList &Args) const;
+  bool IsUsingLTO(const ToolChain &TC, const llvm::opt::ArgList &Args) const;
 
 private:
   /// \brief Retrieves a ToolChain for a particular target triple.

Modified: cfe/trunk/include/clang/Driver/SanitizerArgs.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/SanitizerArgs.h?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/SanitizerArgs.h (original)
+++ cfe/trunk/include/clang/Driver/SanitizerArgs.h Fri Feb 20 14:30:56 2015
@@ -51,6 +51,7 @@ class SanitizerArgs {
 
   bool requiresPIE() const;
   bool needsUnwindTables() const;
+  bool needsLTO() const;
   bool linkCXXRuntimes() const { return LinkCXXRuntimes; }
   void addArgs(const llvm::opt::ArgList &Args,
                llvm::opt::ArgStringList &CmdArgs) const;

Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Fri Feb 20 14:30:56 2015
@@ -172,6 +172,8 @@ public:
 
   void mangleStringLiteral(const StringLiteral *, raw_ostream &) override;
 
+  void mangleCXXVTableBitSet(const CXXRecordDecl *RD, raw_ostream &) override;
+
   bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
     // Lambda closure types are already numbered.
     if (isLambda(ND))
@@ -4040,6 +4042,22 @@ void ItaniumMangleContextImpl::mangleTyp
   mangleCXXRTTIName(Ty, Out);
 }
 
+void ItaniumMangleContextImpl::mangleCXXVTableBitSet(const CXXRecordDecl *RD,
+                                                     raw_ostream &Out) {
+  Linkage L = RD->getLinkageInternal();
+  if (L == InternalLinkage || L == UniqueExternalLinkage) {
+    // This part of the identifier needs to be unique across all translation
+    // units in the linked program. The scheme fails if multiple translation
+    // units are compiled using the same relative source file path, or if
+    // multiple translation units are built from the same source file.
+    SourceManager &SM = getASTContext().getSourceManager();
+    Out << "[" << SM.getFileEntryForID(SM.getMainFileID())->getName() << "]";
+  }
+
+  CXXNameMangler Mangler(*this, Out);
+  Mangler.mangleType(QualType(RD->getTypeForDecl(), 0));
+}
+
 void ItaniumMangleContextImpl::mangleStringLiteral(const StringLiteral *, raw_ostream &) {
   llvm_unreachable("Can't mangle string literals");
 }

Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Fri Feb 20 14:30:56 2015
@@ -138,6 +138,8 @@ public:
   void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
                                  raw_ostream &Out) override;
   void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;
+  void mangleCXXVTableBitSet(const CXXRecordDecl *RD,
+                             raw_ostream &Out) override;
   bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
     // Lambda closure types are already numbered.
     if (isLambda(ND))
@@ -2567,6 +2569,11 @@ void MicrosoftMangleContextImpl::mangleS
   Mangler.getStream() << '@';
 }
 
+void MicrosoftMangleContextImpl::mangleCXXVTableBitSet(const CXXRecordDecl *RD,
+                                                       raw_ostream &Out) {
+  llvm::report_fatal_error("Cannot mangle bitsets yet");
+}
+
 MicrosoftMangleContext *
 MicrosoftMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
   return new MicrosoftMangleContextImpl(Context, Diags);

Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Fri Feb 20 14:30:56 2015
@@ -24,6 +24,7 @@
 #include "clang/Basic/TargetBuiltins.h"
 #include "clang/CodeGen/CGFunctionInfo.h"
 #include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/IR/Intrinsics.h"
 
 using namespace clang;
 using namespace CodeGen;
@@ -2087,6 +2088,38 @@ llvm::Value *CodeGenFunction::GetVTableP
   return VTable;
 }
 
+void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXMethodDecl *MD,
+                                                llvm::Value *VTable) {
+  if (!SanOpts.has(SanitizerKind::CFIVptr))
+    return;
+
+  const CXXRecordDecl *RD = MD->getParent();
+  // FIXME: Add blacklisting scheme.
+  if (RD->isInStdNamespace())
+    return;
+
+  std::string OutName;
+  llvm::raw_string_ostream Out(OutName);
+  CGM.getCXXABI().getMangleContext().mangleCXXVTableBitSet(RD, Out);
+
+  llvm::Value *BitSetName = llvm::MetadataAsValue::get(
+      getLLVMContext(), llvm::MDString::get(getLLVMContext(), Out.str()));
+
+  llvm::Value *BitSetTest = Builder.CreateCall2(
+      CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
+      Builder.CreateBitCast(VTable, CGM.Int8PtrTy), BitSetName);
+
+  llvm::BasicBlock *ContBlock = createBasicBlock("vtable.check.cont");
+  llvm::BasicBlock *TrapBlock = createBasicBlock("vtable.check.trap");
+
+  Builder.CreateCondBr(BitSetTest, ContBlock, TrapBlock);
+
+  EmitBlock(TrapBlock);
+  Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::trap));
+  Builder.CreateUnreachable();
+
+  EmitBlock(ContBlock);
+}
 
 // FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do
 // quite what we want.

Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVTables.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGVTables.cpp Fri Feb 20 14:30:56 2015
@@ -669,6 +669,8 @@ CodeGenVTables::GenerateConstructionVTab
       VTLayout->getNumVTableThunks(), RTTI);
   VTable->setInitializer(Init);
   
+  CGM.EmitVTableBitSetEntries(VTable, *VTLayout.get());
+
   return VTable;
 }
 
@@ -837,3 +839,62 @@ void CodeGenModule::EmitDeferredVTables(
          "deferred extra v-tables during v-table emission?");
   DeferredVTables.clear();
 }
+
+void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
+                                            const VTableLayout &VTLayout) {
+  if (!LangOpts.Sanitize.has(SanitizerKind::CFIVptr))
+    return;
+
+  llvm::Metadata *VTableMD = llvm::ConstantAsMetadata::get(VTable);
+
+  std::vector<llvm::MDTuple *> BitsetEntries;
+  // Create a bit set entry for each address point.
+  for (auto &&AP : VTLayout.getAddressPoints()) {
+    // FIXME: Add blacklisting scheme.
+    if (AP.first.getBase()->isInStdNamespace())
+      continue;
+
+    std::string OutName;
+    llvm::raw_string_ostream Out(OutName);
+    getCXXABI().getMangleContext().mangleCXXVTableBitSet(AP.first.getBase(),
+                                                         Out);
+
+    CharUnits PointerWidth =
+        Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+    uint64_t AddrPointOffset = AP.second * PointerWidth.getQuantity();
+
+    llvm::Metadata *BitsetOps[] = {
+        llvm::MDString::get(getLLVMContext(), Out.str()),
+        VTableMD,
+        llvm::ConstantAsMetadata::get(
+            llvm::ConstantInt::get(Int64Ty, AddrPointOffset))};
+    llvm::MDTuple *BitsetEntry =
+        llvm::MDTuple::get(getLLVMContext(), BitsetOps);
+    BitsetEntries.push_back(BitsetEntry);
+  }
+
+  // Sort the bit set entries for determinism.
+  std::sort(BitsetEntries.begin(), BitsetEntries.end(), [](llvm::MDTuple *T1,
+                                                           llvm::MDTuple *T2) {
+    StringRef S1 = cast<llvm::MDString>(T1->getOperand(0))->getString();
+    StringRef S2 = cast<llvm::MDString>(T2->getOperand(0))->getString();
+    if (S1 < S2)
+      return true;
+    if (S1 != S2)
+      return false;
+
+    uint64_t Offset1 = cast<llvm::ConstantInt>(
+                           cast<llvm::ConstantAsMetadata>(T1->getOperand(2))
+                               ->getValue())->getZExtValue();
+    uint64_t Offset2 = cast<llvm::ConstantInt>(
+                           cast<llvm::ConstantAsMetadata>(T2->getOperand(2))
+                               ->getValue())->getZExtValue();
+    assert(Offset1 != Offset2);
+    return Offset1 < Offset2;
+  });
+
+  llvm::NamedMDNode *BitsetsMD =
+      getModule().getOrInsertNamedMetadata("llvm.bitsets");
+  for (auto BitsetEntry : BitsetEntries)
+    BitsetsMD->addOperand(BitsetEntry);
+}

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Fri Feb 20 14:30:56 2015
@@ -1346,6 +1346,9 @@ public:
   /// to by This.
   llvm::Value *GetVTablePtr(llvm::Value *This, llvm::Type *Ty);
 
+  /// EmitVTablePtrCheckForCall - Virtual method MD is being called via VTable.
+  /// If vptr CFI is enabled, emit a check that VTable is valid.
+  void EmitVTablePtrCheckForCall(const CXXMethodDecl *MD, llvm::Value *VTable);
 
   /// CanDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
   /// expr can be devirtualized.

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Fri Feb 20 14:30:56 2015
@@ -1103,6 +1103,11 @@ public:
   /// \param D Threadprivate declaration.
   void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D);
 
+  /// Emit bit set entries for the given vtable using the given layout if
+  /// vptr CFI is enabled.
+  void EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
+                               const VTableLayout &VTLayout);
+
 private:
   llvm::Constant *
   GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D,

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Fri Feb 20 14:30:56 2015
@@ -1281,6 +1281,8 @@ void ItaniumCXXABI::emitVTableDefinition
       cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__cxxabiv1") &&
       DC->getParent()->isTranslationUnit())
     EmitFundamentalRTTIDescriptors();
+
+  CGM.EmitVTableBitSetEntries(VTable, VTLayout);
 }
 
 llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructor(
@@ -1372,6 +1374,8 @@ llvm::Value *ItaniumCXXABI::getVirtualFu
   Ty = Ty->getPointerTo()->getPointerTo();
   llvm::Value *VTable = CGF.GetVTablePtr(This, Ty);
 
+  CGF.EmitVTablePtrCheckForCall(cast<CXXMethodDecl>(GD.getDecl()), VTable);
+
   uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
   llvm::Value *VFuncPtr =
       CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn");

Modified: cfe/trunk/lib/Driver/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Driver.cpp?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Driver.cpp (original)
+++ cfe/trunk/lib/Driver/Driver.cpp Fri Feb 20 14:30:56 2015
@@ -17,6 +17,7 @@
 #include "clang/Driver/DriverDiagnostic.h"
 #include "clang/Driver/Job.h"
 #include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
 #include "clang/Driver/Tool.h"
 #include "clang/Driver/ToolChain.h"
 #include "llvm/ADT/ArrayRef.h"
@@ -1269,7 +1270,7 @@ void Driver::BuildActions(const ToolChai
         continue;
 
       // Otherwise construct the appropriate action.
-      Current = ConstructPhaseAction(Args, Phase, std::move(Current));
+      Current = ConstructPhaseAction(TC, Args, Phase, std::move(Current));
       if (Current->getType() == types::TY_Nothing)
         break;
     }
@@ -1295,7 +1296,8 @@ void Driver::BuildActions(const ToolChai
 }
 
 std::unique_ptr<Action>
-Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
+Driver::ConstructPhaseAction(const ToolChain &TC, const ArgList &Args,
+                             phases::ID Phase,
                              std::unique_ptr<Action> Input) const {
   llvm::PrettyStackTraceString CrashInfo("Constructing phase actions");
   // Build the appropriate action.
@@ -1354,7 +1356,7 @@ Driver::ConstructPhaseAction(const ArgLi
                                                types::TY_LLVM_BC);
   }
   case phases::Backend: {
-    if (IsUsingLTO(Args)) {
+    if (IsUsingLTO(TC, Args)) {
       types::ID Output =
         Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC;
       return llvm::make_unique<BackendJobAction>(std::move(Input), Output);
@@ -1375,7 +1377,10 @@ Driver::ConstructPhaseAction(const ArgLi
   llvm_unreachable("invalid phase in ConstructPhaseAction");
 }
 
-bool Driver::IsUsingLTO(const ArgList &Args) const {
+bool Driver::IsUsingLTO(const ToolChain &TC, const ArgList &Args) const {
+  if (TC.getSanitizerArgs().needsLTO())
+    return true;
+
   if (Args.hasFlag(options::OPT_flto, options::OPT_fno_lto, false))
     return true;
 

Modified: cfe/trunk/lib/Driver/SanitizerArgs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/SanitizerArgs.cpp?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/SanitizerArgs.cpp (original)
+++ cfe/trunk/lib/Driver/SanitizerArgs.cpp Fri Feb 20 14:30:56 2015
@@ -47,7 +47,8 @@ ID = ALIAS, ID##Group = 1 << SO_##ID##Gr
   SupportsCoverage = Address | Memory | Leak | Undefined | Integer,
   RecoverableByDefault = Undefined | Integer,
   Unrecoverable = Address | Unreachable | Return,
-  LegacyFsanitizeRecoverMask = Undefined | Integer
+  LegacyFsanitizeRecoverMask = Undefined | Integer,
+  NeedsLTO = CFIVptr,
 };
 }
 
@@ -148,6 +149,10 @@ bool SanitizerArgs::needsUnwindTables()
   return hasOneOf(Sanitizers, NeedsUnwindTables);
 }
 
+bool SanitizerArgs::needsLTO() const {
+  return hasOneOf(Sanitizers, CFIVptr);
+}
+
 void SanitizerArgs::clear() {
   Sanitizers.clear();
   RecoverableSanitizers.clear();

Modified: cfe/trunk/lib/Driver/Tools.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.cpp (original)
+++ cfe/trunk/lib/Driver/Tools.cpp Fri Feb 20 14:30:56 2015
@@ -5817,7 +5817,8 @@ void darwin::Link::AddLinkArgs(Compilati
   // If we are using LTO, then automatically create a temporary file path for
   // the linker to use, so that it's lifetime will extend past a possible
   // dsymutil step.
-  if (Version[0] >= 116 && D.IsUsingLTO(Args) && NeedsTempPath(Inputs)) {
+  if (Version[0] >= 116 && D.IsUsingLTO(getToolChain(), Args) &&
+      NeedsTempPath(Inputs)) {
     const char *TmpPath = C.getArgs().MakeArgString(
       D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object)));
     C.addTempFile(TmpPath);
@@ -6840,7 +6841,7 @@ void freebsd::Link::ConstructJob(Compila
   Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
   Args.AddAllArgs(CmdArgs, options::OPT_r);
 
-  if (D.IsUsingLTO(Args))
+  if (D.IsUsingLTO(getToolChain(), Args))
     AddGoldPlugin(ToolChain, Args, CmdArgs);
 
   bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
@@ -7676,7 +7677,7 @@ void gnutools::Link::ConstructJob(Compil
   for (const auto &Path : Paths)
     CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
 
-  if (D.IsUsingLTO(Args))
+  if (D.IsUsingLTO(getToolChain(), Args))
     AddGoldPlugin(ToolChain, Args, CmdArgs);
 
   if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))

Added: cfe/trunk/test/CodeGenCXX/cfi-vptr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cfi-vptr.cpp?rev=230055&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cfi-vptr.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/cfi-vptr.cpp Fri Feb 20 14:30:56 2015
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vptr -emit-llvm -o - %s | FileCheck %s
+
+struct A {
+  A();
+  virtual void f();
+};
+
+struct B : virtual A {
+  B();
+};
+
+struct C : virtual A {
+  C();
+};
+
+namespace {
+
+struct D : B, C {
+  D();
+  virtual void f();
+};
+
+}
+
+A::A() {}
+B::B() {}
+C::C() {}
+D::D() {}
+
+void A::f() {
+}
+
+void D::f() {
+}
+
+// CHECK: define void @_Z2afP1A
+void af(A *a) {
+  // CHECK: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1A")
+  // CHECK-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ]*]]
+
+  // CHECK: [[TRAPBB]]
+  // CHECK-NEXT: call void @llvm.trap()
+  // CHECK-NEXT: unreachable
+
+  // CHECK: [[CONTBB]]
+  // CHECK: call void %
+  a->f();
+}
+
+// CHECK: define internal void @_Z2dfPN12_GLOBAL__N_11DE
+void df(D *d) {
+  // CHECK: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"[{{.*}}cfi-vptr.cpp]N12_GLOBAL__N_11DE")
+  d->f();
+}
+
+D d;
+
+void foo() {
+  df(&d);
+}
+
+// CHECK-DAG: !{!"1A", [3 x i8*]* @_ZTV1A, i64 16}
+// CHECK-DAG: !{!"1A", [5 x i8*]* @_ZTCN12_GLOBAL__N_11DE0_1B, i64 32}
+// CHECK-DAG: !{!"1B", [5 x i8*]* @_ZTCN12_GLOBAL__N_11DE0_1B, i64 32}
+// CHECK-DAG: !{!"1A", [9 x i8*]* @_ZTCN12_GLOBAL__N_11DE8_1C, i64 64}
+// CHECK-DAG: !{!"1C", [9 x i8*]* @_ZTCN12_GLOBAL__N_11DE8_1C, i64 32}
+// CHECK-DAG: !{!"1A", [10 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
+// CHECK-DAG: !{!"1B", [10 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
+// CHECK-DAG: !{!"1C", [10 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 72}
+// CHECK-DAG: !{!"[{{.*}}cfi-vptr.cpp]N12_GLOBAL__N_11DE", [10 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
+// CHECK-DAG: !{!"1A", [5 x i8*]* @_ZTV1B, i64 32}
+// CHECK-DAG: !{!"1B", [5 x i8*]* @_ZTV1B, i64 32}
+// CHECK-DAG: !{!"1A", [5 x i8*]* @_ZTV1C, i64 32}
+// CHECK-DAG: !{!"1C", [5 x i8*]* @_ZTV1C, i64 32}

Modified: cfe/trunk/test/Driver/fsanitize.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/fsanitize.c?rev=230055&r1=230054&r2=230055&view=diff
==============================================================================
--- cfe/trunk/test/Driver/fsanitize.c (original)
+++ cfe/trunk/test/Driver/fsanitize.c Fri Feb 20 14:30:56 2015
@@ -190,6 +190,10 @@
 // RUN: %clang -target x86_64-apple-darwin10 -fsanitize=function -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FSAN-UBSAN-DARWIN
 // CHECK-FSAN-UBSAN-DARWIN: unsupported option '-fsanitize=function' for target 'x86_64-apple-darwin10'
 
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-vptr -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI
+// CHECK-CFI: -emit-llvm-bc{{.*}}-fsanitize=cfi-vptr
+
 // RUN: %clang_cl -fsanitize=address -c -MDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
 // RUN: %clang_cl -fsanitize=address -c -MTd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL
 // RUN: %clang_cl -fsanitize=address -c -LDd -### -- %s 2>&1 | FileCheck %s -check-prefix=CHECK-ASAN-DEBUGRTL






More information about the cfe-commits mailing list