diff options
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerCorpus.h | 17 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.cpp | 1 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.h | 18 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerLoop.cpp | 7 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp | 3 | ||||
| -rw-r--r-- | compiler-rt/test/fuzzer/only-some-bytes.test | 31 | 
6 files changed, 72 insertions, 5 deletions
diff --git a/compiler-rt/lib/fuzzer/FuzzerCorpus.h b/compiler-rt/lib/fuzzer/FuzzerCorpus.h index b4ba64b4b02..c1603e1ad3c 100644 --- a/compiler-rt/lib/fuzzer/FuzzerCorpus.h +++ b/compiler-rt/lib/fuzzer/FuzzerCorpus.h @@ -12,6 +12,7 @@  #ifndef LLVM_FUZZER_CORPUS  #define LLVM_FUZZER_CORPUS +#include "FuzzerDataFlowTrace.h"  #include "FuzzerDefs.h"  #include "FuzzerIO.h"  #include "FuzzerRandom.h" @@ -37,6 +38,7 @@ struct InputInfo {    bool Reduced = false;    bool HasFocusFunction = false;    Vector<uint32_t> UniqFeatureSet; +  Vector<bool> DataFlowTraceForFocusFunction;  };  class InputCorpus { @@ -76,10 +78,17 @@ class InputCorpus {      });    } +  size_t NumInputsWithDataFlowTrace() { +    return std::count_if(Inputs.begin(), Inputs.end(), [](const InputInfo *II) { +      return !II->DataFlowTraceForFocusFunction.empty(); +    }); +  } +    bool empty() const { return Inputs.empty(); }    const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; }    void AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile, -                   bool HasFocusFunction, const Vector<uint32_t> &FeatureSet) { +                   bool HasFocusFunction, const Vector<uint32_t> &FeatureSet, +                   const DataFlowTrace &DFT) {      assert(!U.empty());      if (FeatureDebug)        Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures); @@ -92,7 +101,11 @@ class InputCorpus {      II.HasFocusFunction = HasFocusFunction;      std::sort(II.UniqFeatureSet.begin(), II.UniqFeatureSet.end());      ComputeSHA1(U.data(), U.size(), II.Sha1); -    Hashes.insert(Sha1ToString(II.Sha1)); +    auto Sha1Str = Sha1ToString(II.Sha1); +    Hashes.insert(Sha1Str); +    if (HasFocusFunction) +      if (auto V = DFT.Get(Sha1Str)) +        II.DataFlowTraceForFocusFunction = *V;      UpdateCorpusDistribution();      PrintCorpus();      // ValidateFeatureSet(); diff --git a/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.cpp b/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.cpp index 69efd6f38b5..114034c5b42 100644 --- a/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.cpp @@ -73,6 +73,7 @@ void DataFlowTrace::Init(const std::string &DirPath,              ParseError("the trace should contain only 0 or 1");            V[I] = Beg[I] == '1';          } +        Traces[Name] = V;          // Print just a few small traces.          if (NumTracesWithFocusFunction <= 3 && Len <= 16)            Printf("%s => |%s|\n", Name.c_str(), L.c_str() + SpacePos + 1); diff --git a/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.h b/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.h index 2b7b71fdbfa..1511430c354 100644 --- a/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.h +++ b/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.h @@ -31,9 +31,25 @@  #include "FuzzerDefs.h" +#include <unordered_map> +#include <vector> +#include <string> +  namespace fuzzer { -struct DataFlowTrace { +class DataFlowTrace { + public:    void Init(const std::string &DirPath, const std::string &FocusFunction); +  void Clear() { Traces.clear(); } +  const Vector<bool> *Get(const std::string &InputSha1) const { +    auto It = Traces.find(InputSha1); +    if (It != Traces.end()) +      return &It->second; +    return nullptr; +  } + + private: +  // Input's sha1 => DFT for the FocusFunction. +  std::unordered_map<std::string, Vector<bool> > Traces;  };  }  // namespace fuzzer diff --git a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp index a195d21d38c..346f90e6ed9 100644 --- a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp @@ -469,10 +469,11 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,      TPC.UpdateObservedPCs();      Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile,                         TPC.ObservedFocusFunction(), -                       UniqFeatureSetTmp); +                       UniqFeatureSetTmp, DFT);      return true;    }    if (II && FoundUniqFeaturesOfII && +      II->DataFlowTraceForFocusFunction.empty() &&        FoundUniqFeaturesOfII == II->UniqFeatureSet.size() &&        II->U.size() > Size) {      Corpus.Replace(II, {Data, Data + Size}); @@ -739,6 +740,9 @@ void Fuzzer::ReadAndExecuteSeedCorpora(const Vector<std::string> &CorpusDirs) {    if (!Options.FocusFunction.empty())      Printf("INFO: %zd/%zd inputs touch the focus function\n",             Corpus.NumInputsThatTouchFocusFunction(), Corpus.size()); +  if (!Options.DataFlowTrace.empty()) +    Printf("INFO: %zd/%zd inputs have the Data Flow Trace\n", +           Corpus.NumInputsWithDataFlowTrace(), Corpus.size());    if (Corpus.empty() && Options.MaxNumberOfRuns) {      Printf("ERROR: no interesting inputs were found. " @@ -749,6 +753,7 @@ void Fuzzer::ReadAndExecuteSeedCorpora(const Vector<std::string> &CorpusDirs) {  void Fuzzer::Loop(const Vector<std::string> &CorpusDirs) {    ReadAndExecuteSeedCorpora(CorpusDirs); +  DFT.Clear();  // No need for DFT any more.    TPC.SetPrintNewPCs(Options.PrintNewCovPcs);    TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs);    system_clock::time_point LastCorpusReload = system_clock::now(); diff --git a/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp b/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp index 0b8673876a9..1b3a0934a68 100644 --- a/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp +++ b/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp @@ -582,12 +582,13 @@ TEST(FuzzerUtil, Base64) {  }  TEST(Corpus, Distribution) { +  DataFlowTrace DFT;    Random Rand(0);    std::unique_ptr<InputCorpus> C(new InputCorpus(""));    size_t N = 10;    size_t TriesPerUnit = 1<<16;    for (size_t i = 0; i < N; i++) -    C->AddToCorpus(Unit{ static_cast<uint8_t>(i) }, 1, false, false, {}); +    C->AddToCorpus(Unit{ static_cast<uint8_t>(i) }, 1, false, false, {}, DFT);    Vector<size_t> Hist(N);    for (size_t i = 0; i < N * TriesPerUnit; i++) { diff --git a/compiler-rt/test/fuzzer/only-some-bytes.test b/compiler-rt/test/fuzzer/only-some-bytes.test new file mode 100644 index 00000000000..5301d25364a --- /dev/null +++ b/compiler-rt/test/fuzzer/only-some-bytes.test @@ -0,0 +1,31 @@ +# Tests the data flow tracer. +REQUIRES: linux + +# Build the tracer and the test. +RUN: %no_fuzzer_cpp_compiler -c -fno-sanitize=all -fsanitize=dataflow  %S/../../lib/fuzzer/dataflow/DataFlow.cpp -o  %t-DataFlow.o +RUN: %no_fuzzer_cpp_compiler    -fno-sanitize=all -fsanitize=dataflow -fsanitize-coverage=trace-pc-guard,pc-table,func,trace-cmp   %S/OnlySomeBytesTest.cpp     %t-DataFlow.o -o %t-DFT +RUN: %cpp_compiler %S/OnlySomeBytesTest.cpp -o %t-Fuzz + +# Prepare the inputs. +RUN: rm -rf %t/IN +RUN: mkdir -p %t/IN +RUN: echo -n 0123456789012345678901234567890123456789012345678901234567891234 > %t/IN/6 +RUN: cat  %t/IN/6 %t/IN/6 %t/IN/6 %t/IN/6 > %t/IN/8 +RUN: cat  %t/IN/8 %t/IN/8 %t/IN/8 %t/IN/8 > %t/IN/10 +RUN: cat  %t/IN/10 %t/IN/10 %t/IN/10 %t/IN/10 > %t/IN/12 +# %t/IN/12 is 4096 bytes-long. + +RUN: %t-Fuzz -focus_function=f0 -runs=0 %t/IN 2>&1 | FileCheck %s --check-prefix=NO_FOCUSED_INPUT +NO_FOCUSED_INPUT: INFO: 0/2 inputs touch the focus function + +RUN: (echo -n ABC; cat %t/IN/12) > %t/IN/ABC +RUN: %t-Fuzz -focus_function=f0 -runs=0 %t/IN 2>&1 | FileCheck %s --check-prefix=ONE_FOCUSED_INPUT +ONE_FOCUSED_INPUT: INFO: 1/3 inputs touch the focus function + +RUN: rm -rf %t/DFT_DIR +RUN: %libfuzzer_src/scripts/collect_data_flow.py %t-DFT %t/IN %t/DFT_DIR + +# Repat twice to make sure that the inputs with DFT are not removed from the corpus. +RUN: %t-Fuzz -focus_function=f0 -data_flow_trace=%t/DFT_DIR -runs=100 %t/IN 2>&1 | FileCheck %s --check-prefix=HAVE_DFT +RUN: %t-Fuzz -focus_function=f0 -data_flow_trace=%t/DFT_DIR -runs=100 %t/IN 2>&1 | FileCheck %s --check-prefix=HAVE_DFT +HAVE_DFT: INFO: 1/{{.*}} inputs have the Data Flow Trace  | 

