5 changes: 5 additions & 0 deletions compiler-rt/lib/fuzzer/FuzzerLoop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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,
Expand All @@ -706,6 +709,8 @@ void Fuzzer::MutateAndTestOne() {
if (Options.ReduceDepth && !FoundUniqFeatures)
break;
}

II.NeedsEnergyUpdate = true;
}

void Fuzzer::PurgeAllocator() {
Expand Down
3 changes: 3 additions & 0 deletions compiler-rt/lib/fuzzer/FuzzerOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
65 changes: 64 additions & 1 deletion compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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++)
Expand Down Expand Up @@ -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();

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();
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();
Expand Down