]> granicus.if.org Git - clang/commitdiff
Allow specifying sanitizers in blacklists
authorVlad Tsyrklevich <vlad@tsyrklevich.net>
Mon, 25 Sep 2017 22:11:12 +0000 (22:11 +0000)
committerVlad Tsyrklevich <vlad@tsyrklevich.net>
Mon, 25 Sep 2017 22:11:12 +0000 (22:11 +0000)
Summary:
This is the follow-up patch to D37924.

This change refactors clang to use the the newly added section headers
in SpecialCaseList to specify which sanitizers blacklists entries
should apply to, like so:

  [cfi-vcall]
  fun:*bad_vcall*
  [cfi-derived-cast|cfi-unrelated-cast]
  fun:*bad_cast*

The SanitizerSpecialCaseList class has been added to allow querying by
SanitizerMask, and SanitizerBlacklist and its downstream users have been
updated to provide that information. Old blacklists not using sections
will continue to function identically since the blacklist entries will
be placed into a '[*]' section by default matching against all
sanitizers.

Reviewers: pcc, kcc, eugenis, vsk

Reviewed By: eugenis

Subscribers: dberris, cfe-commits, mgorny

Differential Revision: https://reviews.llvm.org/D37925

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@314171 91177308-0d34-0410-b5e6-96231b3b80d8

22 files changed:
docs/ControlFlowIntegrity.rst
docs/SanitizerSpecialCaseList.rst
include/clang/Basic/SanitizerBlacklist.h
include/clang/Basic/SanitizerSpecialCaseList.h [new file with mode: 0644]
lib/AST/Decl.cpp
lib/Basic/CMakeLists.txt
lib/Basic/SanitizerBlacklist.cpp
lib/Basic/SanitizerSpecialCaseList.cpp [new file with mode: 0644]
lib/Basic/XRayLists.cpp
lib/CodeGen/CGClass.cpp
lib/CodeGen/CGDeclCXX.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
test/CodeGen/Inputs/sanitizer-special-case-list.sanitized.txt [new file with mode: 0644]
test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized1.txt [new file with mode: 0644]
test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized2.txt [new file with mode: 0644]
test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized3.txt [new file with mode: 0644]
test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized4.txt [new file with mode: 0644]
test/CodeGen/sanitizer-special-case-list.c [new file with mode: 0644]
test/CodeGenCXX/cfi-blacklist.cpp

index eed5ac5120098eb2680daa686fc44d2ba0985889..04fb43a70f1990c6c2c98424a9d335cdf0a935b1 100644 (file)
@@ -243,17 +243,25 @@ Blacklist
 
 A :doc:`SanitizerSpecialCaseList` can be used to relax CFI checks for certain
 source files, functions and types using the ``src``, ``fun`` and ``type``
-entity types.
+entity types. Specific CFI modes can be be specified using ``[section]``
+headers.
 
 .. code-block:: bash
 
-    # Suppress checking for code in a file.
+    # Suppress all CFI checking for code in a file.
     src:bad_file.cpp
     src:bad_header.h
     # Ignore all functions with names containing MyFooBar.
     fun:*MyFooBar*
     # Ignore all types in the standard library.
     type:std::*
+    # Disable only unrelated cast checks for this function
+    [cfi-unrelated-cast]
+    fun:*UnrelatedCast*
+    # Disable CFI call checks for this function without affecting cast checks
+    [cfi-vcall|cfi-nvcall|cfi-icall]
+    fun:*BadCall*
+
 
 .. _cfi-cross-dso:
 
index a4165b2521cfa626a435c6cb9d674a4da02fc6f9..a636a02b01a507b929360e0044dcd650fe04d0da 100644 (file)
@@ -51,14 +51,23 @@ Example
 Format
 ======
 
-Each line contains an entity type, followed by a colon and a regular
-expression, specifying the names of the entities, optionally followed by
-an equals sign and a tool-specific category. Empty lines and lines starting
-with "#" are ignored. The meanining of ``*`` in regular expression for entity
-names is different - it is treated as in shell wildcarding. Two generic
-entity types are ``src`` and ``fun``, which allow user to add, respectively,
-source files and functions to special case list. Some sanitizer tools may
-introduce custom entity types - refer to tool-specific docs.
+Blacklists consist of entries, optionally grouped into sections. Empty lines and
+lines starting with "#" are ignored.
+
+Section names are regular expressions written in square brackets that denote
+which sanitizer the following entries apply to. For example, ``[address]``
+specifies AddressSanitizer while ``[cfi-vcall|cfi-icall]`` specifies Control
+Flow Integrity virtual and indirect call checking. Entries without a section
+will be placed under the ``[*]`` section applying to all enabled sanitizers.
+
+Entries contain an entity type, followed by a colon and a regular expression,
+specifying the names of the entities, optionally followed by an equals sign and
+a tool-specific category, e.g. ``fun:*ExampleFunc=example_category``.  The
+meaning of ``*`` in regular expression for entity names is different - it is
+treated as in shell wildcarding. Two generic entity types are ``src`` and
+``fun``, which allow users to specify source files and functions, respectively.
+Some sanitizer tools may introduce custom entity types and categories - refer to
+tool-specific docs.
 
 .. code-block:: bash
 
@@ -77,3 +86,10 @@ introduce custom entity types - refer to tool-specific docs.
     fun:*BadFunction*
     # Specific sanitizer tools may introduce categories.
     src:/special/path/*=special_sources
+    # Sections can be used to limit blacklist entries to specific sanitizers
+    [address]
+    fun:*BadASanFunc*
+    # Section names are regular expressions
+    [cfi-vcall|cfi-icall]
+    fun:*BadCfiCall
+    # Entries without sections are placed into [*] and apply to all sanitizers
index e651e183168333f3cac7a0fed030f579ffd431fd..1ae5c36eea99ab65aafdd25f5f100c4c3bb95374 100644 (file)
 #define LLVM_CLANG_BASIC_SANITIZERBLACKLIST_H
 
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/SanitizerSpecialCaseList.h"
+#include "clang/Basic/Sanitizers.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/StringRef.h"
-#include "llvm/Support/SpecialCaseList.h"
 #include <memory>
 
 namespace clang {
 
 class SanitizerBlacklist {
-  std::unique_ptr<llvm::SpecialCaseList> SCL;
+  std::unique_ptr<SanitizerSpecialCaseList> SSCL;
   SourceManager &SM;
 
 public:
   SanitizerBlacklist(const std::vector<std::string> &BlacklistPaths,
                      SourceManager &SM);
-  bool isBlacklistedGlobal(StringRef GlobalName,
+  bool isBlacklistedGlobal(SanitizerMask Mask, StringRef GlobalName,
                            StringRef Category = StringRef()) const;
-  bool isBlacklistedType(StringRef MangledTypeName,
+  bool isBlacklistedType(SanitizerMask Mask, StringRef MangledTypeName,
                          StringRef Category = StringRef()) const;
-  bool isBlacklistedFunction(StringRef FunctionName) const;
-  bool isBlacklistedFile(StringRef FileName,
+  bool isBlacklistedFunction(SanitizerMask Mask, StringRef FunctionName) const;
+  bool isBlacklistedFile(SanitizerMask Mask, StringRef FileName,
                          StringRef Category = StringRef()) const;
-  bool isBlacklistedLocation(SourceLocation Loc,
+  bool isBlacklistedLocation(SanitizerMask Mask, SourceLocation Loc,
                              StringRef Category = StringRef()) const;
 };
 
diff --git a/include/clang/Basic/SanitizerSpecialCaseList.h b/include/clang/Basic/SanitizerSpecialCaseList.h
new file mode 100644 (file)
index 0000000..e325202
--- /dev/null
@@ -0,0 +1,54 @@
+//===--- SanitizerSpecialCaseList.h - SCL for sanitizers --------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// An extension of SpecialCaseList to allowing querying sections by
+// SanitizerMask.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_SANITIZERSPECIALCASELIST_H
+#define LLVM_CLANG_BASIC_SANITIZERSPECIALCASELIST_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/Sanitizers.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/SpecialCaseList.h"
+#include <memory>
+
+namespace clang {
+
+class SanitizerSpecialCaseList : public llvm::SpecialCaseList {
+public:
+  static std::unique_ptr<SanitizerSpecialCaseList>
+  create(const std::vector<std::string> &Paths, std::string &Error);
+
+  static std::unique_ptr<SanitizerSpecialCaseList>
+  createOrDie(const std::vector<std::string> &Paths);
+
+  // Query blacklisted entries if any bit in Mask matches the entry's section.
+  bool inSection(SanitizerMask Mask, StringRef Prefix, StringRef Query,
+                 StringRef Category = StringRef()) const;
+
+protected:
+  // Initialize SanitizerSections.
+  void createSanitizerSections();
+
+  struct SanitizerSection {
+    SanitizerSection(SanitizerMask SM, SectionEntries &E)
+        : Mask(SM), Entries(E){};
+
+    SanitizerMask Mask;
+    SectionEntries &Entries;
+  };
+
+  std::vector<SanitizerSection> SanitizerSections;
+};
+
+} // end namespace clang
+
+#endif
index f77345f9c2d33f0a60c19246d50ccc6b1e23a3e2..df30426ebb61e71c1c052d2b8259d7f16df08874 100644 (file)
@@ -3923,9 +3923,9 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
 
 bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const {
   ASTContext &Context = getASTContext();
-  if (!Context.getLangOpts().Sanitize.hasOneOf(
-          SanitizerKind::Address | SanitizerKind::KernelAddress) ||
-      !Context.getLangOpts().SanitizeAddressFieldPadding)
+  const SanitizerMask EnabledAsanMask = Context.getLangOpts().Sanitize.Mask &
+      (SanitizerKind::Address | SanitizerKind::KernelAddress);
+  if (!EnabledAsanMask || !Context.getLangOpts().SanitizeAddressFieldPadding)
     return false;
   const auto &Blacklist = Context.getSanitizerBlacklist();
   const auto *CXXRD = dyn_cast<CXXRecordDecl>(this);
@@ -3943,9 +3943,11 @@ bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const {
     ReasonToReject = 4;  // has trivial destructor.
   else if (CXXRD->isStandardLayout())
     ReasonToReject = 5;  // is standard layout.
-  else if (Blacklist.isBlacklistedLocation(getLocation(), "field-padding"))
+  else if (Blacklist.isBlacklistedLocation(EnabledAsanMask, getLocation(),
+                                           "field-padding"))
     ReasonToReject = 6;  // is in a blacklisted file.
-  else if (Blacklist.isBlacklistedType(getQualifiedNameAsString(),
+  else if (Blacklist.isBlacklistedType(EnabledAsanMask,
+                                       getQualifiedNameAsString(),
                                        "field-padding"))
     ReasonToReject = 7;  // is blacklisted.
 
index 2bec0e83ae973e4f7faac06ffe3a9cd2d77841dc..d0c9b902f67e15c6532808d1d56e79460e6ed7c7 100644 (file)
@@ -62,6 +62,7 @@ add_clang_library(clangBasic
   OpenMPKinds.cpp
   OperatorPrecedence.cpp
   SanitizerBlacklist.cpp
+  SanitizerSpecialCaseList.cpp
   Sanitizers.cpp
   SourceLocation.cpp
   SourceManager.cpp
index de78c94bc19568da433ac6f3cd01060c537d6b9c..199ded1f317a468be1ed9eff18ef19d519727a33 100644 (file)
@@ -17,30 +17,35 @@ using namespace clang;
 
 SanitizerBlacklist::SanitizerBlacklist(
     const std::vector<std::string> &BlacklistPaths, SourceManager &SM)
-    : SCL(llvm::SpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {}
+    : SSCL(SanitizerSpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {}
 
-bool SanitizerBlacklist::isBlacklistedGlobal(StringRef GlobalName,
+bool SanitizerBlacklist::isBlacklistedGlobal(SanitizerMask Mask,
+                                             StringRef GlobalName,
                                              StringRef Category) const {
-  return SCL->inSection("global", GlobalName, Category);
+  return SSCL->inSection(Mask, "global", GlobalName, Category);
 }
 
-bool SanitizerBlacklist::isBlacklistedType(StringRef MangledTypeName,
+bool SanitizerBlacklist::isBlacklistedType(SanitizerMask Mask,
+                                           StringRef MangledTypeName,
                                            StringRef Category) const {
-  return SCL->inSection("type", MangledTypeName, Category);
+  return SSCL->inSection(Mask, "type", MangledTypeName, Category);
 }
 
-bool SanitizerBlacklist::isBlacklistedFunction(StringRef FunctionName) const {
-  return SCL->inSection("fun", FunctionName);
+bool SanitizerBlacklist::isBlacklistedFunction(SanitizerMask Mask,
+                                               StringRef FunctionName) const {
+  return SSCL->inSection(Mask, "fun", FunctionName);
 }
 
-bool SanitizerBlacklist::isBlacklistedFile(StringRef FileName,
+bool SanitizerBlacklist::isBlacklistedFile(SanitizerMask Mask,
+                                           StringRef FileName,
                                            StringRef Category) const {
-  return SCL->inSection("src", FileName, Category);
+  return SSCL->inSection(Mask, "src", FileName, Category);
 }
 
-bool SanitizerBlacklist::isBlacklistedLocation(SourceLocation Loc,
+bool SanitizerBlacklist::isBlacklistedLocation(SanitizerMask Mask,
+                                               SourceLocation Loc,
                                                StringRef Category) const {
   return Loc.isValid() &&
-         isBlacklistedFile(SM.getFilename(SM.getFileLoc(Loc)), Category);
+         isBlacklistedFile(Mask, SM.getFilename(SM.getFileLoc(Loc)), Category);
 }
 
diff --git a/lib/Basic/SanitizerSpecialCaseList.cpp b/lib/Basic/SanitizerSpecialCaseList.cpp
new file mode 100644 (file)
index 0000000..4dd52ee
--- /dev/null
@@ -0,0 +1,64 @@
+//===--- SanitizerSpecialCaseList.cpp - SCL for sanitizers ----------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// An extension of SpecialCaseList to allowing querying sections by
+// SanitizerMask.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Basic/SanitizerSpecialCaseList.h"
+
+using namespace clang;
+
+std::unique_ptr<SanitizerSpecialCaseList>
+SanitizerSpecialCaseList::create(const std::vector<std::string> &Paths,
+                                 std::string &Error) {
+  std::unique_ptr<clang::SanitizerSpecialCaseList> SSCL(
+      new SanitizerSpecialCaseList());
+  if (SSCL->createInternal(Paths, Error)) {
+    SSCL->createSanitizerSections();
+    return SSCL;
+  }
+  return nullptr;
+}
+
+std::unique_ptr<SanitizerSpecialCaseList>
+SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths) {
+  std::string Error;
+  if (auto SSCL = create(Paths, Error))
+    return SSCL;
+  llvm::report_fatal_error(Error);
+}
+
+void SanitizerSpecialCaseList::createSanitizerSections() {
+  for (auto &S : Sections) {
+    SanitizerMask Mask = 0;
+
+#define SANITIZER(NAME, ID)                                                    \
+  if (S.SectionMatcher->match(NAME))                                           \
+    Mask |= SanitizerKind::ID;
+#define SANITIZER_GROUP(NAME, ID, ALIAS) SANITIZER(NAME, ID)
+
+#include "clang/Basic/Sanitizers.def"
+#undef SANITIZER
+#undef SANITIZER_GROUP
+
+    SanitizerSections.emplace_back(Mask, S.Entries);
+  }
+}
+
+bool SanitizerSpecialCaseList::inSection(SanitizerMask Mask, StringRef Prefix,
+                                         StringRef Query,
+                                         StringRef Category) const {
+  for (auto &S : SanitizerSections)
+    if ((S.Mask & Mask) &&
+        SpecialCaseList::inSection(S.Entries, Prefix, Query, Category))
+      return true;
+
+  return false;
+}
index 0a439c7af90dfed239da8051a36673db81b250a9..462777d53400f68577e11536c69de5ffad42e6ae 100644 (file)
@@ -26,11 +26,13 @@ XRayFunctionFilter::ImbueAttribute
 XRayFunctionFilter::shouldImbueFunction(StringRef FunctionName) const {
   // First apply the always instrument list, than if it isn't an "always" see
   // whether it's treated as a "never" instrument function.
-  if (AlwaysInstrument->inSection("fun", FunctionName, "arg1"))
+  if (AlwaysInstrument->inSection("xray_always_instrument", "fun", FunctionName,
+                                  "arg1"))
     return ImbueAttribute::ALWAYS_ARG1;
-  if (AlwaysInstrument->inSection("fun", FunctionName))
+  if (AlwaysInstrument->inSection("xray_always_instrument", "fun",
+                                  FunctionName))
     return ImbueAttribute::ALWAYS;
-  if (NeverInstrument->inSection("fun", FunctionName))
+  if (NeverInstrument->inSection("xray_never_instrument", "fun", FunctionName))
     return ImbueAttribute::NEVER;
   return ImbueAttribute::NONE;
 }
@@ -38,9 +40,11 @@ XRayFunctionFilter::shouldImbueFunction(StringRef FunctionName) const {
 XRayFunctionFilter::ImbueAttribute
 XRayFunctionFilter::shouldImbueFunctionsInFile(StringRef Filename,
                                                StringRef Category) const {
-  if (AlwaysInstrument->inSection("src", Filename, Category))
+  if (AlwaysInstrument->inSection("xray_always_instrument", "src", Filename,
+                                  Category))
     return ImbueAttribute::ALWAYS;
-  if (NeverInstrument->inSection("src", Filename, Category))
+  if (NeverInstrument->inSection("xray_never_instrument", "src", Filename,
+                                 Category))
     return ImbueAttribute::NEVER;
   return ImbueAttribute::NONE;
 }
index 1ebe5219cd19d207c9189e1c76352f5a776f6235..75a0fd43e8b939b6e03ce4ad68e37d80b4570368 100644 (file)
@@ -2604,28 +2604,34 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
       !CGM.HasHiddenLTOVisibility(RD))
     return;
 
-  std::string TypeName = RD->getQualifiedNameAsString();
-  if (getContext().getSanitizerBlacklist().isBlacklistedType(TypeName))
-    return;
-
-  SanitizerScope SanScope(this);
+  SanitizerMask M;
   llvm::SanitizerStatKind SSK;
   switch (TCK) {
   case CFITCK_VCall:
+    M = SanitizerKind::CFIVCall;
     SSK = llvm::SanStat_CFI_VCall;
     break;
   case CFITCK_NVCall:
+    M = SanitizerKind::CFINVCall;
     SSK = llvm::SanStat_CFI_NVCall;
     break;
   case CFITCK_DerivedCast:
+    M = SanitizerKind::CFIDerivedCast;
     SSK = llvm::SanStat_CFI_DerivedCast;
     break;
   case CFITCK_UnrelatedCast:
+    M = SanitizerKind::CFIUnrelatedCast;
     SSK = llvm::SanStat_CFI_UnrelatedCast;
     break;
   case CFITCK_ICall:
     llvm_unreachable("not expecting CFITCK_ICall");
   }
+
+  std::string TypeName = RD->getQualifiedNameAsString();
+  if (getContext().getSanitizerBlacklist().isBlacklistedType(M, TypeName))
+    return;
+
+  SanitizerScope SanScope(this);
   EmitSanitizerStatReport(SSK);
 
   llvm::Metadata *MD =
@@ -2636,24 +2642,6 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
   llvm::Value *TypeTest = Builder.CreateCall(
       CGM.getIntrinsic(llvm::Intrinsic::type_test), {CastedVTable, TypeId});
 
-  SanitizerMask M;
-  switch (TCK) {
-  case CFITCK_VCall:
-    M = SanitizerKind::CFIVCall;
-    break;
-  case CFITCK_NVCall:
-    M = SanitizerKind::CFINVCall;
-    break;
-  case CFITCK_DerivedCast:
-    M = SanitizerKind::CFIDerivedCast;
-    break;
-  case CFITCK_UnrelatedCast:
-    M = SanitizerKind::CFIUnrelatedCast;
-    break;
-  case CFITCK_ICall:
-    llvm_unreachable("not expecting CFITCK_ICall");
-  }
-
   llvm::Constant *StaticData[] = {
       llvm::ConstantInt::get(Int8Ty, TCK),
       EmitCheckSourceLocation(Loc),
@@ -2688,7 +2676,8 @@ bool CodeGenFunction::ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD) {
     return false;
 
   std::string TypeName = RD->getQualifiedNameAsString();
-  return !getContext().getSanitizerBlacklist().isBlacklistedType(TypeName);
+  return !getContext().getSanitizerBlacklist().isBlacklistedType(
+      SanitizerKind::CFIVCall, TypeName);
 }
 
 llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
index 4db207cc2daee9267adf37739a95de67a27d7740..e3437eb9367e9379ebf3dc6badfbee398e3bc502 100644 (file)
@@ -316,17 +316,25 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrDestructFunction(
   if (!getLangOpts().Exceptions)
     Fn->setDoesNotThrow();
 
-  if (!isInSanitizerBlacklist(Fn, Loc)) {
-    if (getLangOpts().Sanitize.hasOneOf(SanitizerKind::Address |
-                                        SanitizerKind::KernelAddress))
-      Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
-    if (getLangOpts().Sanitize.has(SanitizerKind::Thread))
-      Fn->addFnAttr(llvm::Attribute::SanitizeThread);
-    if (getLangOpts().Sanitize.has(SanitizerKind::Memory))
-      Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
-    if (getLangOpts().Sanitize.has(SanitizerKind::SafeStack))
-      Fn->addFnAttr(llvm::Attribute::SafeStack);
-  }
+  if (getLangOpts().Sanitize.has(SanitizerKind::Address) &&
+      !isInSanitizerBlacklist(SanitizerKind::Address, Fn, Loc))
+    Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
+
+  if (getLangOpts().Sanitize.has(SanitizerKind::KernelAddress) &&
+      !isInSanitizerBlacklist(SanitizerKind::KernelAddress, Fn, Loc))
+    Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
+
+  if (getLangOpts().Sanitize.has(SanitizerKind::Thread) &&
+      !isInSanitizerBlacklist(SanitizerKind::Thread, Fn, Loc))
+    Fn->addFnAttr(llvm::Attribute::SanitizeThread);
+
+  if (getLangOpts().Sanitize.has(SanitizerKind::Memory) &&
+      !isInSanitizerBlacklist(SanitizerKind::Memory, Fn, Loc))
+    Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
+
+  if (getLangOpts().Sanitize.has(SanitizerKind::SafeStack) &&
+      !isInSanitizerBlacklist(SanitizerKind::SafeStack, Fn, Loc))
+    Fn->addFnAttr(llvm::Attribute::SafeStack);
 
   return Fn;
 }
index 193e4f122af011afed726237203b6a7acfe2ab3c..cf3dc49ef2a581f82298e312cc587daeafde84db 100644 (file)
@@ -725,7 +725,7 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
 
     // Blacklist based on the mangled type.
     if (!CGM.getContext().getSanitizerBlacklist().isBlacklistedType(
-            Out.str())) {
+            SanitizerKind::Vptr, Out.str())) {
       llvm::hash_code TypeHash = hash_value(Out.str());
 
       // Load the vptr, and compute hash_16_bytes(TypeHash, vptr).
index 1c9fc367940c2ba0e75e226b6bb1fc616bb2959c..53737d54651403c3b0b126e27e82e6fd8fa60834 100644 (file)
@@ -804,8 +804,19 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
   CurFnInfo = &FnInfo;
   assert(CurFn->isDeclaration() && "Function already has body?");
 
-  if (CGM.isInSanitizerBlacklist(Fn, Loc))
-    SanOpts.clear();
+  // If this function has been blacklisted for any of the enabled sanitizers,
+  // disable the sanitizer for the function.
+  do {
+#define SANITIZER(NAME, ID)                                                    \
+  if (SanOpts.empty())                                                         \
+    break;                                                                     \
+  if (SanOpts.has(SanitizerKind::ID))                                          \
+    if (CGM.isInSanitizerBlacklist(SanitizerKind::ID, Fn, Loc))                \
+      SanOpts.set(SanitizerKind::ID, false);
+
+#include "clang/Basic/Sanitizers.def"
+#undef SANITIZER
+  } while (0);
 
   if (D) {
     // Apply the no_sanitize* attributes to SanOpts.
index 4903d408ada6f97ad7a747f1e45abad2b799c491..a8cc50bdd646c853779ef485e2abdcf626793fe5 100644 (file)
@@ -1543,20 +1543,21 @@ void CodeGenModule::AddGlobalAnnotations(const ValueDecl *D,
     Annotations.push_back(EmitAnnotateAttr(GV, I, D->getLocation()));
 }
 
-bool CodeGenModule::isInSanitizerBlacklist(llvm::Function *Fn,
+bool CodeGenModule::isInSanitizerBlacklist(SanitizerMask Kind,
+                                           llvm::Function *Fn,
                                            SourceLocation Loc) const {
   const auto &SanitizerBL = getContext().getSanitizerBlacklist();
   // Blacklist by function name.
-  if (SanitizerBL.isBlacklistedFunction(Fn->getName()))
+  if (SanitizerBL.isBlacklistedFunction(Kind, Fn->getName()))
     return true;
   // Blacklist by location.
   if (Loc.isValid())
-    return SanitizerBL.isBlacklistedLocation(Loc);
+    return SanitizerBL.isBlacklistedLocation(Kind, Loc);
   // If location is unknown, this may be a compiler-generated function. Assume
   // it's located in the main file.
   auto &SM = Context.getSourceManager();
   if (const auto *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
-    return SanitizerBL.isBlacklistedFile(MainFile->getName());
+    return SanitizerBL.isBlacklistedFile(Kind, MainFile->getName());
   }
   return false;
 }
@@ -1565,13 +1566,14 @@ bool CodeGenModule::isInSanitizerBlacklist(llvm::GlobalVariable *GV,
                                            SourceLocation Loc, QualType Ty,
                                            StringRef Category) const {
   // For now globals can be blacklisted only in ASan and KASan.
-  if (!LangOpts.Sanitize.hasOneOf(
-          SanitizerKind::Address | SanitizerKind::KernelAddress))
+  const SanitizerMask EnabledAsanMask = LangOpts.Sanitize.Mask &
+      (SanitizerKind::Address | SanitizerKind::KernelAddress);
+  if (!EnabledAsanMask)
     return false;
   const auto &SanitizerBL = getContext().getSanitizerBlacklist();
-  if (SanitizerBL.isBlacklistedGlobal(GV->getName(), Category))
+  if (SanitizerBL.isBlacklistedGlobal(EnabledAsanMask, GV->getName(), Category))
     return true;
-  if (SanitizerBL.isBlacklistedLocation(Loc, Category))
+  if (SanitizerBL.isBlacklistedLocation(EnabledAsanMask, Loc, Category))
     return true;
   // Check global type.
   if (!Ty.isNull()) {
@@ -1583,7 +1585,7 @@ bool CodeGenModule::isInSanitizerBlacklist(llvm::GlobalVariable *GV,
     // We allow to blacklist only record types (classes, structs etc.)
     if (Ty->isRecordType()) {
       std::string TypeStr = Ty.getAsString(getContext().getPrintingPolicy());
-      if (SanitizerBL.isBlacklistedType(TypeStr, Category))
+      if (SanitizerBL.isBlacklistedType(EnabledAsanMask, TypeStr, Category))
         return true;
     }
   }
index 4bff296cb1957557f42ab5d3603efd28f12f221a..c2bc0e8b8b2e004ac99a41922c00c44b3e480dc8 100644 (file)
@@ -1106,7 +1106,8 @@ public:
   /// annotations are emitted during finalization of the LLVM code.
   void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV);
 
-  bool isInSanitizerBlacklist(llvm::Function *Fn, SourceLocation Loc) const;
+  bool isInSanitizerBlacklist(SanitizerMask Kind, llvm::Function *Fn,
+                              SourceLocation Loc) const;
 
   bool isInSanitizerBlacklist(llvm::GlobalVariable *GV, SourceLocation Loc,
                               QualType Ty,
diff --git a/test/CodeGen/Inputs/sanitizer-special-case-list.sanitized.txt b/test/CodeGen/Inputs/sanitizer-special-case-list.sanitized.txt
new file mode 100644 (file)
index 0000000..a2afde0
--- /dev/null
@@ -0,0 +1,4 @@
+[unsigned-integer-overflow]
+fun:*cfi*
+[cfi]
+fun:*overflow*
diff --git a/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized1.txt b/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized1.txt
new file mode 100644 (file)
index 0000000..45ad57b
--- /dev/null
@@ -0,0 +1,2 @@
+fun:*cfi*
+fun:*overflow*
diff --git a/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized2.txt b/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized2.txt
new file mode 100644 (file)
index 0000000..375b246
--- /dev/null
@@ -0,0 +1,4 @@
+[cfi]
+fun:*cfi*
+[unsigned-integer-overflow]
+fun:*overflow*
diff --git a/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized3.txt b/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized3.txt
new file mode 100644 (file)
index 0000000..b038fee
--- /dev/null
@@ -0,0 +1,4 @@
+[cfi-icall]
+fun:*cfi*
+[unsigned-integer-overflow]
+fun:*overflow*
diff --git a/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized4.txt b/test/CodeGen/Inputs/sanitizer-special-case-list.unsanitized4.txt
new file mode 100644 (file)
index 0000000..b31747e
--- /dev/null
@@ -0,0 +1,4 @@
+[c*]
+fun:*cfi*
+[u*]
+fun:*overflow*
diff --git a/test/CodeGen/sanitizer-special-case-list.c b/test/CodeGen/sanitizer-special-case-list.c
new file mode 100644 (file)
index 0000000..45cfecd
--- /dev/null
@@ -0,0 +1,26 @@
+// Verify that blacklist sections correctly select sanitizers to apply blacklist entries to.
+//
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized1.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized2.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized3.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.unsanitized4.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=UNSANITIZED
+//
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow,cfi-icall -fsanitize-blacklist=%S/Inputs/sanitizer-special-case-list.sanitized.txt -emit-llvm %s -o - | FileCheck %s --check-prefix=SANITIZED
+
+unsigned i;
+
+// SANITIZED: @overflow
+// UNSANITIZED: @overflow
+unsigned overflow() {
+  // SANITIZED: call {{.*}}void @__ubsan
+  // UNSANITIZED-NOT: call {{.*}}void @__ubsan
+  return i * 37;
+}
+
+// SANITIZED: @cfi
+// UNSANITIZED: @cfi
+void cfi(void (*fp)()) {
+  // SANITIZED: llvm.type.test
+  // UNSANITIZED-NOT: llvm.type.test
+  fp();
+}
index af8a10601d2928bf475568eb2e9c25981b1eceb2..c01e5fcd926038ed36e49422bc3e4f9338c07527 100644 (file)
@@ -1,6 +1,18 @@
 // RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOBL %s
-// RUN: echo "type:std::*" > %t.txt
-// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
+
+// Check that blacklisting cfi and cfi-vcall work correctly
+// RUN: echo "[cfi-vcall]" > %t.vcall.txt
+// RUN: echo "type:std::*" >> %t.vcall.txt
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.vcall.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
+//
+// RUN: echo "[cfi]" > %t.cfi.txt
+// RUN: echo "type:std::*" >> %t.cfi.txt
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.cfi.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
+
+// Check that blacklisting non-vcall modes does not affect vcalls
+// RUN: echo "[cfi-icall|cfi-nvcall|cfi-cast-strict|cfi-derived-cast|cfi-unrelated-cast]" > %t.other.txt
+// RUN: echo "type:std::*" >> %t.other.txt
+// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.other.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOBL %s
 
 struct S1 {
   virtual void f();