[compiler-rt] r360378 - [libFuzzer] implement -focus_function=auto, to be used with Data Flow Traces

Kostya Serebryany via llvm-commits llvm-commits at lists.llvm.org
Thu May 9 14:29:45 PDT 2019


Author: kcc
Date: Thu May  9 14:29:45 2019
New Revision: 360378

URL: http://llvm.org/viewvc/llvm-project?rev=360378&view=rev
Log:
[libFuzzer] implement -focus_function=auto, to be used with Data Flow Traces

Modified:
    compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.cpp
    compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.h
    compiler-rt/trunk/lib/fuzzer/FuzzerFlags.def
    compiler-rt/trunk/lib/fuzzer/FuzzerLoop.cpp
    compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp
    compiler-rt/trunk/test/fuzzer/OnlySomeBytesTest.cpp
    compiler-rt/trunk/test/fuzzer/dataflow.test
    compiler-rt/trunk/test/fuzzer/only-some-bytes.test

Modified: compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.cpp?rev=360378&r1=360377&r2=360378&view=diff
==============================================================================
--- compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.cpp (original)
+++ compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.cpp Thu May  9 14:29:45 2019
@@ -10,34 +10,141 @@
 
 #include "FuzzerDataFlowTrace.h"
 #include "FuzzerIO.h"
+#include "FuzzerRandom.h"
 
 #include <cstdlib>
 #include <fstream>
+#include <sstream>
 #include <string>
 #include <vector>
 
 namespace fuzzer {
+static const char *kFunctionsTxt = "functions.txt";
+
+bool BlockCoverage::AppendCoverage(const std::string &S) {
+  std::stringstream SS(S);
+  return AppendCoverage(SS);
+}
+
+// Coverage lines have this form:
+// CN X Y Z T
+// where N is the number of the function, T is the total number of instrumented
+// BBs, and X,Y,Z, if present, are the indecies of covered BB.
+// BB #0, which is the entry block, is not explicitly listed.
+bool BlockCoverage::AppendCoverage(std::istream &IN) {
+  std::string L;
+  while (std::getline(IN, L, '\n')) {
+    if (L.empty() || L[0] != 'C')
+      continue; // Ignore non-coverage lines.
+    std::stringstream SS(L.c_str() + 1);
+    size_t FunctionId  = 0;
+    SS >> FunctionId;
+    Vector<uint32_t> CoveredBlocks;
+    while (true) {
+      uint32_t BB = 0;
+      SS >> BB;
+      if (!SS) break;
+      CoveredBlocks.push_back(BB);
+    }
+    if (CoveredBlocks.empty()) return false;
+    uint32_t NumBlocks = CoveredBlocks.back();
+    CoveredBlocks.pop_back();
+    for (auto BB : CoveredBlocks)
+      if (BB >= NumBlocks) return false;
+    auto It = Functions.find(FunctionId);
+    auto &Counters =
+        It == Functions.end()
+            ? Functions.insert({FunctionId, Vector<uint32_t>(NumBlocks)})
+                  .first->second
+            : It->second;
+
+    if (Counters.size() != NumBlocks) return false;  // wrong number of blocks.
+
+    Counters[0]++;
+    for (auto BB : CoveredBlocks)
+      Counters[BB]++;
+  }
+  return true;
+}
+
+// Assign weights to each function.
+// General principles:
+//   * any uncovered function gets weight 0.
+//   * a function with lots of uncovered blocks gets bigger weight.
+//   * a function with a less frequently executed code gets bigger weight.
+Vector<double> BlockCoverage::FunctionWeights(size_t NumFunctions) const {
+  Vector<double> Res(NumFunctions);
+  for (auto It : Functions) {
+    auto FunctionID = It.first;
+    auto Counters = It.second;
+    auto &Weight = Res[FunctionID];
+    Weight = 1000.;  // this function is covered.
+    Weight /= SmallestNonZeroCounter(Counters);
+    Weight *= NumberOfUncoveredBlocks(Counters) + 1;  // make sure it's not 0.
+  }
+  return Res;
+}
+
+void DataFlowTrace::ReadCoverage(const std::string &DirPath) {
+  Vector<SizedFile> Files;
+  GetSizedFilesFromDir(DirPath, &Files);
+  for (auto &SF : Files) {
+    auto Name = Basename(SF.File);
+    if (Name == kFunctionsTxt) continue;
+    std::ifstream IF(SF.File);
+    Coverage.AppendCoverage(IF);
+  }
+}
 
 void DataFlowTrace::Init(const std::string &DirPath,
-                         const std::string &FocusFunction) {
+                         std::string *FocusFunction,
+                         Random &Rand) {
   if (DirPath.empty()) return;
-  const char *kFunctionsTxt = "functions.txt";
   Printf("INFO: DataFlowTrace: reading from '%s'\n", DirPath.c_str());
   Vector<SizedFile> Files;
   GetSizedFilesFromDir(DirPath, &Files);
   std::string L;
+  size_t FocusFuncIdx = SIZE_MAX;
+  Vector<std::string> FunctionNames;
 
   // Read functions.txt
   std::ifstream IF(DirPlusFile(DirPath, kFunctionsTxt));
-  size_t FocusFuncIdx = SIZE_MAX;
   size_t NumFunctions = 0;
   while (std::getline(IF, L, '\n')) {
+    FunctionNames.push_back(L);
     NumFunctions++;
-    if (FocusFunction == L)
+    if (*FocusFunction == L)
       FocusFuncIdx = NumFunctions - 1;
   }
+
+  if (*FocusFunction == "auto") {
+    // AUTOFOCUS works like this:
+    // * reads the coverage data from the DFT files.
+    // * assigns weights to functions based on coverage.
+    // * chooses a random function according to the weights.
+    ReadCoverage(DirPath);
+    auto Weights = Coverage.FunctionWeights(NumFunctions);
+    Vector<double> Intervals(NumFunctions + 1);
+    std::iota(Intervals.begin(), Intervals.end(), 0);
+    auto Distribution = std::piecewise_constant_distribution<double>(
+        Intervals.begin(), Intervals.end(), Weights.begin());
+    FocusFuncIdx = static_cast<size_t>(Distribution(Rand));
+    *FocusFunction = FunctionNames[FocusFuncIdx];
+    assert(FocusFuncIdx < NumFunctions);
+    Printf("INFO: AUTOFOCUS: %zd %s\n", FocusFuncIdx,
+           FunctionNames[FocusFuncIdx].c_str());
+    for (size_t i = 0; i < NumFunctions; i++) {
+      if (!Weights[i]) continue;
+      Printf("  [%zd] W %g\tBB-tot %u\tBB-cov %u\tEntryFreq %u:\t%s\n", i,
+             Weights[i], Coverage.GetNumberOfBlocks(i),
+             Coverage.GetNumberOfCoveredBlocks(i), Coverage.GetCounter(i, 0),
+             FunctionNames[i].c_str());
+    }
+  }
+
   if (!NumFunctions || FocusFuncIdx == SIZE_MAX || Files.size() <= 1)
     return;
+
   // Read traces.
   size_t NumTraceFiles = 0;
   size_t NumTracesWithFocusFunction = 0;

Modified: compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.h?rev=360378&r1=360377&r2=360378&view=diff
==============================================================================
--- compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.h (original)
+++ compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.h Thu May  9 14:29:45 2019
@@ -35,9 +35,80 @@
 #include <string>
 
 namespace fuzzer {
+
+class BlockCoverage {
+ public:
+  bool AppendCoverage(std::istream &IN);
+  bool AppendCoverage(const std::string &S);
+
+  size_t NumCoveredFunctions() const { return Functions.size(); }
+
+  uint32_t GetCounter(size_t FunctionId, size_t BasicBlockId) {
+    auto It = Functions.find(FunctionId);
+    if (It == Functions.end()) return 0;
+    const auto &Counters = It->second;
+    if (BasicBlockId < Counters.size())
+      return Counters[BasicBlockId];
+    return 0;
+  }
+
+  uint32_t GetNumberOfBlocks(size_t FunctionId) {
+    auto It = Functions.find(FunctionId);
+    if (It == Functions.end()) return 0;
+    const auto &Counters = It->second;
+    return Counters.size();
+  }
+
+  uint32_t GetNumberOfCoveredBlocks(size_t FunctionId) {
+    auto It = Functions.find(FunctionId);
+    if (It == Functions.end()) return 0;
+    const auto &Counters = It->second;
+    uint32_t Result = 0;
+    for (auto Cnt: Counters)
+      if (Cnt)
+        Result++;
+    return Result;
+  }
+
+  Vector<double> FunctionWeights(size_t NumFunctions) const;
+  void clear() { Functions.clear(); }
+
+ private:
+
+  typedef Vector<uint32_t> CoverageVector;
+
+  uint32_t NumberOfCoveredBlocks(const CoverageVector &Counters) const {
+    uint32_t Res = 0;
+    for (auto Cnt : Counters)
+      if (Cnt)
+        Res++;
+    return Res;
+  }
+
+  uint32_t NumberOfUncoveredBlocks(const CoverageVector &Counters) const {
+    return Counters.size() - NumberOfCoveredBlocks(Counters);
+  }
+
+  uint32_t SmallestNonZeroCounter(const CoverageVector &Counters) const {
+    assert(!Counters.empty());
+    uint32_t Res = Counters[0];
+    for (auto Cnt : Counters)
+      if (Cnt)
+        Res = Min(Res, Cnt);
+    assert(Res);
+    return Res;
+  }
+
+  // Function ID => vector of counters.
+  // Each counter represents how many input files trigger the given basic block.
+  std::unordered_map<size_t, CoverageVector> Functions;
+};
+
 class DataFlowTrace {
  public:
-  void Init(const std::string &DirPath, const std::string &FocusFunction);
+  void ReadCoverage(const std::string &DirPath);
+  void Init(const std::string &DirPath, std::string *FocusFunction,
+            Random &Rand);
   void Clear() { Traces.clear(); }
   const Vector<uint8_t> *Get(const std::string &InputSha1) const {
     auto It = Traces.find(InputSha1);
@@ -49,6 +120,7 @@ class DataFlowTrace {
  private:
   // Input's sha1 => DFT for the FocusFunction.
   std::unordered_map<std::string, Vector<uint8_t> > Traces;
+  BlockCoverage Coverage;
 };
 }  // namespace fuzzer
 

Modified: compiler-rt/trunk/lib/fuzzer/FuzzerFlags.def
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerFlags.def?rev=360378&r1=360377&r2=360378&view=diff
==============================================================================
--- compiler-rt/trunk/lib/fuzzer/FuzzerFlags.def (original)
+++ compiler-rt/trunk/lib/fuzzer/FuzzerFlags.def Thu May  9 14:29:45 2019
@@ -151,7 +151,9 @@ FUZZER_FLAG_INT(ignore_remaining_args, 0
                 "after this one. Useful for fuzzers that need to do their own "
                 "argument parsing.")
 FUZZER_FLAG_STRING(focus_function, "Experimental. "
-     "Fuzzing will focus on inputs that trigger calls to this function")
+     "Fuzzing will focus on inputs that trigger calls to this function. "
+     "If -focus_function=auto and -data_flow_trace is used, libFuzzer "
+     "will choose the focus functions automatically.")
 
 FUZZER_FLAG_INT(analyze_dict, 0, "Experimental")
 FUZZER_DEPRECATED_FLAG(use_clang_coverage)

Modified: compiler-rt/trunk/lib/fuzzer/FuzzerLoop.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerLoop.cpp?rev=360378&r1=360377&r2=360378&view=diff
==============================================================================
--- compiler-rt/trunk/lib/fuzzer/FuzzerLoop.cpp (original)
+++ compiler-rt/trunk/lib/fuzzer/FuzzerLoop.cpp Thu May  9 14:29:45 2019
@@ -157,8 +157,9 @@ Fuzzer::Fuzzer(UserCallback CB, InputCor
   AllocateCurrentUnitData();
   CurrentUnitSize = 0;
   memset(BaseSha1, 0, sizeof(BaseSha1));
-  TPC.SetFocusFunction(Options.FocusFunction);
-  DFT.Init(Options.DataFlowTrace, Options.FocusFunction);
+  auto FocusFunctionOrAuto = Options.FocusFunction;
+  DFT.Init(Options.DataFlowTrace, &FocusFunctionOrAuto , MD.GetRand());
+  TPC.SetFocusFunction(FocusFunctionOrAuto);
 }
 
 Fuzzer::~Fuzzer() {}

Modified: compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp?rev=360378&r1=360377&r2=360378&view=diff
==============================================================================
--- compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp (original)
+++ compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp Thu May  9 14:29:45 2019
@@ -762,6 +762,92 @@ TEST(Merge, Merge) {
         {"B", "D"}, 3);
 }
 
+TEST(DFT, BlockCoverage) {
+  BlockCoverage Cov;
+  // Assuming C0 has 5 instrumented blocks,
+  // C1: 7 blocks, C2: 4, C3: 9, C4 never covered, C5: 15,
+
+  // Add C0
+  EXPECT_TRUE(Cov.AppendCoverage("C0 5\n"));
+  EXPECT_EQ(Cov.GetCounter(0, 0), 1U);
+  EXPECT_EQ(Cov.GetCounter(0, 1), 0U);  // not seen this BB yet.
+  EXPECT_EQ(Cov.GetCounter(0, 5), 0U);  // BB ID out of bounds.
+  EXPECT_EQ(Cov.GetCounter(1, 0), 0U);  // not seen this function yet.
+
+  EXPECT_EQ(Cov.GetNumberOfBlocks(0), 5U);
+  EXPECT_EQ(Cov.GetNumberOfCoveredBlocks(0), 1U);
+  EXPECT_EQ(Cov.GetNumberOfBlocks(1), 0U);
+
+  // Various errors.
+  EXPECT_FALSE(Cov.AppendCoverage("C0\n"));  // No total number.
+  EXPECT_FALSE(Cov.AppendCoverage("C0 7\n"));  // No total number.
+  EXPECT_FALSE(Cov.AppendCoverage("CZ\n"));  // Wrong function number.
+  EXPECT_FALSE(Cov.AppendCoverage("C1 7 7"));  // BB ID is too big.
+  EXPECT_FALSE(Cov.AppendCoverage("C1 100 7")); // BB ID is too big.
+
+  // Add C0 more times.
+  EXPECT_TRUE(Cov.AppendCoverage("C0 5\n"));
+  EXPECT_EQ(Cov.GetCounter(0, 0), 2U);
+  EXPECT_TRUE(Cov.AppendCoverage("C0 1 2 5\n"));
+  EXPECT_EQ(Cov.GetCounter(0, 0), 3U);
+  EXPECT_EQ(Cov.GetCounter(0, 1), 1U);
+  EXPECT_EQ(Cov.GetCounter(0, 2), 1U);
+  EXPECT_EQ(Cov.GetCounter(0, 3), 0U);
+  EXPECT_EQ(Cov.GetCounter(0, 4), 0U);
+  EXPECT_EQ(Cov.GetNumberOfCoveredBlocks(0), 3U);
+  EXPECT_TRUE(Cov.AppendCoverage("C0 1 3 4 5\n"));
+  EXPECT_EQ(Cov.GetCounter(0, 0), 4U);
+  EXPECT_EQ(Cov.GetCounter(0, 1), 2U);
+  EXPECT_EQ(Cov.GetCounter(0, 2), 1U);
+  EXPECT_EQ(Cov.GetCounter(0, 3), 1U);
+  EXPECT_EQ(Cov.GetCounter(0, 4), 1U);
+  EXPECT_EQ(Cov.GetNumberOfCoveredBlocks(0), 5U);
+
+  EXPECT_TRUE(Cov.AppendCoverage("C1 7\nC2 4\nC3 9\nC5 15\nC0 5\n"));
+  EXPECT_EQ(Cov.GetCounter(0, 0), 5U);
+  EXPECT_EQ(Cov.GetCounter(1, 0), 1U);
+  EXPECT_EQ(Cov.GetCounter(2, 0), 1U);
+  EXPECT_EQ(Cov.GetCounter(3, 0), 1U);
+  EXPECT_EQ(Cov.GetCounter(4, 0), 0U);
+  EXPECT_EQ(Cov.GetCounter(5, 0), 1U);
+
+  EXPECT_TRUE(Cov.AppendCoverage("C3 4 5 9\nC5 11 12 15"));
+  EXPECT_EQ(Cov.GetCounter(0, 0), 5U);
+  EXPECT_EQ(Cov.GetCounter(1, 0), 1U);
+  EXPECT_EQ(Cov.GetCounter(2, 0), 1U);
+  EXPECT_EQ(Cov.GetCounter(3, 0), 2U);
+  EXPECT_EQ(Cov.GetCounter(3, 4), 1U);
+  EXPECT_EQ(Cov.GetCounter(3, 5), 1U);
+  EXPECT_EQ(Cov.GetCounter(3, 6), 0U);
+  EXPECT_EQ(Cov.GetCounter(4, 0), 0U);
+  EXPECT_EQ(Cov.GetCounter(5, 0), 2U);
+  EXPECT_EQ(Cov.GetCounter(5, 10), 0U);
+  EXPECT_EQ(Cov.GetCounter(5, 11), 1U);
+  EXPECT_EQ(Cov.GetCounter(5, 12), 1U);
+}
+
+TEST(DFT, FunctionWeights) {
+  BlockCoverage Cov;
+  // unused function gets zero weight.
+  EXPECT_TRUE(Cov.AppendCoverage("C0 5\n"));
+  auto Weights = Cov.FunctionWeights(2);
+  EXPECT_GT(Weights[0], 0.);
+  EXPECT_EQ(Weights[1], 0.);
+
+  // Less frequently used function gets less weight.
+  Cov.clear();
+  EXPECT_TRUE(Cov.AppendCoverage("C0 5\nC1 5\nC1 5\n"));
+  Weights = Cov.FunctionWeights(2);
+  EXPECT_GT(Weights[0], Weights[1]);
+
+  // A function with more uncovered bclocks gets more weight.
+  Cov.clear();
+  EXPECT_TRUE(Cov.AppendCoverage("C0 1 2 3 5\nC1 2 4\n"));
+  Weights = Cov.FunctionWeights(2);
+  EXPECT_GT(Weights[1], Weights[0]);
+}
+
+
 TEST(Fuzzer, ForEachNonZeroByte) {
   const size_t N = 64;
   alignas(64) uint8_t Ar[N + 8] = {

Modified: compiler-rt/trunk/test/fuzzer/OnlySomeBytesTest.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/fuzzer/OnlySomeBytesTest.cpp?rev=360378&r1=360377&r2=360378&view=diff
==============================================================================
--- compiler-rt/trunk/test/fuzzer/OnlySomeBytesTest.cpp (original)
+++ compiler-rt/trunk/test/fuzzer/OnlySomeBytesTest.cpp Thu May  9 14:29:45 2019
@@ -24,8 +24,16 @@ __attribute__((noinline)) void bad() {
 
 __attribute__((noinline)) void f0(IN in) {
   uint32_t x = in[5] + 251 * in[7] + 251 * 251 * in[9];
-  if (x == 'F' + 251 * 'U' + 251 * 251 * 'Z')
+  if (x == 'F' + 251 * 'U' + 251 * 251 * 'Z') {
+    // artificially inflate uncovered control in f0
+    // so that auto-focus is more likely to chose this function.
+    if (one == -1) {
+      if (one == 2) one = 1;    if (one == 3) one = 1;    if (one == 4) one = 1;
+      if (one == 5) one = 1;    if (one == 6) one = 1;    if (one == 7) one = 1;
+      if (one == 8) one = 1;    if (one == 9) one = 1;    if (one == 0) one = 1;
+    }
     bad();
+  }
 }
 
 __attribute__((noinline)) void fC(IN in) { if (in[2] == 'C') f0(in); }

Modified: compiler-rt/trunk/test/fuzzer/dataflow.test
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/fuzzer/dataflow.test?rev=360378&r1=360377&r2=360378&view=diff
==============================================================================
--- compiler-rt/trunk/test/fuzzer/dataflow.test (original)
+++ compiler-rt/trunk/test/fuzzer/dataflow.test Thu May  9 14:29:45 2019
@@ -92,11 +92,11 @@ RUN: %libfuzzer_src/scripts/collect_data
 RUN: rm -rf %t/OUT
 RUN: %libfuzzer_src/scripts/collect_data_flow.py %t-ThreeFunctionsTestDF %t/IN %t/OUT
 RUN: %t-ThreeFunctionsTest -data_flow_trace=%t/OUT -runs=0 -focus_function=Func2 2>&1 | FileCheck %s --check-prefix=USE_DATA_FLOW_TRACE
-USE_DATA_FLOW_TRACE: INFO: Focus function is set to 'Func2'
 USE_DATA_FLOW_TRACE: INFO: DataFlowTrace: reading from {{.*}}/OUT
 USE_DATA_FLOW_TRACE-DAG: ca8eefe2fd5d6b32028f355fafa3e739a6bf5edc => |000001|
 USE_DATA_FLOW_TRACE-DAG: d28cb407e8e1a702c72d25473f0553d3ec172262 => |0000011|
 USE_DATA_FLOW_TRACE: INFO: DataFlowTrace: 6 trace files, 3 functions, 2 traces with focus function
+USE_DATA_FLOW_TRACE: INFO: Focus function is set to 'Func2'
 
 # Test that we can run collect_data_flow on a long input (>2**16 bytes)
 RUN: rm -rf %t/OUT

Modified: compiler-rt/trunk/test/fuzzer/only-some-bytes.test
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/fuzzer/only-some-bytes.test?rev=360378&r1=360377&r2=360378&view=diff
==============================================================================
--- compiler-rt/trunk/test/fuzzer/only-some-bytes.test (original)
+++ compiler-rt/trunk/test/fuzzer/only-some-bytes.test Thu May  9 14:29:45 2019
@@ -31,7 +31,16 @@ RUN: %t-Fuzz -focus_function=f0 -data_fl
 HAVE_DFT: INFO: 1/{{.*}} inputs have the Data Flow Trace
 
 # Collect DFT, then use it.
-RUN: rm -rf %t/C  && mkdir %t/C &&  cp %t/IN/* %t/C
+RUN: rm -rf %t/C %t/C1  && mkdir %t/C %t/C1 &&  cp %t/IN/* %t/C
 RUN: rm -rf %t/C_DFT && %libfuzzer_src/scripts/collect_data_flow.py %t-DFT %t/C %t/C_DFT > /dev/null 2>&1
-RUN: not %t-Fuzz -focus_function=f0 -data_flow_trace=%t/C_DFT -seed=1 -runs=1000000 -use_value_profile=1 %t/C 2> %t/log
+RUN: not %t-Fuzz -focus_function=f0 -data_flow_trace=%t/C_DFT -seed=1 -runs=1000000 -use_value_profile=1 %t/C1 %t/C 2> %t/log
+RUN: grep BINGO %t/log
+
+# Test -focus_function=auto: run 50 times and verify that 'f0' is the most frequent focus function.
+RUN: %t-Fuzz -focus_function=auto -data_flow_trace=%t/C_DFT -runs=0 %t/C -jobs=50 2>&1 | grep AUTOFOCUS  | sort | uniq -c | sort -g -r | head -n 1 | FileCheck %s --check-prefix=AUTOFOCUS
+AUTOFOCUS: INFO: AUTOFOCUS: {{.*}} f0
+
+# Actually execute 50 fuzzing processes with a small number of runs, to test  -focus_function=auto for real.
+# We can not test data_flow_trace=auto in just a single run, because it may choose to focus on a wrong function.
+RUN: not %t-Fuzz -focus_function=auto -data_flow_trace=%t/C_DFT %t/C -jobs=50 -runs=200000 -use_value_profile=1 2> %t/log
 RUN: grep BINGO %t/log




More information about the llvm-commits mailing list