[compiler-rt] e2e38fc - Entropic: Boosting LibFuzzer Performance

Matt Morehouse via llvm-commits llvm-commits at lists.llvm.org
Thu May 21 10:45:51 PDT 2020


Fix in 353e5aa42dfee3f119fd1790509ea35a280295f7

On Wed, May 20, 2020 at 6:43 PM Richard Smith <richard at metafoo.co.uk> wrote:

> On Tue, 19 May 2020 at 10:31, Matt Morehouse via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
>
>>
>> Author: Matt Morehouse
>> Date: 2020-05-19T10:28:57-07:00
>> New Revision: e2e38fca64e49d684de0b100437fe2f227f8fcdd
>>
>> URL:
>> https://github.com/llvm/llvm-project/commit/e2e38fca64e49d684de0b100437fe2f227f8fcdd
>> DIFF:
>> https://github.com/llvm/llvm-project/commit/e2e38fca64e49d684de0b100437fe2f227f8fcdd.diff
>>
>> LOG: Entropic: Boosting LibFuzzer Performance
>>
>> Summary:
>> This is collaboration between Marcel Boehme @ Monash, Australia and
>> Valentin Manès plus Sang Kil Cha @ KAIST, South Korea.
>>
>> We have made a few modifications to boost LibFuzzer performance by
>> changing how weights are assigned to the seeds in the corpus. Essentially,
>> seeds that reveal more "information" about globally rare features are
>> assigned a higher weight. Our results on the Fuzzer Test Suite seem quite
>> promising. In terms of bug finding, our Entropic patch usually finds the
>> same errors much faster and in more runs. In terms of coverage, our version
>> Entropic achieves the same coverage in less than half the time for the
>> majority of subjects. For the lack of space, we shared more detailed
>> performance results directly with @kcc. We'll publish the preprint with all
>> the technical details as soon as it is accepted. Happy to share if you drop
>> us an email.
>>
>> There should be plenty of opportunities to optimise further. For
>> instance, while Entropic achieves the same coverage in less than half the
>> time, Entropic has a much lower #execs per second. We ran the perf-tool and
>> found a few performance bottlenecks.
>>
>> Thanks for open-sourcing LibFuzzer (and the entire LLVM Compiler
>> Infrastructure)! This has been such a tremendous help to my research.
>>
>> Patch By: Marcel Boehme
>>
>> Reviewers: kcc, metzman, morehouse, Dor1s, vitalybuka
>>
>> Reviewed By: kcc
>>
>> Subscribers: dgg5503, Valentin, llvm-commits, kcc
>>
>> Tags: #llvm
>>
>> Differential Revision: https://reviews.llvm.org/D73776
>>
>> Added:
>>
>>
>> Modified:
>>     compiler-rt/lib/fuzzer/FuzzerCorpus.h
>>     compiler-rt/lib/fuzzer/FuzzerDriver.cpp
>>     compiler-rt/lib/fuzzer/FuzzerFlags.def
>>     compiler-rt/lib/fuzzer/FuzzerLoop.cpp
>>     compiler-rt/lib/fuzzer/FuzzerOptions.h
>>     compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp
>>
>> Removed:
>>
>>
>>
>>
>> ################################################################################
>> diff  --git a/compiler-rt/lib/fuzzer/FuzzerCorpus.h
>> b/compiler-rt/lib/fuzzer/FuzzerCorpus.h
>> index 6a95ef3a8e64..54d1e09ec6df 100644
>> --- a/compiler-rt/lib/fuzzer/FuzzerCorpus.h
>> +++ b/compiler-rt/lib/fuzzer/FuzzerCorpus.h
>> @@ -38,12 +38,102 @@ struct InputInfo {
>>    bool HasFocusFunction = false;
>>    Vector<uint32_t> UniqFeatureSet;
>>    Vector<uint8_t> DataFlowTraceForFocusFunction;
>> +  // Power schedule.
>> +  bool NeedsEnergyUpdate = false;
>> +  double Energy = 0.0;
>> +  size_t SumIncidence = 0;
>> +  Vector<std::pair<uint32_t, uint16_t>> FeatureFreqs;
>> +
>> +  // Delete feature Idx and its frequency from FeatureFreqs.
>> +  bool DeleteFeatureFreq(uint32_t Idx) {
>> +    if (FeatureFreqs.empty())
>> +      return false;
>> +
>> +    // Binary search over local feature frequencies sorted by index.
>> +    auto Lower = std::lower_bound(FeatureFreqs.begin(),
>> FeatureFreqs.end(),
>> +                                  std::pair<uint32_t, uint16_t>(Idx, 0));
>> +
>> +    if (Lower != FeatureFreqs.end() && Lower->first == Idx) {
>> +      FeatureFreqs.erase(Lower);
>> +      return true;
>> +    }
>> +    return false;
>> +  }
>> +
>> +  // Assign more energy to a high-entropy seed, i.e., that reveals more
>> +  // information about the globally rare features in the neighborhood
>> +  // of the seed. Since we do not know the entropy of a seed that has
>> +  // never been executed we assign fresh seeds maximum entropy and
>> +  // let II->Energy approach the true entropy from above.
>> +  void UpdateEnergy(size_t GlobalNumberOfFeatures) {
>> +    Energy = 0.0;
>> +    SumIncidence = 0;
>> +
>> +    // Apply add-one smoothing to locally discovered features.
>> +    for (auto F : FeatureFreqs) {
>> +      size_t LocalIncidence = F.second + 1;
>> +      Energy -= LocalIncidence * logl(LocalIncidence);
>> +      SumIncidence += LocalIncidence;
>> +    }
>> +
>> +    // Apply add-one smoothing to locally undiscovered features.
>> +    //   PreciseEnergy -= 0; // since logl(1.0) == 0)
>> +    SumIncidence += (GlobalNumberOfFeatures - FeatureFreqs.size());
>> +
>> +    // Add a single locally abundant feature apply add-one smoothing.
>> +    size_t AbdIncidence = NumExecutedMutations + 1;
>> +    Energy -= AbdIncidence * logl(AbdIncidence);
>> +    SumIncidence += AbdIncidence;
>> +
>> +    // Normalize.
>> +    if (SumIncidence != 0)
>> +      Energy = (Energy / SumIncidence) + logl(SumIncidence);
>> +  }
>> +
>> +  // Increment the frequency of the feature Idx.
>> +  void UpdateFeatureFrequency(uint32_t Idx) {
>> +    NeedsEnergyUpdate = true;
>> +
>> +    // The local feature frequencies is an ordered vector of pairs.
>> +    // If there are no local feature frequencies, push_back preserves
>> order.
>> +    // Set the feature frequency for feature Idx32 to 1.
>> +    if (FeatureFreqs.empty()) {
>> +      FeatureFreqs.push_back(std::pair<uint32_t, uint16_t>(Idx, 1));
>> +      return;
>> +    }
>> +
>> +    // Binary search over local feature frequencies sorted by index.
>> +    auto Lower = std::lower_bound(FeatureFreqs.begin(),
>> FeatureFreqs.end(),
>> +                                  std::pair<uint32_t, uint16_t>(Idx, 0));
>> +
>> +    // If feature Idx32 already exists, increment its frequency.
>> +    // Otherwise, insert a new pair right after the next lower index.
>> +    if (Lower != FeatureFreqs.end() && Lower->first == Idx) {
>> +      Lower->second++;
>> +    } else {
>> +      FeatureFreqs.insert(Lower, std::pair<uint32_t, uint16_t>(Idx, 1));
>> +    }
>> +  }
>> +};
>> +
>> +struct EntropicOptions {
>> +  bool Enabled;
>> +  size_t NumberOfRarestFeatures;
>> +  size_t FeatureFrequencyThreshold;
>>  };
>>
>>  class InputCorpus {
>> -  static const size_t kFeatureSetSize = 1 << 21;
>> - public:
>> -  InputCorpus(const std::string &OutputCorpus) :
>> OutputCorpus(OutputCorpus) {
>> +  static const uint32_t kFeatureSetSize = 1 << 21;
>> +  static const uint8_t kMaxMutationFactor = 20;
>> +  static const size_t kSparseEnergyUpdates = 100;
>> +
>> +  size_t NumExecutedMutations = 0;
>> +
>> +  EntropicOptions Entropic;
>> +
>> +public:
>> +  InputCorpus(const std::string &OutputCorpus, EntropicOptions Entropic)
>> +      : Entropic(Entropic), OutputCorpus(OutputCorpus) {
>>      memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature));
>>      memset(SmallestElementPerFeature, 0,
>> sizeof(SmallestElementPerFeature));
>>    }
>> @@ -70,6 +160,7 @@ class InputCorpus {
>>          Res = std::max(Res, II->U.size());
>>      return Res;
>>    }
>> +  void IncrementNumExecutedMutations() { NumExecutedMutations++; }
>>
>>    size_t NumInputsThatTouchFocusFunction() {
>>      return std::count_if(Inputs.begin(), Inputs.end(), [](const
>> InputInfo *II) {
>> @@ -99,6 +190,10 @@ class InputCorpus {
>>      II.MayDeleteFile = MayDeleteFile;
>>      II.UniqFeatureSet = FeatureSet;
>>      II.HasFocusFunction = HasFocusFunction;
>> +    // Assign maximal energy to the new seed.
>> +    II.Energy = RareFeatures.empty() ? 1.0 : log(RareFeatures.size());
>> +    II.SumIncidence = RareFeatures.size();
>> +    II.NeedsEnergyUpdate = false;
>>      std::sort(II.UniqFeatureSet.begin(), II.UniqFeatureSet.end());
>>      ComputeSHA1(U.data(), U.size(), II.Sha1);
>>      auto Sha1Str = Sha1ToString(II.Sha1);
>> @@ -111,7 +206,7 @@ class InputCorpus {
>>      // But if we don't, we'll use the DFT of its base input.
>>      if (II.DataFlowTraceForFocusFunction.empty() && BaseII)
>>        II.DataFlowTraceForFocusFunction =
>> BaseII->DataFlowTraceForFocusFunction;
>> -    UpdateCorpusDistribution();
>> +    DistributionNeedsUpdate = true;
>>      PrintCorpus();
>>      // ValidateFeatureSet();
>>      return &II;
>> @@ -162,7 +257,7 @@ class InputCorpus {
>>      Hashes.insert(Sha1ToString(II->Sha1));
>>      II->U = U;
>>      II->Reduced = true;
>> -    UpdateCorpusDistribution();
>> +    DistributionNeedsUpdate = true;
>>    }
>>
>>    bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); }
>> @@ -175,6 +270,7 @@ class InputCorpus {
>>
>>    // Returns an index of random unit from the corpus to mutate.
>>    size_t ChooseUnitIdxToMutate(Random &Rand) {
>> +    UpdateCorpusDistribution(Rand);
>>      size_t Idx = static_cast<size_t>(CorpusDistribution(Rand));
>>      assert(Idx < Inputs.size());
>>      return Idx;
>> @@ -210,10 +306,65 @@ class InputCorpus {
>>      InputInfo &II = *Inputs[Idx];
>>      DeleteFile(II);
>>      Unit().swap(II.U);
>> +    II.Energy = 0.0;
>> +    II.NeedsEnergyUpdate = false;
>> +    DistributionNeedsUpdate = true;
>>      if (FeatureDebug)
>>        Printf("EVICTED %zd\n", Idx);
>>    }
>>
>> +  void AddRareFeature(uint32_t Idx) {
>> +    // Maintain *at least* TopXRarestFeatures many rare features
>> +    // and all features with a frequency below ConsideredRare.
>> +    // Remove all other features.
>> +    while (RareFeatures.size() > Entropic.NumberOfRarestFeatures &&
>> +           FreqOfMostAbundantRareFeature >
>> Entropic.FeatureFrequencyThreshold) {
>> +
>> +      // Find most and second most abbundant feature.
>> +      uint32_t MostAbundantRareFeatureIndices[2] = {RareFeatures[0],
>> +                                                    RareFeatures[0]};
>> +      size_t Delete = 0;
>> +      for (size_t i = 0; i < RareFeatures.size(); i++) {
>> +        uint32_t Idx2 = RareFeatures[i];
>> +        if (GlobalFeatureFreqs[Idx2] >=
>> +            GlobalFeatureFreqs[MostAbundantRareFeatureIndices[0]]) {
>> +          MostAbundantRareFeatureIndices[1] =
>> MostAbundantRareFeatureIndices[0];
>> +          MostAbundantRareFeatureIndices[0] = Idx2;
>> +          Delete = i;
>> +        }
>> +      }
>> +
>> +      // Remove most abundant rare feature.
>> +      RareFeatures[Delete] = RareFeatures.back();
>> +      RareFeatures.pop_back();
>> +
>> +      for (auto II : Inputs) {
>> +        if (II->DeleteFeatureFreq(MostAbundantRareFeatureIndices[0]))
>> +          II->NeedsEnergyUpdate = true;
>> +      }
>> +
>> +      // Set 2nd most abundant as the new most abundant feature count.
>> +      FreqOfMostAbundantRareFeature =
>> +          GlobalFeatureFreqs[MostAbundantRareFeatureIndices[1]];
>> +    }
>> +
>> +    // Add rare feature, handle collisions, and update energy.
>> +    RareFeatures.push_back(Idx);
>> +    GlobalFeatureFreqs[Idx] = 0;
>> +    for (auto II : Inputs) {
>> +      II->DeleteFeatureFreq(Idx);
>> +
>> +      // Apply add-one smoothing to this locally undiscovered feature.
>> +      // Zero energy seeds will never be fuzzed and remain zero energy.
>> +      if (II->Energy > 0.0) {
>> +        II->SumIncidence += 1;
>> +        II->Energy += logl(II->SumIncidence) / II->SumIncidence;
>> +      }
>> +    }
>> +
>> +    DistributionNeedsUpdate = true;
>> +  }
>> +
>>    bool AddFeature(size_t Idx, uint32_t NewSize, bool Shrink) {
>>      assert(NewSize);
>>      Idx = Idx % kFeatureSetSize;
>> @@ -228,6 +379,8 @@ class InputCorpus {
>>            DeleteInput(OldIdx);
>>        } else {
>>          NumAddedFeatures++;
>> +        if (Entropic.Enabled)
>> +          AddRareFeature((uint32_t)Idx);
>>        }
>>        NumUpdatedFeatures++;
>>        if (FeatureDebug)
>> @@ -239,6 +392,30 @@ class InputCorpus {
>>      return false;
>>    }
>>
>> +  // Increment frequency of feature Idx globally and locally.
>> +  void UpdateFeatureFrequency(InputInfo *II, size_t Idx) {
>> +    uint32_t Idx32 = Idx % kFeatureSetSize;
>> +
>> +    // Saturated increment.
>> +    if (GlobalFeatureFreqs[Idx32] == 0xFFFF)
>> +      return;
>> +    uint16_t Freq = GlobalFeatureFreqs[Idx32]++;
>> +
>> +    // Skip if abundant.
>> +    if (Freq > FreqOfMostAbundantRareFeature ||
>> +        std::find(RareFeatures.begin(), RareFeatures.end(), Idx32) ==
>> +            RareFeatures.end())
>> +      return;
>> +
>> +    // Update global frequencies.
>> +    if (Freq == FreqOfMostAbundantRareFeature)
>> +      FreqOfMostAbundantRareFeature++;
>> +
>> +    // Update local frequencies.
>> +    if (II)
>> +      II->UpdateFeatureFrequency(Idx32);
>> +  }
>> +
>>    size_t NumFeatures() const { return NumAddedFeatures; }
>>    size_t NumFeatureUpdates() const { return NumUpdatedFeatures; }
>>
>> @@ -265,19 +442,60 @@ class InputCorpus {
>>    // Updates the probability distribution for the units in the corpus.
>>    // Must be called whenever the corpus or unit weights are changed.
>>    //
>> -  // Hypothesis: units added to the corpus last are more interesting.
>> -  //
>> -  // Hypothesis: inputs with infrequent features are more interesting.
>> -  void UpdateCorpusDistribution() {
>> +  // Hypothesis: inputs that maximize information about globally rare
>> features
>> +  // are interesting.
>> +  void UpdateCorpusDistribution(Random &Rand) {
>> +    // Skip update if no seeds or rare features were added/deleted.
>> +    // Sparse updates for local change of feature frequencies,
>> +    // i.e., randomly do not skip.
>> +    if (!DistributionNeedsUpdate &&
>> +        (!Entropic.Enabled || Rand(kSparseEnergyUpdates)))
>> +      return;
>> +
>> +    DistributionNeedsUpdate = false;
>> +
>>      size_t N = Inputs.size();
>>      assert(N);
>>      Intervals.resize(N + 1);
>>      Weights.resize(N);
>>      std::iota(Intervals.begin(), Intervals.end(), 0);
>> -    for (size_t i = 0; i < N; i++)
>> -      Weights[i] = Inputs[i]->NumFeatures
>> -                       ? (i + 1) * (Inputs[i]->HasFocusFunction ? 1000 :
>> 1)
>> -                       : 0.;
>> +
>> +    bool VanillaSchedule = true;
>> +    if (Entropic.Enabled) {
>> +      for (auto II : Inputs) {
>> +        if (II->NeedsEnergyUpdate && II->Energy != 0.0) {
>> +          II->NeedsEnergyUpdate = false;
>> +          II->UpdateEnergy(RareFeatures.size());
>> +        }
>> +      }
>> +
>> +      for (size_t i = 0; i < N; i++) {
>> +
>> +        if (Inputs[i]->NumFeatures == 0) {
>> +          // If the seed doesn't represent any features, assign zero
>> energy.
>> +          Weights[i] = 0.;
>> +        } else if (Inputs[i]->NumExecutedMutations / kMaxMutationFactor >
>> +                   NumExecutedMutations / Inputs.size()) {
>> +          // If the seed was fuzzed a lot more than average, assign zero
>> energy.
>> +          Weights[i] = 0.;
>> +        } else {
>> +          // Otherwise, simply assign the computed energy.
>> +          Weights[i] = Inputs[i]->Energy;
>> +        }
>> +
>> +        // If energy for all seeds is zero, fall back to vanilla
>> schedule.
>> +        if (Weights[i] > 0.0)
>> +          VanillaSchedule = false;
>> +      }
>> +    }
>> +
>> +    if (VanillaSchedule) {
>> +      for (size_t i = 0; i < N; i++)
>> +        Weights[i] = Inputs[i]->NumFeatures
>> +                         ? (i + 1) * (Inputs[i]->HasFocusFunction ? 1000
>> : 1)
>> +                         : 0.;
>> +    }
>> +
>>      if (FeatureDebug) {
>>        for (size_t i = 0; i < N; i++)
>>          Printf("%zd ", Inputs[i]->NumFeatures);
>> @@ -302,6 +520,11 @@ class InputCorpus {
>>    uint32_t InputSizesPerFeature[kFeatureSetSize];
>>    uint32_t SmallestElementPerFeature[kFeatureSetSize];
>>
>> +  bool DistributionNeedsUpdate = true;
>> +  uint16_t FreqOfMostAbundantRareFeature = 0;
>> +  uint16_t GlobalFeatureFreqs[kFeatureSetSize] = {};
>> +  Vector<uint32_t> RareFeatures;
>> +
>>    std::string OutputCorpus;
>>  };
>>
>>
>> diff  --git a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp
>> b/compiler-rt/lib/fuzzer/FuzzerDriver.cpp
>> index 0d4e468a674b..1a0b2580c5b7 100644
>> --- a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp
>> +++ b/compiler-rt/lib/fuzzer/FuzzerDriver.cpp
>> @@ -708,6 +708,26 @@ int FuzzerDriver(int *argc, char ***argv,
>> UserCallback Callback) {
>>      Options.CollectDataFlow = Flags.collect_data_flow;
>>    if (Flags.stop_file)
>>      Options.StopFile = Flags.stop_file;
>> +  Options.Entropic = Flags.entropic;
>> +  Options.EntropicFeatureFrequencyThreshold =
>> +      (size_t)Flags.entropic_feature_frequency_threshold;
>> +  Options.EntropicNumberOfRarestFeatures =
>> +      (size_t)Flags.entropic_number_of_rarest_features;
>> +  if (Options.Entropic) {
>> +    if (!Options.FocusFunction.empty()) {
>> +      Printf("ERROR: The parameters `--entropic` and `--focus_function`
>> cannot "
>> +             "be used together.\n");
>> +      exit(1);
>> +    }
>> +    Printf("INFO: Running with entropic power schedule (0x%X, %d).\n",
>> +           Options.EntropicFeatureFrequencyThreshold,
>> +           Options.EntropicNumberOfRarestFeatures);
>> +  }
>> +  struct EntropicOptions Entropic;
>> +  Entropic.Enabled = Options.Entropic;
>> +  Entropic.FeatureFrequencyThreshold =
>> +      Options.EntropicFeatureFrequencyThreshold;
>> +  Entropic.NumberOfRarestFeatures =
>> Options.EntropicNumberOfRarestFeatures;
>>
>>    unsigned Seed = Flags.seed;
>>    // Initialize Seed.
>> @@ -728,7 +748,7 @@ int FuzzerDriver(int *argc, char ***argv,
>> UserCallback Callback) {
>>
>>    Random Rand(Seed);
>>    auto *MD = new MutationDispatcher(Rand, Options);
>> -  auto *Corpus = new InputCorpus(Options.OutputCorpus);
>> +  auto *Corpus = new InputCorpus(Options.OutputCorpus, Entropic);
>>    auto *F = new Fuzzer(Callback, *Corpus, *MD, Options);
>>
>>    for (auto &U: Dictionary)
>>
>> diff  --git a/compiler-rt/lib/fuzzer/FuzzerFlags.def
>> b/compiler-rt/lib/fuzzer/FuzzerFlags.def
>> index d2aaf24587d2..832224a705d2 100644
>> --- a/compiler-rt/lib/fuzzer/FuzzerFlags.def
>> +++ b/compiler-rt/lib/fuzzer/FuzzerFlags.def
>> @@ -153,6 +153,14 @@ FUZZER_FLAG_STRING(focus_function, "Experimental. "
>>       "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(entropic, 0, "Experimental. Enables entropic power
>> schedule.")
>> +FUZZER_FLAG_INT(entropic_feature_frequency_threshold, 0xFF,
>> "Experimental. If "
>> +     "entropic is enabled, all features which are observed less often
>> than "
>> +     "the specified value are considered as rare.")
>> +FUZZER_FLAG_INT(entropic_number_of_rarest_features, 100, "Experimental.
>> If "
>> +     "entropic is enabled, we keep track of the frequencies only for the
>> "
>> +     "Top-X least abundant features (union features that are considered
>> as "
>> +     "rare).")
>>
>>  FUZZER_FLAG_INT(analyze_dict, 0, "Experimental")
>>  FUZZER_DEPRECATED_FLAG(use_clang_coverage)
>>
>> diff  --git a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp
>> b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp
>> index 273c62919e89..7c3288fc5750 100644
>> --- a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp
>> +++ b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp
>> @@ -475,6 +475,8 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size,
>> bool MayDeleteFile,
>>    TPC.CollectFeatures([&](size_t Feature) {
>>      if (Corpus.AddFeature(Feature, Size, Options.Shrink))
>>        UniqFeatureSetTmp.push_back(Feature);
>> +    if (Options.Entropic)
>> +      Corpus.UpdateFeatureFrequency(II, Feature);
>>      if (Options.ReduceInputs && II)
>>        if (std::binary_search(II->UniqFeatureSet.begin(),
>>                               II->UniqFeatureSet.end(), Feature))
>> @@ -693,6 +695,7 @@ void Fuzzer::MutateAndTestOne() {
>>      assert(NewSize <= CurrentMaxMutationLen && "Mutator return oversized
>> unit");
>>      Size = NewSize;
>>      II.NumExecutedMutations++;
>> +    Corpus.IncrementNumExecutedMutations();
>>
>>      bool FoundUniqFeatures = false;
>>      bool NewCov = RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true,
>> &II,
>> @@ -706,6 +709,8 @@ void Fuzzer::MutateAndTestOne() {
>>      if (Options.ReduceDepth && !FoundUniqFeatures)
>>        break;
>>    }
>> +
>> +  II.NeedsEnergyUpdate = true;
>>  }
>>
>>  void Fuzzer::PurgeAllocator() {
>>
>> diff  --git a/compiler-rt/lib/fuzzer/FuzzerOptions.h
>> b/compiler-rt/lib/fuzzer/FuzzerOptions.h
>> index beecc980380b..9d975bd61fe7 100644
>> --- a/compiler-rt/lib/fuzzer/FuzzerOptions.h
>> +++ b/compiler-rt/lib/fuzzer/FuzzerOptions.h
>> @@ -44,6 +44,9 @@ struct FuzzingOptions {
>>    size_t MaxNumberOfRuns = -1L;
>>    int ReportSlowUnits = 10;
>>    bool OnlyASCII = false;
>> +  bool Entropic = false;
>> +  size_t EntropicFeatureFrequencyThreshold = 0xFF;
>> +  size_t EntropicNumberOfRarestFeatures = 100;
>>    std::string OutputCorpus;
>>    std::string ArtifactPrefix = "./";
>>    std::string ExactArtifactPath;
>>
>> diff  --git a/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp
>> b/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp
>> index 7fc4b9a55b08..b480e9f0fff5 100644
>> --- a/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp
>> +++ b/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp
>> @@ -592,7 +592,8 @@ TEST(FuzzerUtil, Base64) {
>>  TEST(Corpus, Distribution) {
>>    DataFlowTrace DFT;
>>    Random Rand(0);
>> -  std::unique_ptr<InputCorpus> C(new InputCorpus(""));
>> +  struct EntropicOptions Entropic = {false, 0xFF, 100};
>> +  std::unique_ptr<InputCorpus> C(new InputCorpus("", Entropic));
>>    size_t N = 10;
>>    size_t TriesPerUnit = 1<<16;
>>    for (size_t i = 0; i < N; i++)
>> @@ -1050,6 +1051,68 @@ TEST(FuzzerCommand, SetOutput) {
>>    EXPECT_EQ(CmdLine, makeCmdLine("", ">thud 2>&1"));
>>  }
>>
>> +TEST(Entropic, UpdateFrequency) {
>> +  const size_t One = 1, Two = 2;
>> +  const size_t FeatIdx1 = 0, FeatIdx2 = 42, FeatIdx3 = 12, FeatIdx4 = 26;
>> +  size_t Index;
>> +  // Create input corpus with default entropic configuration
>> +  struct EntropicOptions Entropic = {true, 0xFF, 100};
>> +  std::unique_ptr<InputCorpus> C(new InputCorpus("", Entropic));
>> +  InputInfo *II = new InputInfo();
>>
>
> This is leaked.
>
>
>> +
>> +  C->AddRareFeature(FeatIdx1);
>> +  C->UpdateFeatureFrequency(II, FeatIdx1);
>> +  EXPECT_EQ(II->FeatureFreqs.size(), One);
>> +  C->AddRareFeature(FeatIdx2);
>> +  C->UpdateFeatureFrequency(II, FeatIdx1);
>> +  C->UpdateFeatureFrequency(II, FeatIdx2);
>> +  EXPECT_EQ(II->FeatureFreqs.size(), Two);
>> +  EXPECT_EQ(II->FeatureFreqs[0].second, 2);
>> +  EXPECT_EQ(II->FeatureFreqs[1].second, 1);
>> +
>> +  C->AddRareFeature(FeatIdx3);
>> +  C->AddRareFeature(FeatIdx4);
>> +  C->UpdateFeatureFrequency(II, FeatIdx3);
>> +  C->UpdateFeatureFrequency(II, FeatIdx3);
>> +  C->UpdateFeatureFrequency(II, FeatIdx3);
>> +  C->UpdateFeatureFrequency(II, FeatIdx4);
>> +
>> +  for (Index = 1; Index < II->FeatureFreqs.size(); Index++)
>> +    EXPECT_LT(II->FeatureFreqs[Index - 1].first,
>> II->FeatureFreqs[Index].first);
>> +
>> +  II->DeleteFeatureFreq(FeatIdx3);
>> +  for (Index = 1; Index < II->FeatureFreqs.size(); Index++)
>> +    EXPECT_LT(II->FeatureFreqs[Index - 1].first,
>> II->FeatureFreqs[Index].first);
>> +}
>> +
>> +double SubAndSquare(double X, double Y) {
>> +  double R = X - Y;
>> +  R = R * R;
>> +  return R;
>> +}
>> +
>> +TEST(Entropic, ComputeEnergy) {
>> +  const double Precision = 0.01;
>> +  struct EntropicOptions Entropic = {true, 0xFF, 100};
>> +  std::unique_ptr<InputCorpus> C(new InputCorpus("", Entropic));
>> +  InputInfo *II = new InputInfo();
>>
>
> As is this. Please can you fix or revert?
>
>
>> +  Vector<std::pair<uint32_t, uint16_t>> FeatureFreqs = {{1, 3}, {2, 3},
>> {3, 3}};
>> +  II->FeatureFreqs = FeatureFreqs;
>> +  II->NumExecutedMutations = 0;
>> +  II->UpdateEnergy(4);
>> +  EXPECT_LT(SubAndSquare(II->Energy, 1.450805), Precision);
>> +
>> +  II->NumExecutedMutations = 9;
>> +  II->UpdateEnergy(5);
>> +  EXPECT_LT(SubAndSquare(II->Energy, 1.525496), Precision);
>> +
>> +  II->FeatureFreqs[0].second++;
>> +  II->FeatureFreqs.push_back(std::pair<uint32_t, uint16_t>(42, 6));
>> +  II->NumExecutedMutations = 20;
>> +  II->UpdateEnergy(10);
>> +  EXPECT_LT(SubAndSquare(II->Energy, 1.792831), Precision);
>> +}
>> +
>>  int main(int argc, char **argv) {
>>    testing::InitGoogleTest(&argc, argv);
>>    return RUN_ALL_TESTS();
>>
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20200521/9b919ff3/attachment.html>


More information about the llvm-commits mailing list