[libFuzzer] Mutation tracking and logging implemented
Code now exists to track number of mutations that are used in fuzzing in
total and ones that produce new coverage. The stats are currently being
dumped to the command line.
Patch By: Kode Williams
Differntial Revision: https://reviews.llvm.org/D48054
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer@336597 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/FuzzerMutate.cpp b/FuzzerMutate.cpp
index 865e598..ef059fc 100644
--- a/FuzzerMutate.cpp
+++ b/FuzzerMutate.cpp
@@ -58,6 +58,10 @@
if (EF->LLVMFuzzerCustomCrossOver)
Mutators.push_back(
{&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"});
+
+ // Initialize mutation statistic counters.
+ TotalMutations.resize(Mutators.size(), 0);
+ UsefulMutations.resize(Mutators.size(), 0);
}
static char RandCh(Random &Rand) {
@@ -261,9 +265,9 @@
DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
} break;
case 3: if (Options.UseMemmem) {
- auto X = TPC.MMT.Get(Rand.Rand());
- DE = DictionaryEntry(X);
- } break;
+ auto X = TPC.MMT.Get(Rand.Rand());
+ DE = DictionaryEntry(X);
+ } break;
default:
assert(0);
}
@@ -431,18 +435,18 @@
auto &U = MutateInPlaceHere;
size_t NewSize = 0;
switch(Rand(3)) {
- case 0:
- NewSize = CrossOver(Data, Size, O.data(), O.size(), U.data(), U.size());
- break;
- case 1:
- NewSize = InsertPartOf(O.data(), O.size(), U.data(), U.size(), MaxSize);
- if (!NewSize)
- NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size());
- break;
- case 2:
+ case 0:
+ NewSize = CrossOver(Data, Size, O.data(), O.size(), U.data(), U.size());
+ break;
+ case 1:
+ NewSize = InsertPartOf(O.data(), O.size(), U.data(), U.size(), MaxSize);
+ if (!NewSize)
NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size());
- break;
- default: assert(0);
+ break;
+ case 2:
+ NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size());
+ break;
+ default: assert(0);
}
assert(NewSize > 0 && "CrossOver returned empty unit");
assert(NewSize <= MaxSize && "CrossOver returned overisized unit");
@@ -451,7 +455,7 @@
}
void MutationDispatcher::StartMutationSequence() {
- CurrentMutatorSequence.clear();
+ CurrentMutatorIdxSequence.clear();
CurrentDictionaryEntrySequence.clear();
}
@@ -465,6 +469,7 @@
if (!PersistentAutoDictionary.ContainsWord(DE->GetW()))
PersistentAutoDictionary.push_back({DE->GetW(), 1});
}
+ RecordUsefulMutations();
}
void MutationDispatcher::PrintRecommendedDictionary() {
@@ -484,9 +489,9 @@
}
void MutationDispatcher::PrintMutationSequence() {
- Printf("MS: %zd ", CurrentMutatorSequence.size());
- for (auto M : CurrentMutatorSequence)
- Printf("%s-", M.Name);
+ Printf("MS: %zd ", CurrentMutatorIdxSequence.size());
+ for (auto M : CurrentMutatorIdxSequence)
+ Printf("%s-", Mutators[M].Name);
if (!CurrentDictionaryEntrySequence.empty()) {
Printf(" DE: ");
for (auto DE : CurrentDictionaryEntrySequence) {
@@ -514,12 +519,14 @@
// in which case they will return 0.
// Try several times before returning un-mutated data.
for (int Iter = 0; Iter < 100; Iter++) {
- auto M = Mutators[Rand(Mutators.size())];
+ size_t MutatorIdx = Rand(Mutators.size());
+ auto M = Mutators[MutatorIdx];
size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);
if (NewSize && NewSize <= MaxSize) {
if (Options.OnlyASCII)
ToASCII(Data, NewSize);
- CurrentMutatorSequence.push_back(M);
+ CurrentMutatorIdxSequence.push_back(MutatorIdx);
+ TotalMutations[MutatorIdx]++;
return NewSize;
}
}
@@ -532,4 +539,23 @@
{W, std::numeric_limits<size_t>::max()});
}
+void MutationDispatcher::RecordUsefulMutations() {
+ for (const size_t M : CurrentMutatorIdxSequence)
+ UsefulMutations[M]++;
+}
+
+void MutationDispatcher::PrintMutationStats() {
+ Printf("\nstat::mutation_usefulness: ");
+ for (size_t i = 0; i < Mutators.size(); i++) {
+ double UsefulPercentage =
+ TotalMutations[i]
+ ? (100.0 * UsefulMutations[i]) / TotalMutations[i]
+ : 0;
+ Printf("%.3f", UsefulPercentage);
+ if (i < Mutators.size() - 1)
+ Printf(",");
+ }
+ Printf("\n");
+}
+
} // namespace fuzzer