[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