Index: lib/Transforms/Instrumentation/SanitizerCoverage.cpp =================================================================== --- lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -28,13 +28,14 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/Instrumentation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/EHPersonalities.h" +#include "llvm/IR/CFG.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" +#include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InlineAsm.h" @@ -45,6 +46,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/ModuleUtils.h" @@ -94,6 +96,11 @@ "instructions"), cl::Hidden, cl::init(false)); +static cl::opt ClPruneBlocks( + "sanitizer-coverage-prune-blocks", + cl::desc("Reduce the number of instrumented blocks (experimental)"), + cl::Hidden, cl::init(false)); + // Experimental 8-bit counters used as an additional search heuristic during // coverage-guided fuzzing. // The counters are not thread-friendly: @@ -298,6 +305,22 @@ return true; } +// Check if BB dominates all its successors. +static bool shouldInstrumentBlock(const BasicBlock *BB, + const DominatorTree *DT) { + if (!ClPruneBlocks) + return true; + if (succ_begin(BB) == succ_end(BB)) + return true; + + for (const BasicBlock *SUCC : make_range(succ_begin(BB), succ_end(BB))) { + if (!DT->dominates(BB, SUCC)) + return true; + } + + return false; +} + bool SanitizerCoverageModule::runOnFunction(Function &F) { if (F.empty()) return false; if (F.getName().find(".module_ctor") != std::string::npos) @@ -311,11 +334,15 @@ if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge) SplitAllCriticalEdges(F); SmallVector IndirCalls; - SmallVector AllBlocks; + SmallVector BlocksToInstrument; SmallVector CmpTraceTargets; SmallVector SwitchTraceTargets; + + DominatorTree DT; + DT.recalculate(F); for (auto &BB : F) { - AllBlocks.push_back(&BB); + if (shouldInstrumentBlock(&BB, &DT)) + BlocksToInstrument.push_back(&BB); for (auto &Inst : BB) { if (Options.IndirectCalls) { CallSite CS(&Inst); @@ -330,7 +357,8 @@ } } } - InjectCoverage(F, AllBlocks); + + InjectCoverage(F, BlocksToInstrument); InjectCoverageForIndirectCalls(F, IndirCalls); InjectTraceForCmp(F, CmpTraceTargets); InjectTraceForSwitch(F, SwitchTraceTargets); Index: test/Instrumentation/SanitizerCoverage/coverage.ll =================================================================== --- test/Instrumentation/SanitizerCoverage/coverage.ll +++ test/Instrumentation/SanitizerCoverage/coverage.ll @@ -13,6 +13,7 @@ ; RUN: -S | FileCheck %s --check-prefix=CHECK2 ; RUN: opt < %s -sancov -sanitizer-coverage-level=2 -sanitizer-coverage-block-threshold=1 \ ; RUN: -S | FileCheck %s --check-prefix=CHECK_WITH_CHECK +; RUN: opt < %s -sancov -sanitizer-coverage-level=2 -sanitizer-coverage-prune-blocks=1 -S | FileCheck %s --check-prefix=CHECKPRUNE target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target triple = "x86_64-unknown-linux-gnu" @@ -134,3 +135,11 @@ ; CHECK4-LABEL: define void @call_unreachable ; CHECK4-NOT: __sanitizer_cov ; CHECK4: unreachable + +; CHECKPRUNE-LABEL: define void @foo +; CHECKPRUNE: call void @__sanitizer_cov +; CHECKPRUNE: call void asm sideeffect "", ""() +; CHECKPRUNE: call void @__sanitizer_cov +; CHECKPRUNE: call void asm sideeffect "", ""() +; CHECKPRUNE-NOT: call void @__sanitizer_cov +; CHECKPRUNE: ret void