tuktuk updated this revision to Diff 256546.
tuktuk added a comment.

I was indeed able to run the test again after changing its name to //.cpp//, 
thank you for your help. I have restored XFAIL lines from the original 
//sanitizer_coverage_no_prune.cpp// that I should not have deleted. Now the 
test passes again. Also the test now uses %t to work in a subdirectory like 
//sanitizer_coverage_symbolize.cpp// does.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63616/new/

https://reviews.llvm.org/D63616

Files:
  clang/docs/SanitizerCoverage.rst
  clang/include/clang/Basic/CodeGenOptions.h
  clang/include/clang/Basic/DiagnosticDriverKinds.td
  clang/include/clang/Driver/Options.td
  clang/include/clang/Driver/SanitizerArgs.h
  clang/lib/CodeGen/BackendUtil.cpp
  clang/lib/Driver/SanitizerArgs.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  
compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_whitelist_blacklist.cpp
  llvm/include/llvm/Transforms/Instrumentation/SanitizerCoverage.h
  llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp

Index: llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
===================================================================
--- llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
+++ llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
@@ -35,6 +35,8 @@
 #include "llvm/InitializePasses.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/SpecialCaseList.h"
+#include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Transforms/Instrumentation.h"
 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
@@ -198,8 +200,11 @@
 class ModuleSanitizerCoverage {
 public:
   ModuleSanitizerCoverage(
-      const SanitizerCoverageOptions &Options = SanitizerCoverageOptions())
-      : Options(OverrideFromCL(Options)) {}
+      const SanitizerCoverageOptions &Options = SanitizerCoverageOptions(),
+      const SpecialCaseList *Whitelist = nullptr,
+      const SpecialCaseList *Blacklist = nullptr)
+      : Options(OverrideFromCL(Options)), Whitelist(Whitelist),
+        Blacklist(Blacklist) {}
   bool instrumentModule(Module &M, DomTreeCallback DTCallback,
                         PostDomTreeCallback PDTCallback);
 
@@ -263,18 +268,32 @@
   SmallVector<GlobalValue *, 20> GlobalsToAppendToCompilerUsed;
 
   SanitizerCoverageOptions Options;
+
+  const SpecialCaseList *Whitelist;
+  const SpecialCaseList *Blacklist;
 };
 
 class ModuleSanitizerCoverageLegacyPass : public ModulePass {
 public:
   ModuleSanitizerCoverageLegacyPass(
-      const SanitizerCoverageOptions &Options = SanitizerCoverageOptions())
+      const SanitizerCoverageOptions &Options = SanitizerCoverageOptions(),
+      const std::vector<std::string> &WhitelistFiles =
+          std::vector<std::string>(),
+      const std::vector<std::string> &BlacklistFiles =
+          std::vector<std::string>())
       : ModulePass(ID), Options(Options) {
+    if (WhitelistFiles.size() > 0)
+      Whitelist = SpecialCaseList::createOrDie(WhitelistFiles,
+                                               *vfs::getRealFileSystem());
+    if (BlacklistFiles.size() > 0)
+      Blacklist = SpecialCaseList::createOrDie(BlacklistFiles,
+                                               *vfs::getRealFileSystem());
     initializeModuleSanitizerCoverageLegacyPassPass(
         *PassRegistry::getPassRegistry());
   }
   bool runOnModule(Module &M) override {
-    ModuleSanitizerCoverage ModuleSancov(Options);
+    ModuleSanitizerCoverage ModuleSancov(Options, Whitelist.get(),
+                                         Blacklist.get());
     auto DTCallback = [this](Function &F) -> const DominatorTree * {
       return &this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
     };
@@ -295,6 +314,9 @@
 
 private:
   SanitizerCoverageOptions Options;
+
+  std::unique_ptr<SpecialCaseList> Whitelist;
+  std::unique_ptr<SpecialCaseList> Blacklist;
 };
 
 } // namespace
@@ -374,6 +396,12 @@
     Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
   if (Options.CoverageType == SanitizerCoverageOptions::SCK_None)
     return false;
+  if (Whitelist &&
+      !Whitelist->inSection("coverage", "src", M.getSourceFileName()))
+    return false;
+  if (Blacklist &&
+      Blacklist->inSection("coverage", "src", M.getSourceFileName()))
+    return false;
   C = &(M.getContext());
   DL = &M.getDataLayout();
   CurModule = &M;
@@ -611,6 +639,10 @@
   if (F.hasPersonalityFn() &&
       isAsynchronousEHPersonality(classifyEHPersonality(F.getPersonalityFn())))
     return;
+  if (Whitelist && !Whitelist->inSection("coverage", "fun", F.getName()))
+    return;
+  if (Blacklist && Blacklist->inSection("coverage", "fun", F.getName()))
+    return;
   if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
     SplitAllCriticalEdges(F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests());
   SmallVector<Instruction *, 8> IndirCalls;
@@ -976,6 +1008,9 @@
                     "Pass for instrumenting coverage on functions", false,
                     false)
 ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass(
-    const SanitizerCoverageOptions &Options) {
-  return new ModuleSanitizerCoverageLegacyPass(Options);
+    const SanitizerCoverageOptions &Options,
+    const std::vector<std::string> &WhitelistFiles,
+    const std::vector<std::string> &BlacklistFiles) {
+  return new ModuleSanitizerCoverageLegacyPass(Options, WhitelistFiles,
+                                               BlacklistFiles);
 }
Index: llvm/include/llvm/Transforms/Instrumentation/SanitizerCoverage.h
===================================================================
--- llvm/include/llvm/Transforms/Instrumentation/SanitizerCoverage.h
+++ llvm/include/llvm/Transforms/Instrumentation/SanitizerCoverage.h
@@ -40,7 +40,10 @@
 
 // Insert SanitizerCoverage instrumentation.
 ModulePass *createModuleSanitizerCoverageLegacyPassPass(
-    const SanitizerCoverageOptions &Options = SanitizerCoverageOptions());
+    const SanitizerCoverageOptions &Options = SanitizerCoverageOptions(),
+    const std::vector<std::string> &WhitelistFiles = std::vector<std::string>(),
+    const std::vector<std::string> &BlacklistFiles =
+        std::vector<std::string>());
 
 } // namespace llvm
 
Index: compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_whitelist_blacklist.cpp
===================================================================
--- /dev/null
+++ compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_whitelist_blacklist.cpp
@@ -0,0 +1,123 @@
+// Tests -fsanitize-coverage-whitelist=whitelist.txt and
+// -fsanitize-coverage-blacklist=blacklist.txt with libFuzzer-like coverage
+// options
+
+// REQUIRES: has_sancovcc,stable-runtime
+// UNSUPPORTED: i386-darwin
+// XFAIL: ubsan,tsan
+// XFAIL: android && asan
+
+// RUN: DIR=%t_workdir
+// RUN: rm -rf $DIR
+// RUN: mkdir -p $DIR
+// RUN: cd $DIR
+
+// RUN: echo -e "src:*\nfun:*"     > wl_all.txt
+// RUN: echo -e ""                 > wl_none.txt
+// RUN: echo -e "src:%s\nfun:*"    > wl_file.txt
+// RUN: echo -e "src:*\nfun:*bar*" > wl_bar.txt
+// RUN: echo -e "src:*\nfun:*foo*" > wl_foo.txt
+// RUN: echo -e "src:*"            > bl_all.txt
+// RUN: echo -e ""                 > bl_none.txt
+// RUN: echo -e "src:%s"           > bl_file.txt
+// RUN: echo -e "fun:*foo*"        > bl_foo.txt
+// RUN: echo -e "fun:*bar*"        > bl_bar.txt
+
+// Check inline-8bit-counters
+// RUN: echo 'section "__sancov_cntrs"'                                                                             >  patterns.txt
+// RUN: echo '%[0-9]\+ = load i8, i8\* getelementptr inbounds (\[[0-9]\+ x i8\], \[[0-9]\+ x i8\]\* @__sancov_gen_' >> patterns.txt
+// RUN: echo 'store i8 %[0-9]\+, i8\* getelementptr inbounds (\[[0-9]\+ x i8\], \[[0-9]\+ x i8\]\* @__sancov_gen_'  >> patterns.txt
+
+// Check indirect-calls
+// RUN: echo 'call void @__sanitizer_cov_trace_pc_indir'                                                            >> patterns.txt
+
+// Check trace-cmp
+// RUN: echo 'call void @__sanitizer_cov_trace_cmp4'                                                                >> patterns.txt
+
+// Check pc-table
+// RUN: echo 'section "__sancov_pcs"'                                                                               >> patterns.txt
+
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table                                                                                      2>&1 |     grep -f patterns.txt | count 14
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_all.txt                                             2>&1 |     grep -f patterns.txt | count 14
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_none.txt                                            2>&1 | not grep -f patterns.txt
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_file.txt                                            2>&1 |     grep -f patterns.txt | count 14
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_foo.txt                                             2>&1 |     grep -f patterns.txt | count 9
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_bar.txt                                             2>&1 |     grep -f patterns.txt | count 5
+
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table                                           -fsanitize-coverage-blacklist=bl_all.txt   2>&1 | not grep -f patterns.txt
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_all.txt  -fsanitize-coverage-blacklist=bl_all.txt   2>&1 | not grep -f patterns.txt
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_none.txt -fsanitize-coverage-blacklist=bl_all.txt   2>&1 | not grep -f patterns.txt
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_file.txt -fsanitize-coverage-blacklist=bl_all.txt   2>&1 | not grep -f patterns.txt
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_foo.txt  -fsanitize-coverage-blacklist=bl_all.txt   2>&1 | not grep -f patterns.txt
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_bar.txt  -fsanitize-coverage-blacklist=bl_all.txt   2>&1 | not grep -f patterns.txt
+
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table                                           -fsanitize-coverage-blacklist=bl_none.txt  2>&1 |     grep -f patterns.txt | count 14
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_all.txt  -fsanitize-coverage-blacklist=bl_none.txt  2>&1 |     grep -f patterns.txt | count 14
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_none.txt -fsanitize-coverage-blacklist=bl_none.txt  2>&1 | not grep -f patterns.txt
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_file.txt -fsanitize-coverage-blacklist=bl_none.txt  2>&1 |     grep -f patterns.txt | count 14
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_foo.txt  -fsanitize-coverage-blacklist=bl_none.txt  2>&1 |     grep -f patterns.txt | count 9
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_bar.txt  -fsanitize-coverage-blacklist=bl_none.txt  2>&1 |     grep -f patterns.txt | count 5
+
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table                                           -fsanitize-coverage-blacklist=bl_file.txt  2>&1 | not grep -f patterns.txt
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_all.txt  -fsanitize-coverage-blacklist=bl_file.txt  2>&1 | not grep -f patterns.txt
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_none.txt -fsanitize-coverage-blacklist=bl_file.txt  2>&1 | not grep -f patterns.txt
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_file.txt -fsanitize-coverage-blacklist=bl_file.txt  2>&1 | not grep -f patterns.txt
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_foo.txt  -fsanitize-coverage-blacklist=bl_file.txt  2>&1 | not grep -f patterns.txt
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_bar.txt  -fsanitize-coverage-blacklist=bl_file.txt  2>&1 | not grep -f patterns.txt
+
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table                                           -fsanitize-coverage-blacklist=bl_foo.txt   2>&1 |     grep -f patterns.txt | count 5
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_all.txt  -fsanitize-coverage-blacklist=bl_foo.txt   2>&1 |     grep -f patterns.txt | count 5
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_none.txt -fsanitize-coverage-blacklist=bl_foo.txt   2>&1 | not grep -f patterns.txt
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_file.txt -fsanitize-coverage-blacklist=bl_foo.txt   2>&1 |     grep -f patterns.txt | count 5
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_foo.txt  -fsanitize-coverage-blacklist=bl_foo.txt   2>&1 | not grep -f patterns.txt
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_bar.txt  -fsanitize-coverage-blacklist=bl_foo.txt   2>&1 |     grep -f patterns.txt | count 5
+
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table                                           -fsanitize-coverage-blacklist=bl_bar.txt   2>&1 |     grep -f patterns.txt | count 9
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_all.txt  -fsanitize-coverage-blacklist=bl_bar.txt   2>&1 |     grep -f patterns.txt | count 9
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_none.txt -fsanitize-coverage-blacklist=bl_bar.txt   2>&1 | not grep -f patterns.txt
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_file.txt -fsanitize-coverage-blacklist=bl_bar.txt   2>&1 |     grep -f patterns.txt | count 9
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_foo.txt  -fsanitize-coverage-blacklist=bl_bar.txt   2>&1 |     grep -f patterns.txt | count 9
+// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=inline-8bit-counters,indirect-calls,trace-cmp,pc-table -fsanitize-coverage-whitelist=wl_bar.txt  -fsanitize-coverage-blacklist=bl_bar.txt   2>&1 | not grep -f patterns.txt
+
+// RUN: cd -
+// RUN: rm -rf $DIR
+
+
+// foo has 3 instrumentation points, 0 indirect call, 1 comparison point
+
+// Expected results with patterns.txt when foo gets instrumentation with
+// libFuzzer-like coverage options: 9 lines
+//   inline-8bit-counters ->
+//     @__sancov_gen_XX = private global [3 x i8] zeroinitializer, section "__sancov_cntrs"...
+//     %XX = load i8, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__sancov_gen_, i64 0, i64 0)...
+//     %XX = load i8, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__sancov_gen_, i64 0, i64 1)...
+//     %XX = load i8, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__sancov_gen_, i64 0, i64 2)...
+//     store i8 %XX, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__sancov_gen_, i64 0, i64 0)...
+//     store i8 %XX, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__sancov_gen_, i64 0, i64 1)...
+//     store i8 %XX, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__sancov_gen_, i64 0, i64 2)...
+//   trace-cmp ->
+//     call void @__sanitizer_cov_trace_cmp4(i32 %XX, i32 %XX)
+//   pc-table ->
+//     @__sancov_gen_XX = private constant [6 x i64*] ..., section "__sancov_pcs"...
+
+bool foo(int *a, int *b) {
+  if (*a == *b) {
+    return true;
+  }
+  return false;
+}
+
+// bar has 1 instrumentation point, 1 indirect call, 0 comparison point
+
+// Expected results with patterns.txt when bar gets instrumentation with
+// libFuzzer-like coverage options: 5 lines
+//   inline-8bit-counters ->
+//     @__sancov_gen_XX = private global [1 x i8] zeroinitializer, section "__sancov_cntrs"...
+//     %XX = load i8, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @__sancov_gen_.2, i64 0, i64 0), ...
+//     store i8 %XX, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @__sancov_gen_.2, i64 0, i64 0), ...
+//   indirect-calls ->
+//     call void @__sanitizer_cov_trace_pc_indir(i64 %XX)
+//   pc-table ->
+//     @__sancov_gen_XX = private constant [2 x i64*] ..., section "__sancov_pcs"...
+
+void bar(void (*f)()) { f(); }
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -1181,6 +1181,10 @@
   Opts.SanitizeCoveragePCTable = Args.hasArg(OPT_fsanitize_coverage_pc_table);
   Opts.SanitizeCoverageStackDepth =
       Args.hasArg(OPT_fsanitize_coverage_stack_depth);
+  Opts.SanitizeCoverageWhitelistFiles =
+      Args.getAllArgValues(OPT_fsanitize_coverage_whitelist);
+  Opts.SanitizeCoverageBlacklistFiles =
+      Args.getAllArgValues(OPT_fsanitize_coverage_blacklist);
   Opts.SanitizeMemoryTrackOrigins =
       getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags);
   Opts.SanitizeMemoryUseAfterDtor =
Index: clang/lib/Driver/SanitizerArgs.cpp
===================================================================
--- clang/lib/Driver/SanitizerArgs.cpp
+++ clang/lib/Driver/SanitizerArgs.cpp
@@ -151,6 +151,40 @@
   }
 }
 
+/// Parse -f(no-)?sanitize-(coverage-)?(white|black)list argument's values,
+/// diagnosing any invalid file paths and validating special case list format.
+static void parseSpecialCaseListArg(const Driver &D,
+                                    const llvm::opt::ArgList &Args,
+                                    std::vector<std::string> &SCLFiles,
+                                    llvm::opt::OptSpecifier SCLOptionID,
+                                    llvm::opt::OptSpecifier NoSCLOptionID,
+                                    unsigned MalformedSCLErrorDiagID) {
+  for (const auto *Arg : Args) {
+    // Match -fsanitize-(coverage-)?(white|black)list.
+    if (Arg->getOption().matches(SCLOptionID)) {
+      Arg->claim();
+      std::string SCLPath = Arg->getValue();
+      if (D.getVFS().exists(SCLPath)) {
+        SCLFiles.push_back(SCLPath);
+      } else {
+        D.Diag(clang::diag::err_drv_no_such_file) << SCLPath;
+      }
+      // Match -fno-sanitize-blacklist.
+    } else if (Arg->getOption().matches(NoSCLOptionID)) {
+      Arg->claim();
+      SCLFiles.clear();
+    }
+  }
+  // Validate special case list format.
+  {
+    std::string BLError;
+    std::unique_ptr<llvm::SpecialCaseList> SCL(
+        llvm::SpecialCaseList::create(SCLFiles, D.getVFS(), BLError));
+    if (!SCL.get())
+      D.Diag(MalformedSCLErrorDiagID) << BLError;
+  }
+}
+
 /// Sets group bits for every group that has at least one representative already
 /// enabled in \p Kinds.
 static SanitizerMask setGroupBits(SanitizerMask Kinds) {
@@ -561,37 +595,18 @@
   // Setup blacklist files.
   // Add default blacklist from resource directory.
   addDefaultBlacklists(D, Kinds, SystemBlacklistFiles);
-  // Parse -f(no-)sanitize-blacklist options.
-  for (const auto *Arg : Args) {
-    if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) {
-      Arg->claim();
-      std::string BLPath = Arg->getValue();
-      if (D.getVFS().exists(BLPath)) {
-        UserBlacklistFiles.push_back(BLPath);
-      } else {
-        D.Diag(clang::diag::err_drv_no_such_file) << BLPath;
-      }
-    } else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) {
-      Arg->claim();
-      UserBlacklistFiles.clear();
-      SystemBlacklistFiles.clear();
-    }
-  }
-  // Validate blacklists format.
-  {
-    std::string BLError;
-    std::unique_ptr<llvm::SpecialCaseList> SCL(
-        llvm::SpecialCaseList::create(UserBlacklistFiles, D.getVFS(), BLError));
-    if (!SCL.get())
-      D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
-  }
-  {
-    std::string BLError;
-    std::unique_ptr<llvm::SpecialCaseList> SCL(llvm::SpecialCaseList::create(
-        SystemBlacklistFiles, D.getVFS(), BLError));
-    if (!SCL.get())
-      D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
-  }
+
+  // Parse -f(no-)?sanitize-blacklist options.
+  // This also validates special case lists format.
+  // Here, OptSpecifier() acts as a never-matching command-line argument.
+  // So, there is no way to append to system blacklist but it can be cleared.
+  parseSpecialCaseListArg(D, Args, SystemBlacklistFiles, OptSpecifier(),
+                          options::OPT_fno_sanitize_blacklist,
+                          clang::diag::err_drv_malformed_sanitizer_blacklist);
+  parseSpecialCaseListArg(D, Args, UserBlacklistFiles,
+                          options::OPT_fsanitize_blacklist,
+                          options::OPT_fno_sanitize_blacklist,
+                          clang::diag::err_drv_malformed_sanitizer_blacklist);
 
   // Parse -f[no-]sanitize-memory-track-origins[=level] options.
   if (AllAddedKinds & SanitizerKind::Memory) {
@@ -745,6 +760,21 @@
       CoverageFeatures |= CoverageFunc;
   }
 
+  // Parse -fsanitize-coverage-(black|white)list options if coverage enabled.
+  // This also validates special case lists format.
+  // Here, OptSpecifier() acts as a never-matching command-line argument.
+  // So, there is no way to clear coverage lists but you can append to them.
+  if (CoverageFeatures) {
+    parseSpecialCaseListArg(
+        D, Args, CoverageWhitelistFiles,
+        options::OPT_fsanitize_coverage_whitelist, OptSpecifier(),
+        clang::diag::err_drv_malformed_sanitizer_coverage_whitelist);
+    parseSpecialCaseListArg(
+        D, Args, CoverageBlacklistFiles,
+        options::OPT_fsanitize_coverage_blacklist, OptSpecifier(),
+        clang::diag::err_drv_malformed_sanitizer_coverage_blacklist);
+  }
+
   SharedRuntime =
       Args.hasFlag(options::OPT_shared_libsan, options::OPT_static_libsan,
                    TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia() ||
@@ -871,6 +901,17 @@
   return Res;
 }
 
+static void addSpecialCaseListOpt(const llvm::opt::ArgList &Args,
+                                  llvm::opt::ArgStringList &CmdArgs,
+                                  const char* SCLOptFlag,
+                                  const std::vector<std::string>& SCLFiles) {
+  for (const auto &SCLPath : SCLFiles) {
+    SmallString<64> SCLOpt(SCLOptFlag);
+    SCLOpt += SCLPath;
+    CmdArgs.push_back(Args.MakeArgString(SCLOpt));
+  }
+}
+
 static void addIncludeLinkerOption(const ToolChain &TC,
                                    const llvm::opt::ArgList &Args,
                                    llvm::opt::ArgStringList &CmdArgs,
@@ -933,6 +974,8 @@
     if (CoverageFeatures & F.first)
       CmdArgs.push_back(F.second);
   }
+  addSpecialCaseListOpt(Args, CmdArgs, "-fsanitize-coverage-whitelist=", CoverageWhitelistFiles);
+  addSpecialCaseListOpt(Args, CmdArgs, "-fsanitize-coverage-blacklist=", CoverageBlacklistFiles);
 
   if (TC.getTriple().isOSWindows() && needsUbsanRt()) {
     // Instruct the code generator to embed linker directives in the object file
@@ -968,16 +1011,8 @@
     CmdArgs.push_back(
         Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers)));
 
-  for (const auto &BLPath : UserBlacklistFiles) {
-    SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
-    BlacklistOpt += BLPath;
-    CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
-  }
-  for (const auto &BLPath : SystemBlacklistFiles) {
-    SmallString<64> BlacklistOpt("-fsanitize-system-blacklist=");
-    BlacklistOpt += BLPath;
-    CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
-  }
+  addSpecialCaseListOpt(Args, CmdArgs, "-fsanitize-blacklist=", UserBlacklistFiles);
+  addSpecialCaseListOpt(Args, CmdArgs, "-fsanitize-system-blacklist=", SystemBlacklistFiles);
 
   if (MsanTrackOrigins)
     CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" +
Index: clang/lib/CodeGen/BackendUtil.cpp
===================================================================
--- clang/lib/CodeGen/BackendUtil.cpp
+++ clang/lib/CodeGen/BackendUtil.cpp
@@ -234,7 +234,9 @@
       static_cast<const PassManagerBuilderWrapper &>(Builder);
   const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
   auto Opts = getSancovOptsFromCGOpts(CGOpts);
-  PM.add(createModuleSanitizerCoverageLegacyPassPass(Opts));
+  PM.add(createModuleSanitizerCoverageLegacyPassPass(
+      Opts, CGOpts.SanitizeCoverageWhitelistFiles,
+      CGOpts.SanitizeCoverageBlacklistFiles));
 }
 
 // Check if ASan should use GC-friendly instrumentation for globals.
Index: clang/include/clang/Driver/SanitizerArgs.h
===================================================================
--- clang/include/clang/Driver/SanitizerArgs.h
+++ clang/include/clang/Driver/SanitizerArgs.h
@@ -27,6 +27,8 @@
 
   std::vector<std::string> UserBlacklistFiles;
   std::vector<std::string> SystemBlacklistFiles;
+  std::vector<std::string> CoverageWhitelistFiles;
+  std::vector<std::string> CoverageBlacklistFiles;
   int CoverageFeatures = 0;
   int MsanTrackOrigins = 0;
   bool MsanUseAfterDtor = true;
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1020,6 +1020,12 @@
       Group<f_clang_Group>, Flags<[CoreOption, DriverOption]>,
       HelpText<"Disable specified features of coverage instrumentation for "
                "Sanitizers">, Values<"func,bb,edge,indirect-calls,trace-bb,trace-cmp,trace-div,trace-gep,8bit-counters,trace-pc,trace-pc-guard,no-prune,inline-8bit-counters,inline-bool-flag">;
+def fsanitize_coverage_whitelist : Joined<["-"], "fsanitize-coverage-whitelist=">,
+    Group<f_clang_Group>, Flags<[CoreOption, DriverOption]>,
+    HelpText<"Restrict sanitizer coverage instrumentation exclusively to modules and functions that match the provided special case list, except the blacklisted ones">;
+def fsanitize_coverage_blacklist : Joined<["-"], "fsanitize-coverage-blacklist=">,
+    Group<f_clang_Group>, Flags<[CoreOption, DriverOption]>,
+    HelpText<"Disable sanitizer coverage instrumentation for modules and functions that match the provided special case list, even the whitelisted ones">;
 def fsanitize_memory_track_origins_EQ : Joined<["-"], "fsanitize-memory-track-origins=">,
                                         Group<f_clang_Group>,
                                         HelpText<"Enable origins tracking in MemorySanitizer">;
Index: clang/include/clang/Basic/DiagnosticDriverKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -150,6 +150,10 @@
   "invalid argument '%0' to -%1">;
 def err_drv_malformed_sanitizer_blacklist : Error<
   "malformed sanitizer blacklist: '%0'">;
+def err_drv_malformed_sanitizer_coverage_whitelist : Error<
+  "malformed sanitizer coverage whitelist: '%0'">;
+def err_drv_malformed_sanitizer_coverage_blacklist : Error<
+  "malformed sanitizer coverage blacklist: '%0'">;
 def err_drv_duplicate_config : Error<
   "no more than one option '--config' is allowed">;
 def err_drv_config_file_not_exist : Error<
Index: clang/include/clang/Basic/CodeGenOptions.h
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.h
+++ clang/include/clang/Basic/CodeGenOptions.h
@@ -306,6 +306,16 @@
   /// List of dynamic shared object files to be loaded as pass plugins.
   std::vector<std::string> PassPlugins;
 
+  /// Path to whitelist file specifying which objects
+  /// (files, functions) should exclusively be instrumented
+  /// by sanitizer coverage pass.
+  std::vector<std::string> SanitizeCoverageWhitelistFiles;
+
+  /// Path to blacklist file specifying which objects
+  /// (files, functions) listed for instrumentation by sanitizer
+  /// coverage pass should actually not be instrumented.
+  std::vector<std::string> SanitizeCoverageBlacklistFiles;
+
 public:
   // Define accessors/mutators for code generation options of enumeration type.
 #define CODEGENOPT(Name, Bits, Default)
Index: clang/docs/SanitizerCoverage.rst
===================================================================
--- clang/docs/SanitizerCoverage.rst
+++ clang/docs/SanitizerCoverage.rst
@@ -312,6 +312,58 @@
   // for every non-constant array index.
   void __sanitizer_cov_trace_gep(uintptr_t Idx);
 
+Partially disabling instrumentation
+===================================
+
+It is sometimes useful to tell SanitizerCoverage to instrument only a subset of the
+functions in your target.
+With ``-fsanitize-coverage-whitelist=whitelist.txt``
+and ``-fsanitize-coverage-blacklist=blacklist.txt``,
+you can specify such a subset through the combination of a whitelist and a blacklist.
+
+SanitizerCoverage will only instrument functions that satisfy two conditions.
+First, the function should belong to a source file with a path that is both whitelisted
+and not blacklisted.
+Second, the function should have a mangled name that is both whitelisted and not blacklisted.
+
+The whitelist and blacklist format is similar to that of the sanitizer blacklist format.
+The default whitelist will match every source file and every function.
+The default blacklist will match no source file and no function.
+
+A common use case is to have the whitelist list folders or source files for which you want
+instrumentation and allow all function names, while the blacklist will opt out some specific
+files or functions that the whitelist loosely allowed.
+
+Here is an example whitelist:
+
+.. code-block:: none
+
+  # Enable instrumentation for a whole folder
+  src:bar/*
+  # Enable instrumentation for a specific source file
+  src:foo/a.cpp
+  # Enable instrumentation for all functions in those files
+  fun:*
+
+And an example blacklist:
+
+.. code-block:: none
+
+  # Disable instrumentation for a specific source file that the whitelist allowed
+  src:bar/b.cpp
+  # Disable instrumentation for a specific function that the whitelist allowed
+  fun:*myFunc*
+
+The use of ``*`` wildcards above is required because function names are matched after mangling.
+Without the wildcards, one would have to write the whole mangled name.
+
+Be careful that the paths of source files are matched exactly as they are provided on the clang
+command line.
+For example, the whitelist above would include file ``bar/b.cpp`` if the path was provided
+exactly like this, but would it would fail to include it with other ways to refer to the same
+file such as ``./bar/b.cpp``, or ``bar\b.cpp`` on Windows.
+So, please make sure to always double check that your lists are correctly applied.
+
 Default implementation
 ======================
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to