<div dir="ltr">Hi Kostya,<div><br></div><div>I think that the last line of only-some-bytes.test fails intermittently. About 1 in 100 runs of the test, the line:</div><div>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<br></div><div><br></div><div>does not produce the "BINGO" message. It just keeps getting to 200000 (e.g.)</div><div>...</div><div>#145518 REDUCE cov: 14 ft: 109 corp: 66/172Kb focus: 66 lim: 4099 exec/s: 145518 rss: 389Mb L: 2056/4099 MS: 1 EraseBytes-<br>#145801 REDUCE cov: 14 ft: 109 corp: 66/172Kb focus: 66 lim: 4099 exec/s: 145801 rss: 389Mb L: 2055/4099 MS: 3 CMP-EraseBytes-InsertRepeatedBytes- DE: "h\xd8V\x00"-<br>#170053 RELOAD cov: 14 ft: 116 corp: 72/184Kb focus: 72 lim: 4099 exec/s: 85026 rss: 395Mb<br>#200000 DONE   cov: 14 ft: 116 corp: 72/184Kb focus: 72 lim: 4099 exec/s: 100000 rss: 396Mb<br></div><div><br></div><div>I'm testing with:</div><div><div>#!/bin/bash -xe<br>for ((i=1;i<=1000;i++));<br>do<br>  echo "Run ${i}"<br>  ./bin/llvm-lit -v ../compiler-rt/test/fuzzer/only-some-bytes.test<br>done<br></div><br class="gmail-Apple-interchange-newline"></div><div>Please could you take a look?<br></div><div><br></div><div>Thanks</div><div>Russ</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, 9 May 2019 at 22:27, Kostya Serebryany via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: kcc<br>
Date: Thu May  9 14:29:45 2019<br>
New Revision: 360378<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=360378&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=360378&view=rev</a><br>
Log:<br>
[libFuzzer] implement -focus_function=auto, to be used with Data Flow Traces<br>
<br>
Modified:<br>
    compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.cpp<br>
    compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.h<br>
    compiler-rt/trunk/lib/fuzzer/FuzzerFlags.def<br>
    compiler-rt/trunk/lib/fuzzer/FuzzerLoop.cpp<br>
    compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp<br>
    compiler-rt/trunk/test/fuzzer/OnlySomeBytesTest.cpp<br>
    compiler-rt/trunk/test/fuzzer/dataflow.test<br>
    compiler-rt/trunk/test/fuzzer/only-some-bytes.test<br>
<br>
Modified: compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.cpp?rev=360378&r1=360377&r2=360378&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.cpp?rev=360378&r1=360377&r2=360378&view=diff</a><br>
==============================================================================<br>
--- compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.cpp (original)<br>
+++ compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.cpp Thu May  9 14:29:45 2019<br>
@@ -10,34 +10,141 @@<br>
<br>
 #include "FuzzerDataFlowTrace.h"<br>
 #include "FuzzerIO.h"<br>
+#include "FuzzerRandom.h"<br>
<br>
 #include <cstdlib><br>
 #include <fstream><br>
+#include <sstream><br>
 #include <string><br>
 #include <vector><br>
<br>
 namespace fuzzer {<br>
+static const char *kFunctionsTxt = "functions.txt";<br>
+<br>
+bool BlockCoverage::AppendCoverage(const std::string &S) {<br>
+  std::stringstream SS(S);<br>
+  return AppendCoverage(SS);<br>
+}<br>
+<br>
+// Coverage lines have this form:<br>
+// CN X Y Z T<br>
+// where N is the number of the function, T is the total number of instrumented<br>
+// BBs, and X,Y,Z, if present, are the indecies of covered BB.<br>
+// BB #0, which is the entry block, is not explicitly listed.<br>
+bool BlockCoverage::AppendCoverage(std::istream &IN) {<br>
+  std::string L;<br>
+  while (std::getline(IN, L, '\n')) {<br>
+    if (L.empty() || L[0] != 'C')<br>
+      continue; // Ignore non-coverage lines.<br>
+    std::stringstream SS(L.c_str() + 1);<br>
+    size_t FunctionId  = 0;<br>
+    SS >> FunctionId;<br>
+    Vector<uint32_t> CoveredBlocks;<br>
+    while (true) {<br>
+      uint32_t BB = 0;<br>
+      SS >> BB;<br>
+      if (!SS) break;<br>
+      CoveredBlocks.push_back(BB);<br>
+    }<br>
+    if (CoveredBlocks.empty()) return false;<br>
+    uint32_t NumBlocks = CoveredBlocks.back();<br>
+    CoveredBlocks.pop_back();<br>
+    for (auto BB : CoveredBlocks)<br>
+      if (BB >= NumBlocks) return false;<br>
+    auto It = Functions.find(FunctionId);<br>
+    auto &Counters =<br>
+        It == Functions.end()<br>
+            ? Functions.insert({FunctionId, Vector<uint32_t>(NumBlocks)})<br>
+                  .first->second<br>
+            : It->second;<br>
+<br>
+    if (Counters.size() != NumBlocks) return false;  // wrong number of blocks.<br>
+<br>
+    Counters[0]++;<br>
+    for (auto BB : CoveredBlocks)<br>
+      Counters[BB]++;<br>
+  }<br>
+  return true;<br>
+}<br>
+<br>
+// Assign weights to each function.<br>
+// General principles:<br>
+//   * any uncovered function gets weight 0.<br>
+//   * a function with lots of uncovered blocks gets bigger weight.<br>
+//   * a function with a less frequently executed code gets bigger weight.<br>
+Vector<double> BlockCoverage::FunctionWeights(size_t NumFunctions) const {<br>
+  Vector<double> Res(NumFunctions);<br>
+  for (auto It : Functions) {<br>
+    auto FunctionID = It.first;<br>
+    auto Counters = It.second;<br>
+    auto &Weight = Res[FunctionID];<br>
+    Weight = 1000.;  // this function is covered.<br>
+    Weight /= SmallestNonZeroCounter(Counters);<br>
+    Weight *= NumberOfUncoveredBlocks(Counters) + 1;  // make sure it's not 0.<br>
+  }<br>
+  return Res;<br>
+}<br>
+<br>
+void DataFlowTrace::ReadCoverage(const std::string &DirPath) {<br>
+  Vector<SizedFile> Files;<br>
+  GetSizedFilesFromDir(DirPath, &Files);<br>
+  for (auto &SF : Files) {<br>
+    auto Name = Basename(SF.File);<br>
+    if (Name == kFunctionsTxt) continue;<br>
+    std::ifstream IF(SF.File);<br>
+    Coverage.AppendCoverage(IF);<br>
+  }<br>
+}<br>
<br>
 void DataFlowTrace::Init(const std::string &DirPath,<br>
-                         const std::string &FocusFunction) {<br>
+                         std::string *FocusFunction,<br>
+                         Random &Rand) {<br>
   if (DirPath.empty()) return;<br>
-  const char *kFunctionsTxt = "functions.txt";<br>
   Printf("INFO: DataFlowTrace: reading from '%s'\n", DirPath.c_str());<br>
   Vector<SizedFile> Files;<br>
   GetSizedFilesFromDir(DirPath, &Files);<br>
   std::string L;<br>
+  size_t FocusFuncIdx = SIZE_MAX;<br>
+  Vector<std::string> FunctionNames;<br>
<br>
   // Read functions.txt<br>
   std::ifstream IF(DirPlusFile(DirPath, kFunctionsTxt));<br>
-  size_t FocusFuncIdx = SIZE_MAX;<br>
   size_t NumFunctions = 0;<br>
   while (std::getline(IF, L, '\n')) {<br>
+    FunctionNames.push_back(L);<br>
     NumFunctions++;<br>
-    if (FocusFunction == L)<br>
+    if (*FocusFunction == L)<br>
       FocusFuncIdx = NumFunctions - 1;<br>
   }<br>
+<br>
+  if (*FocusFunction == "auto") {<br>
+    // AUTOFOCUS works like this:<br>
+    // * reads the coverage data from the DFT files.<br>
+    // * assigns weights to functions based on coverage.<br>
+    // * chooses a random function according to the weights.<br>
+    ReadCoverage(DirPath);<br>
+    auto Weights = Coverage.FunctionWeights(NumFunctions);<br>
+    Vector<double> Intervals(NumFunctions + 1);<br>
+    std::iota(Intervals.begin(), Intervals.end(), 0);<br>
+    auto Distribution = std::piecewise_constant_distribution<double>(<br>
+        Intervals.begin(), Intervals.end(), Weights.begin());<br>
+    FocusFuncIdx = static_cast<size_t>(Distribution(Rand));<br>
+    *FocusFunction = FunctionNames[FocusFuncIdx];<br>
+    assert(FocusFuncIdx < NumFunctions);<br>
+    Printf("INFO: AUTOFOCUS: %zd %s\n", FocusFuncIdx,<br>
+           FunctionNames[FocusFuncIdx].c_str());<br>
+    for (size_t i = 0; i < NumFunctions; i++) {<br>
+      if (!Weights[i]) continue;<br>
+      Printf("  [%zd] W %g\tBB-tot %u\tBB-cov %u\tEntryFreq %u:\t%s\n", i,<br>
+             Weights[i], Coverage.GetNumberOfBlocks(i),<br>
+             Coverage.GetNumberOfCoveredBlocks(i), Coverage.GetCounter(i, 0),<br>
+             FunctionNames[i].c_str());<br>
+    }<br>
+  }<br>
+<br>
   if (!NumFunctions || FocusFuncIdx == SIZE_MAX || Files.size() <= 1)<br>
     return;<br>
+<br>
   // Read traces.<br>
   size_t NumTraceFiles = 0;<br>
   size_t NumTracesWithFocusFunction = 0;<br>
<br>
Modified: compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.h?rev=360378&r1=360377&r2=360378&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.h?rev=360378&r1=360377&r2=360378&view=diff</a><br>
==============================================================================<br>
--- compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.h (original)<br>
+++ compiler-rt/trunk/lib/fuzzer/FuzzerDataFlowTrace.h Thu May  9 14:29:45 2019<br>
@@ -35,9 +35,80 @@<br>
 #include <string><br>
<br>
 namespace fuzzer {<br>
+<br>
+class BlockCoverage {<br>
+ public:<br>
+  bool AppendCoverage(std::istream &IN);<br>
+  bool AppendCoverage(const std::string &S);<br>
+<br>
+  size_t NumCoveredFunctions() const { return Functions.size(); }<br>
+<br>
+  uint32_t GetCounter(size_t FunctionId, size_t BasicBlockId) {<br>
+    auto It = Functions.find(FunctionId);<br>
+    if (It == Functions.end()) return 0;<br>
+    const auto &Counters = It->second;<br>
+    if (BasicBlockId < Counters.size())<br>
+      return Counters[BasicBlockId];<br>
+    return 0;<br>
+  }<br>
+<br>
+  uint32_t GetNumberOfBlocks(size_t FunctionId) {<br>
+    auto It = Functions.find(FunctionId);<br>
+    if (It == Functions.end()) return 0;<br>
+    const auto &Counters = It->second;<br>
+    return Counters.size();<br>
+  }<br>
+<br>
+  uint32_t GetNumberOfCoveredBlocks(size_t FunctionId) {<br>
+    auto It = Functions.find(FunctionId);<br>
+    if (It == Functions.end()) return 0;<br>
+    const auto &Counters = It->second;<br>
+    uint32_t Result = 0;<br>
+    for (auto Cnt: Counters)<br>
+      if (Cnt)<br>
+        Result++;<br>
+    return Result;<br>
+  }<br>
+<br>
+  Vector<double> FunctionWeights(size_t NumFunctions) const;<br>
+  void clear() { Functions.clear(); }<br>
+<br>
+ private:<br>
+<br>
+  typedef Vector<uint32_t> CoverageVector;<br>
+<br>
+  uint32_t NumberOfCoveredBlocks(const CoverageVector &Counters) const {<br>
+    uint32_t Res = 0;<br>
+    for (auto Cnt : Counters)<br>
+      if (Cnt)<br>
+        Res++;<br>
+    return Res;<br>
+  }<br>
+<br>
+  uint32_t NumberOfUncoveredBlocks(const CoverageVector &Counters) const {<br>
+    return Counters.size() - NumberOfCoveredBlocks(Counters);<br>
+  }<br>
+<br>
+  uint32_t SmallestNonZeroCounter(const CoverageVector &Counters) const {<br>
+    assert(!Counters.empty());<br>
+    uint32_t Res = Counters[0];<br>
+    for (auto Cnt : Counters)<br>
+      if (Cnt)<br>
+        Res = Min(Res, Cnt);<br>
+    assert(Res);<br>
+    return Res;<br>
+  }<br>
+<br>
+  // Function ID => vector of counters.<br>
+  // Each counter represents how many input files trigger the given basic block.<br>
+  std::unordered_map<size_t, CoverageVector> Functions;<br>
+};<br>
+<br>
 class DataFlowTrace {<br>
  public:<br>
-  void Init(const std::string &DirPath, const std::string &FocusFunction);<br>
+  void ReadCoverage(const std::string &DirPath);<br>
+  void Init(const std::string &DirPath, std::string *FocusFunction,<br>
+            Random &Rand);<br>
   void Clear() { Traces.clear(); }<br>
   const Vector<uint8_t> *Get(const std::string &InputSha1) const {<br>
     auto It = Traces.find(InputSha1);<br>
@@ -49,6 +120,7 @@ class DataFlowTrace {<br>
  private:<br>
   // Input's sha1 => DFT for the FocusFunction.<br>
   std::unordered_map<std::string, Vector<uint8_t> > Traces;<br>
+  BlockCoverage Coverage;<br>
 };<br>
 }  // namespace fuzzer<br>
<br>
<br>
Modified: compiler-rt/trunk/lib/fuzzer/FuzzerFlags.def<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerFlags.def?rev=360378&r1=360377&r2=360378&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerFlags.def?rev=360378&r1=360377&r2=360378&view=diff</a><br>
==============================================================================<br>
--- compiler-rt/trunk/lib/fuzzer/FuzzerFlags.def (original)<br>
+++ compiler-rt/trunk/lib/fuzzer/FuzzerFlags.def Thu May  9 14:29:45 2019<br>
@@ -151,7 +151,9 @@ FUZZER_FLAG_INT(ignore_remaining_args, 0<br>
                 "after this one. Useful for fuzzers that need to do their own "<br>
                 "argument parsing.")<br>
 FUZZER_FLAG_STRING(focus_function, "Experimental. "<br>
-     "Fuzzing will focus on inputs that trigger calls to this function")<br>
+     "Fuzzing will focus on inputs that trigger calls to this function. "<br>
+     "If -focus_function=auto and -data_flow_trace is used, libFuzzer "<br>
+     "will choose the focus functions automatically.")<br>
<br>
 FUZZER_FLAG_INT(analyze_dict, 0, "Experimental")<br>
 FUZZER_DEPRECATED_FLAG(use_clang_coverage)<br>
<br>
Modified: compiler-rt/trunk/lib/fuzzer/FuzzerLoop.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerLoop.cpp?rev=360378&r1=360377&r2=360378&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerLoop.cpp?rev=360378&r1=360377&r2=360378&view=diff</a><br>
==============================================================================<br>
--- compiler-rt/trunk/lib/fuzzer/FuzzerLoop.cpp (original)<br>
+++ compiler-rt/trunk/lib/fuzzer/FuzzerLoop.cpp Thu May  9 14:29:45 2019<br>
@@ -157,8 +157,9 @@ Fuzzer::Fuzzer(UserCallback CB, InputCor<br>
   AllocateCurrentUnitData();<br>
   CurrentUnitSize = 0;<br>
   memset(BaseSha1, 0, sizeof(BaseSha1));<br>
-  TPC.SetFocusFunction(Options.FocusFunction);<br>
-  DFT.Init(Options.DataFlowTrace, Options.FocusFunction);<br>
+  auto FocusFunctionOrAuto = Options.FocusFunction;<br>
+  DFT.Init(Options.DataFlowTrace, &FocusFunctionOrAuto , MD.GetRand());<br>
+  TPC.SetFocusFunction(FocusFunctionOrAuto);<br>
 }<br>
<br>
 Fuzzer::~Fuzzer() {}<br>
<br>
Modified: compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp?rev=360378&r1=360377&r2=360378&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp?rev=360378&r1=360377&r2=360378&view=diff</a><br>
==============================================================================<br>
--- compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp (original)<br>
+++ compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp Thu May  9 14:29:45 2019<br>
@@ -762,6 +762,92 @@ TEST(Merge, Merge) {<br>
         {"B", "D"}, 3);<br>
 }<br>
<br>
+TEST(DFT, BlockCoverage) {<br>
+  BlockCoverage Cov;<br>
+  // Assuming C0 has 5 instrumented blocks,<br>
+  // C1: 7 blocks, C2: 4, C3: 9, C4 never covered, C5: 15,<br>
+<br>
+  // Add C0<br>
+  EXPECT_TRUE(Cov.AppendCoverage("C0 5\n"));<br>
+  EXPECT_EQ(Cov.GetCounter(0, 0), 1U);<br>
+  EXPECT_EQ(Cov.GetCounter(0, 1), 0U);  // not seen this BB yet.<br>
+  EXPECT_EQ(Cov.GetCounter(0, 5), 0U);  // BB ID out of bounds.<br>
+  EXPECT_EQ(Cov.GetCounter(1, 0), 0U);  // not seen this function yet.<br>
+<br>
+  EXPECT_EQ(Cov.GetNumberOfBlocks(0), 5U);<br>
+  EXPECT_EQ(Cov.GetNumberOfCoveredBlocks(0), 1U);<br>
+  EXPECT_EQ(Cov.GetNumberOfBlocks(1), 0U);<br>
+<br>
+  // Various errors.<br>
+  EXPECT_FALSE(Cov.AppendCoverage("C0\n"));  // No total number.<br>
+  EXPECT_FALSE(Cov.AppendCoverage("C0 7\n"));  // No total number.<br>
+  EXPECT_FALSE(Cov.AppendCoverage("CZ\n"));  // Wrong function number.<br>
+  EXPECT_FALSE(Cov.AppendCoverage("C1 7 7"));  // BB ID is too big.<br>
+  EXPECT_FALSE(Cov.AppendCoverage("C1 100 7")); // BB ID is too big.<br>
+<br>
+  // Add C0 more times.<br>
+  EXPECT_TRUE(Cov.AppendCoverage("C0 5\n"));<br>
+  EXPECT_EQ(Cov.GetCounter(0, 0), 2U);<br>
+  EXPECT_TRUE(Cov.AppendCoverage("C0 1 2 5\n"));<br>
+  EXPECT_EQ(Cov.GetCounter(0, 0), 3U);<br>
+  EXPECT_EQ(Cov.GetCounter(0, 1), 1U);<br>
+  EXPECT_EQ(Cov.GetCounter(0, 2), 1U);<br>
+  EXPECT_EQ(Cov.GetCounter(0, 3), 0U);<br>
+  EXPECT_EQ(Cov.GetCounter(0, 4), 0U);<br>
+  EXPECT_EQ(Cov.GetNumberOfCoveredBlocks(0), 3U);<br>
+  EXPECT_TRUE(Cov.AppendCoverage("C0 1 3 4 5\n"));<br>
+  EXPECT_EQ(Cov.GetCounter(0, 0), 4U);<br>
+  EXPECT_EQ(Cov.GetCounter(0, 1), 2U);<br>
+  EXPECT_EQ(Cov.GetCounter(0, 2), 1U);<br>
+  EXPECT_EQ(Cov.GetCounter(0, 3), 1U);<br>
+  EXPECT_EQ(Cov.GetCounter(0, 4), 1U);<br>
+  EXPECT_EQ(Cov.GetNumberOfCoveredBlocks(0), 5U);<br>
+<br>
+  EXPECT_TRUE(Cov.AppendCoverage("C1 7\nC2 4\nC3 9\nC5 15\nC0 5\n"));<br>
+  EXPECT_EQ(Cov.GetCounter(0, 0), 5U);<br>
+  EXPECT_EQ(Cov.GetCounter(1, 0), 1U);<br>
+  EXPECT_EQ(Cov.GetCounter(2, 0), 1U);<br>
+  EXPECT_EQ(Cov.GetCounter(3, 0), 1U);<br>
+  EXPECT_EQ(Cov.GetCounter(4, 0), 0U);<br>
+  EXPECT_EQ(Cov.GetCounter(5, 0), 1U);<br>
+<br>
+  EXPECT_TRUE(Cov.AppendCoverage("C3 4 5 9\nC5 11 12 15"));<br>
+  EXPECT_EQ(Cov.GetCounter(0, 0), 5U);<br>
+  EXPECT_EQ(Cov.GetCounter(1, 0), 1U);<br>
+  EXPECT_EQ(Cov.GetCounter(2, 0), 1U);<br>
+  EXPECT_EQ(Cov.GetCounter(3, 0), 2U);<br>
+  EXPECT_EQ(Cov.GetCounter(3, 4), 1U);<br>
+  EXPECT_EQ(Cov.GetCounter(3, 5), 1U);<br>
+  EXPECT_EQ(Cov.GetCounter(3, 6), 0U);<br>
+  EXPECT_EQ(Cov.GetCounter(4, 0), 0U);<br>
+  EXPECT_EQ(Cov.GetCounter(5, 0), 2U);<br>
+  EXPECT_EQ(Cov.GetCounter(5, 10), 0U);<br>
+  EXPECT_EQ(Cov.GetCounter(5, 11), 1U);<br>
+  EXPECT_EQ(Cov.GetCounter(5, 12), 1U);<br>
+}<br>
+<br>
+TEST(DFT, FunctionWeights) {<br>
+  BlockCoverage Cov;<br>
+  // unused function gets zero weight.<br>
+  EXPECT_TRUE(Cov.AppendCoverage("C0 5\n"));<br>
+  auto Weights = Cov.FunctionWeights(2);<br>
+  EXPECT_GT(Weights[0], 0.);<br>
+  EXPECT_EQ(Weights[1], 0.);<br>
+<br>
+  // Less frequently used function gets less weight.<br>
+  Cov.clear();<br>
+  EXPECT_TRUE(Cov.AppendCoverage("C0 5\nC1 5\nC1 5\n"));<br>
+  Weights = Cov.FunctionWeights(2);<br>
+  EXPECT_GT(Weights[0], Weights[1]);<br>
+<br>
+  // A function with more uncovered bclocks gets more weight.<br>
+  Cov.clear();<br>
+  EXPECT_TRUE(Cov.AppendCoverage("C0 1 2 3 5\nC1 2 4\n"));<br>
+  Weights = Cov.FunctionWeights(2);<br>
+  EXPECT_GT(Weights[1], Weights[0]);<br>
+}<br>
+<br>
+<br>
 TEST(Fuzzer, ForEachNonZeroByte) {<br>
   const size_t N = 64;<br>
   alignas(64) uint8_t Ar[N + 8] = {<br>
<br>
Modified: compiler-rt/trunk/test/fuzzer/OnlySomeBytesTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/fuzzer/OnlySomeBytesTest.cpp?rev=360378&r1=360377&r2=360378&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/fuzzer/OnlySomeBytesTest.cpp?rev=360378&r1=360377&r2=360378&view=diff</a><br>
==============================================================================<br>
--- compiler-rt/trunk/test/fuzzer/OnlySomeBytesTest.cpp (original)<br>
+++ compiler-rt/trunk/test/fuzzer/OnlySomeBytesTest.cpp Thu May  9 14:29:45 2019<br>
@@ -24,8 +24,16 @@ __attribute__((noinline)) void bad() {<br>
<br>
 __attribute__((noinline)) void f0(IN in) {<br>
   uint32_t x = in[5] + 251 * in[7] + 251 * 251 * in[9];<br>
-  if (x == 'F' + 251 * 'U' + 251 * 251 * 'Z')<br>
+  if (x == 'F' + 251 * 'U' + 251 * 251 * 'Z') {<br>
+    // artificially inflate uncovered control in f0<br>
+    // so that auto-focus is more likely to chose this function.<br>
+    if (one == -1) {<br>
+      if (one == 2) one = 1;    if (one == 3) one = 1;    if (one == 4) one = 1;<br>
+      if (one == 5) one = 1;    if (one == 6) one = 1;    if (one == 7) one = 1;<br>
+      if (one == 8) one = 1;    if (one == 9) one = 1;    if (one == 0) one = 1;<br>
+    }<br>
     bad();<br>
+  }<br>
 }<br>
<br>
 __attribute__((noinline)) void fC(IN in) { if (in[2] == 'C') f0(in); }<br>
<br>
Modified: compiler-rt/trunk/test/fuzzer/dataflow.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/fuzzer/dataflow.test?rev=360378&r1=360377&r2=360378&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/fuzzer/dataflow.test?rev=360378&r1=360377&r2=360378&view=diff</a><br>
==============================================================================<br>
--- compiler-rt/trunk/test/fuzzer/dataflow.test (original)<br>
+++ compiler-rt/trunk/test/fuzzer/dataflow.test Thu May  9 14:29:45 2019<br>
@@ -92,11 +92,11 @@ RUN: %libfuzzer_src/scripts/collect_data<br>
 RUN: rm -rf %t/OUT<br>
 RUN: %libfuzzer_src/scripts/collect_data_flow.py %t-ThreeFunctionsTestDF %t/IN %t/OUT<br>
 RUN: %t-ThreeFunctionsTest -data_flow_trace=%t/OUT -runs=0 -focus_function=Func2 2>&1 | FileCheck %s --check-prefix=USE_DATA_FLOW_TRACE<br>
-USE_DATA_FLOW_TRACE: INFO: Focus function is set to 'Func2'<br>
 USE_DATA_FLOW_TRACE: INFO: DataFlowTrace: reading from {{.*}}/OUT<br>
 USE_DATA_FLOW_TRACE-DAG: ca8eefe2fd5d6b32028f355fafa3e739a6bf5edc => |000001|<br>
 USE_DATA_FLOW_TRACE-DAG: d28cb407e8e1a702c72d25473f0553d3ec172262 => |0000011|<br>
 USE_DATA_FLOW_TRACE: INFO: DataFlowTrace: 6 trace files, 3 functions, 2 traces with focus function<br>
+USE_DATA_FLOW_TRACE: INFO: Focus function is set to 'Func2'<br>
<br>
 # Test that we can run collect_data_flow on a long input (>2**16 bytes)<br>
 RUN: rm -rf %t/OUT<br>
<br>
Modified: compiler-rt/trunk/test/fuzzer/only-some-bytes.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/fuzzer/only-some-bytes.test?rev=360378&r1=360377&r2=360378&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/fuzzer/only-some-bytes.test?rev=360378&r1=360377&r2=360378&view=diff</a><br>
==============================================================================<br>
--- compiler-rt/trunk/test/fuzzer/only-some-bytes.test (original)<br>
+++ compiler-rt/trunk/test/fuzzer/only-some-bytes.test Thu May  9 14:29:45 2019<br>
@@ -31,7 +31,16 @@ RUN: %t-Fuzz -focus_function=f0 -data_fl<br>
 HAVE_DFT: INFO: 1/{{.*}} inputs have the Data Flow Trace<br>
<br>
 # Collect DFT, then use it.<br>
-RUN: rm -rf %t/C  && mkdir %t/C &&  cp %t/IN/* %t/C<br>
+RUN: rm -rf %t/C %t/C1  && mkdir %t/C %t/C1 &&  cp %t/IN/* %t/C<br>
 RUN: rm -rf %t/C_DFT && %libfuzzer_src/scripts/collect_data_flow.py %t-DFT %t/C %t/C_DFT > /dev/null 2>&1<br>
-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<br>
+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<br>
+RUN: grep BINGO %t/log<br>
+<br>
+# Test -focus_function=auto: run 50 times and verify that 'f0' is the most frequent focus function.<br>
+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<br>
+AUTOFOCUS: INFO: AUTOFOCUS: {{.*}} f0<br>
+<br>
+# Actually execute 50 fuzzing processes with a small number of runs, to test  -focus_function=auto for real.<br>
+# We can not test data_flow_trace=auto in just a single run, because it may choose to focus on a wrong function.<br>
+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<br>
 RUN: grep BINGO %t/log<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div>