Index: FuzzerDriver.cpp =================================================================== --- FuzzerDriver.cpp +++ FuzzerDriver.cpp @@ -613,6 +613,7 @@ Options.PrintNewCovPcs = Flags.print_pcs; Options.PrintNewCovFuncs = Flags.print_funcs; Options.PrintFinalStats = Flags.print_final_stats; + Options.PrintMutationStats = Flags.print_mutation_stats; Options.PrintCorpusStats = Flags.print_corpus_stats; Options.PrintCoverage = Flags.print_coverage; Options.DumpCoverage = Flags.dump_coverage; Index: FuzzerFlags.def =================================================================== --- FuzzerFlags.def +++ FuzzerFlags.def @@ -151,3 +151,6 @@ FUZZER_FLAG_INT(analyze_dict, 0, "Experimental") FUZZER_FLAG_INT(use_clang_coverage, 0, "Experimental") FUZZER_FLAG_INT(use_feature_frequency, 0, "Experimental/internal") + +// Mutation Stats Change +FUZZER_FLAG_INT(print_mutation_stats, 0, "Experimental") Index: FuzzerLoop.cpp =================================================================== --- FuzzerLoop.cpp +++ FuzzerLoop.cpp @@ -13,6 +13,7 @@ #include "FuzzerIO.h" #include "FuzzerInternal.h" #include "FuzzerMutate.h" +#include "FuzzerMutationStats.h" #include "FuzzerRandom.h" #include "FuzzerShmem.h" #include "FuzzerTracePC.h" @@ -354,6 +355,13 @@ Printf("stat::new_units_added: %zd\n", NumberOfNewUnitsAdded); Printf("stat::slowest_unit_time_sec: %zd\n", TimeOfLongestUnitInSeconds); Printf("stat::peak_rss_mb: %zd\n", GetPeakRSSMb()); + + if (Options.PrintMutationStats) { + MStats->PrintMutationCounts(); + Printf("\n--- Useful ---"); + MStatsUseful->PrintMutationCounts(); + } + } void Fuzzer::SetMaxInputLen(size_t MaxInputLen) { @@ -653,6 +661,7 @@ /*DuringInitialCorpusExecution*/ false); if (NewCov) { ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size}); + MD.CountCurrentMutatorSequence(); break; // We will mutate this input more in the next rounds. } if (Options.ReduceDepth && !FoundUniqFeatures) Index: FuzzerMutate.h =================================================================== --- FuzzerMutate.h +++ FuzzerMutate.h @@ -86,6 +86,8 @@ Random &GetRand() { return Rand; } + void CountCurrentMutatorSequence(); + private: struct Mutator { Index: FuzzerMutate.cpp =================================================================== --- FuzzerMutate.cpp +++ FuzzerMutate.cpp @@ -10,6 +10,7 @@ //===----------------------------------------------------------------------===// #include "FuzzerMutate.h" +#include "FuzzerMutationStats.h" #include "FuzzerCorpus.h" #include "FuzzerDefs.h" #include "FuzzerExtFunctions.h" @@ -68,6 +69,7 @@ size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize) { + MStats->CustomMutationCount++; return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand()); } @@ -87,6 +89,7 @@ return 0; assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit"); memcpy(Data, U.data(), NewSize); + MStats->CustomCrossoverCount++; return NewSize; } @@ -98,6 +101,7 @@ size_t ShuffleStart = Rand(Size - ShuffleAmount); assert(ShuffleStart + ShuffleAmount <= Size); std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand); + MStats->ShuffleBytesCount++; return Size; } @@ -110,6 +114,7 @@ // Erase Data[Idx:Idx+N]. memmove(Data + Idx, Data + Idx + N, Size - Idx - N); // Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx); + MStats->EraseBytesCount++; return Size - N; } @@ -120,6 +125,7 @@ // Insert new value at Data[Idx]. memmove(Data + Idx + 1, Data + Idx, Size - Idx); Data[Idx] = RandCh(Rand); + MStats->InsertByteCount++; return Size + 1; } @@ -138,6 +144,7 @@ uint8_t Byte = Rand.RandBool() ? Rand(256) : (Rand.RandBool() ? 0 : 255); for (size_t i = 0; i < N; i++) Data[Idx + i] = Byte; + MStats->InsertRepeatedBytesCount++; return Size + N; } @@ -146,6 +153,7 @@ if (Size > MaxSize) return 0; size_t Idx = Rand(Size); Data[Idx] = RandCh(Rand); + MStats->ChangeByteCount++; return Size; } @@ -154,12 +162,14 @@ if (Size > MaxSize) return 0; size_t Idx = Rand(Size); Data[Idx] ^= 1 << Rand(8); + MStats->ChangeBitCount++; return Size; } size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size, size_t MaxSize) { + MStats->AddWordFromManualDictionaryCount++; return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize); } @@ -275,11 +285,13 @@ kCmpDictionaryEntriesDequeSize]; DERef = DE; CurrentDictionaryEntrySequence.push_back(&DERef); + MStats->AddWordFromTORCCount++; return Size; } size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary( uint8_t *Data, size_t Size, size_t MaxSize) { + MStats->AddWordFromPersistentAutoDictionaryCount++; return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize); } @@ -292,6 +304,7 @@ if (!Size) return 0; DE.IncUseCount(); CurrentDictionaryEntrySequence.push_back(&DE); + return Size; } @@ -338,6 +351,7 @@ size_t MutationDispatcher::Mutate_CopyPart(uint8_t *Data, size_t Size, size_t MaxSize) { + MStats->CopyPartCount++; if (Size > MaxSize || Size == 0) return 0; if (Rand.RandBool()) return CopyPartOf(Data, Size, Data, Size); @@ -360,7 +374,7 @@ for (size_t i = B + 1; i < E; i++) Val = Val * 10 + Data[i] - '0'; - // Mutate the integer value. + // Mutate the integer value.CurrentMut switch(Rand(5)) { case 0: Val++; break; case 1: Val--; break; @@ -376,6 +390,7 @@ Data[Idx] = (Val % 10) + '0'; Val /= 10; } + MStats->ChangeASCIIIntegerCount++; return Size; } @@ -407,6 +422,7 @@ size_t MutationDispatcher::Mutate_ChangeBinaryInteger(uint8_t *Data, size_t Size, size_t MaxSize) { + MStats->ChangeBinaryIntegerCount++; if (Size > MaxSize) return 0; switch (Rand(4)) { case 3: return ChangeBinaryInteger(Data, Size, Rand); @@ -445,6 +461,7 @@ assert(NewSize > 0 && "CrossOver returned empty unit"); assert(NewSize <= MaxSize && "CrossOver returned overisized unit"); memcpy(Data, U.data(), NewSize); + MStats->CrossOverCount++; return NewSize; } @@ -530,4 +547,40 @@ {W, std::numeric_limits::max()}); } +void MutationDispatcher::CountCurrentMutatorSequence() { + for (auto M : CurrentMutatorSequence) { + if (strncmp(M.Name, "EraseBytes", strlen(M.Name)) == 0) { + MStatsUseful->EraseBytesCount++; + } else if (strncmp(M.Name, "InsertByte", strlen(M.Name)) == 0) { + MStatsUseful->InsertByteCount++; + } else if (strncmp(M.Name, "InsertRepeatedBytes", strlen(M.Name)) == 0) { + MStatsUseful->InsertRepeatedBytesCount++; + } else if (strncmp(M.Name, "ChangeByte", strlen(M.Name)) == 0) { + MStatsUseful->ChangeByteCount++; + } else if (strncmp(M.Name, "ChangeBit", strlen(M.Name)) == 0) { + MStatsUseful->ChangeBitCount++; + } else if (strncmp(M.Name, "ShuffleBytes", strlen(M.Name)) == 0) { + MStatsUseful->ShuffleBytesCount++; + } else if (strncmp(M.Name, "ChangeASCIIInt", strlen(M.Name)) == 0) { + MStatsUseful->ChangeASCIIIntegerCount++; + } else if (strncmp(M.Name, "ChangeBinInt", strlen(M.Name)) == 0) { + MStatsUseful->ChangeBinaryIntegerCount++; + } else if (strncmp(M.Name, "CopyPart", strlen(M.Name)) == 0) { + MStatsUseful->CopyPartCount++; + } else if (strncmp(M.Name, "CrossOver", strlen(M.Name)) == 0) { + MStatsUseful->CrossOverCount++; + } else if (strncmp(M.Name, "ManualDict", strlen(M.Name)) == 0) { + MStatsUseful->AddWordFromManualDictionaryCount++; + } else if (strncmp(M.Name, "PersAutoDict", strlen(M.Name)) == 0) { + MStatsUseful->AddWordFromPersistentAutoDictionaryCount++; + } else if (strncmp(M.Name, "CMP", strlen(M.Name)) == 0) { + MStatsUseful->AddWordFromTORCCount++; + } else if (strncmp(M.Name, "Custom", strlen(M.Name)) == 0) { + MStatsUseful->CustomMutationCount++; + } else if (strncmp(M.Name, "CustomCrossOver", strlen(M.Name)) == 0) { + MStatsUseful->CustomCrossoverCount++; + } + } +} + } // namespace fuzzer Index: FuzzerMutationStats.h =================================================================== --- /dev/null +++ FuzzerMutationStats.h @@ -0,0 +1,48 @@ +//===- FuzzerMutationStats.h - Header for mutation tracking ----------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// fuzzer::MutationStats +//===----------------------------------------------------------------------===// + + +namespace fuzzer { + +class MutationStats { +public: + MutationStats(); + ~MutationStats() {} + void PrintMutationCounts(); + + /// A count of each mutation used in the fuzzing process. + int CustomMutationCount; + int CustomCrossoverCount; + int ShuffleBytesCount; + int EraseBytesCount; + int InsertByteCount; + int InsertRepeatedBytesCount; + int ChangeByteCount; + int ChangeBitCount; + int CopyPartCount; + int AddWordFromManualDictionaryCount; + int AddWordFromTORCCount; + int AddWordFromPersistentAutoDictionaryCount; + int ChangeASCIIIntegerCount; + int ChangeBinaryIntegerCount; + int CrossOverCount; + +private: + struct Mutator { + size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max); + const char *Name; + }; +}; + +extern MutationStats *MStats; +extern MutationStats *MStatsUseful; + +} Index: FuzzerMutationStats.cpp =================================================================== --- /dev/null +++ FuzzerMutationStats.cpp @@ -0,0 +1,70 @@ +//===- FuzzerMutate.cpp - Mutate a test input -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Mutate a test input. +//===----------------------------------------------------------------------===// + +#include "FuzzerMutate.h" +#include "FuzzerMutationStats.h" +#include "FuzzerIO.h" + +#ifndef NAMEOF +#define NAMEOF(var) #var +#endif + +namespace fuzzer { + +MutationStats* MStats = new MutationStats(); +MutationStats* MStatsUseful = new MutationStats(); + +MutationStats::MutationStats() { + CustomMutationCount = 0; + CustomCrossoverCount = 0; + ShuffleBytesCount = 0; + EraseBytesCount = 0; + InsertByteCount = 0; + InsertRepeatedBytesCount = 0; + ChangeByteCount = 0; + ChangeBitCount = 0; + CopyPartCount = 0; + AddWordFromManualDictionaryCount = 0; + AddWordFromTORCCount = 0; + AddWordFromPersistentAutoDictionaryCount = 0; + ChangeASCIIIntegerCount = 0; + ChangeBinaryIntegerCount = 0; + CrossOverCount = 0; +} + +void MutationStats::PrintMutationCounts() { + // Outputs the number of each mutation used + + Printf("\n\n**********************************************\n"); + Printf("Mutations\n\n"); + Printf("%s: %d\n", NAMEOF(CustomMutationCount), CustomMutationCount); + Printf("%s: %d\n", NAMEOF(CustomCrossoverCount), CustomCrossoverCount); + Printf("%s: %d\n", NAMEOF(ShuffleBytesCount), ShuffleBytesCount); + Printf("%s: %d\n", NAMEOF(EraseBytesCount), EraseBytesCount); + Printf("%s: %d\n", NAMEOF(InsertByteCount), InsertByteCount); + Printf("%s: %d\n", NAMEOF(InsertRepeatedBytesCount), + InsertRepeatedBytesCount); + Printf("%s: %d\n", NAMEOF(ChangeByteCount), ChangeByteCount); + Printf("%s: %d\n", NAMEOF(ChangeBitCount), ChangeBitCount); + Printf("%s: %d\n", NAMEOF(CopyPartCount), CopyPartCount); + Printf("%s: %d\n", NAMEOF(AddWordFromManualDictionaryCount), + AddWordFromManualDictionaryCount); + Printf("%s: %d\n", NAMEOF(AddWordFromTORCCount), AddWordFromTORCCount); + Printf("%s: %d\n", NAMEOF(AddWordFromPersistentAutoDictionaryCount), + AddWordFromPersistentAutoDictionaryCount); + Printf("%s: %d\n", NAMEOF(ChangeASCIIIntegerCount), ChangeASCIIIntegerCount); + Printf("%s: %d\n", NAMEOF(ChangeBinaryIntegerCount), + ChangeBinaryIntegerCount); + Printf("%s: %d", NAMEOF(CrossOverCount), CrossOverCount); + Printf("\n**********************************************\n\n"); +} + +} // namespace fuzzer Index: FuzzerOptions.h =================================================================== --- FuzzerOptions.h +++ FuzzerOptions.h @@ -50,6 +50,7 @@ bool PrintNewCovPcs = false; int PrintNewCovFuncs = 0; bool PrintFinalStats = false; + bool PrintMutationStats = false; bool PrintCorpusStats = false; bool PrintCoverage = false; bool DumpCoverage = false;