#define LLVM_FUZZER_CORPUS
#include <random>
+#include <unordered_set>
#include "FuzzerDefs.h"
#include "FuzzerRandom.h"
struct InputInfo {
Unit U; // The actual input data.
uint8_t Sha1[kSHA1NumBytes]; // Checksum.
+ // Stats.
+ uintptr_t NumExecutedMutations = 0;
+ uintptr_t NumSuccessfullMutations = 0;
};
class InputCorpus {
size_t size() const { return Inputs.size(); }
bool empty() const { return Inputs.empty(); }
const Unit &operator[] (size_t Idx) const { return Inputs[Idx].U; }
- void Append(const std::vector<Unit> &V) {
- for (auto &U : V)
- push_back(U);
- }
- void push_back(const Unit &U) {
+ void AddToCorpus(const Unit &U) {
auto H = Hash(U);
if (!Hashes.insert(H).second) return;
InputInfo II;
ConstIter end() const { return Inputs.end(); }
bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); }
- const InputInfo &ChooseUnitToMutate(Random &Rand) {
+ InputInfo &ChooseUnitToMutate(Random &Rand) {
return Inputs[ChooseUnitIdxToMutate(Rand)];
};
// Hypothesis: units added to the corpus last are more likely to be
// interesting. This function gives more weight to the more recent units.
size_t ChooseUnitIdxToMutate(Random &Rand) {
- size_t Idx =
- static_cast<size_t>(CorpusDistribution(Rand.Get_mt19937()));
+ size_t Idx = static_cast<size_t>(CorpusDistribution(Rand.Get_mt19937()));
assert(Idx < Inputs.size());
return Idx;
}
+ void PrintStats() {
+ for (size_t i = 0; i < Inputs.size(); i++) {
+ const auto &II = Inputs[i];
+ Printf(" [%zd %s]\tsz: %zd\truns: %zd\tsucc: %zd\n", i,
+ Sha1ToString(II.Sha1).c_str(), II.U.size(),
+ II.NumExecutedMutations, II.NumSuccessfullMutations);
+ }
+ }
+
private:
// Updates the probability distribution for the units in the corpus.
class MutationDispatcher;
struct FuzzingOptions;
class InputCorpus;
+struct InputInfo;
struct ExternalFunctions;
// Global interface to functions that may or may not be available.
static const int kSHA1NumBytes = 20;
// Computes SHA1 hash of 'Len' bytes in 'Data', writes kSHA1NumBytes to 'Out'.
void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out);
-std::string Sha1ToString(uint8_t Sha1[kSHA1NumBytes]);
+std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]);
// Changes U to contain only ASCII (isprint+isspace) characters.
// Returns true iff U has been changed.
// FuzzerDriver and flag parsing.
//===----------------------------------------------------------------------===//
+#include "FuzzerCorpus.h"
#include "FuzzerInterface.h"
#include "FuzzerInternal.h"
#include "FuzzerMutate.h"
return 0;
}
-int MinimizeCrashInputInternalStep(Fuzzer *F) {
+int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) {
assert(Inputs->size() == 1);
std::string InputFilePath = Inputs->at(0);
Unit U = FileToVector(InputFilePath);
for (size_t I = 0; I < U.size(); I++) {
std::copy(U.begin(), U.begin() + I, X.begin());
std::copy(U.begin() + I + 1, U.end(), X.begin() + I);
- F->AddToCorpus(X);
+ Corpus->AddToCorpus(X);
}
F->SetMaxLen(U.size() - 1);
F->Loop();
!DoPlainRun || Flags.minimize_crash_internal_step;
Options.PrintNewCovPcs = Flags.print_pcs;
Options.PrintFinalStats = Flags.print_final_stats;
+ Options.PrintCorpusStats = Flags.print_corpus_stats;
Options.PrintCoverage = Flags.print_coverage;
Options.PruneCorpus = Flags.prune_corpus;
Random Rand(Seed);
MutationDispatcher MD(Rand, Options);
- Fuzzer F(Callback, MD, Options);
+ InputCorpus Corpus;
+ Fuzzer F(Callback, Corpus, MD, Options);
for (auto &U: Dictionary)
if (U.size() <= Word::GetMaxSize())
if (Flags.handle_term) SetSigTermHandler();
if (Flags.minimize_crash_internal_step)
- return MinimizeCrashInputInternalStep(&F);
+ return MinimizeCrashInputInternalStep(&F, &Corpus);
if (DoPlainRun) {
Options.SaveArtifacts = false;
FUZZER_FLAG_INT(output_csv, 0, "Enable pulse output in CSV format.")
FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.")
FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.")
+FUZZER_FLAG_INT(print_corpus_stats, 0,
+ "If 1, print statistics on corpus elements at exit.")
FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information at exit."
" Experimental, only with trace-pc-guard")
FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.")
#include <climits>
#include <cstdlib>
#include <string.h>
-#include <unordered_set>
#include "FuzzerDefs.h"
#include "FuzzerExtFunctions.h"
#include "FuzzerInterface.h"
#include "FuzzerOptions.h"
#include "FuzzerValueBitMap.h"
-#include "FuzzerCorpus.h"
namespace fuzzer {
size_t VPMapBits;
};
- Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options);
+ Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
+ FuzzingOptions Options);
~Fuzzer();
- void AddToCorpus(const Unit &U) { Corpus.push_back(U); }
void Loop();
void ShuffleAndMinimize(UnitVector *V);
void InitializeTraceState();
void AssignTaintLabels(uint8_t *Data, size_t Size);
- size_t CorpusSize() const { return Corpus.size(); }
- void ReadDir(const std::string &Path, long *Epoch, size_t MaxSize);
void RereadOutputCorpus(size_t MaxSize);
size_t secondsSinceProcessStartUp() {
void CrashCallback();
void InterruptCallback();
void MutateAndTestOne();
- void ReportNewCoverage(const Unit &U);
+ void ReportNewCoverage(InputInfo *II, const Unit &U);
void PrintNewPCs();
void PrintOneNewPC(uintptr_t PC);
bool RunOne(const Unit &U) { return RunOne(U.data(), U.size()); }
- void RunOneAndUpdateCorpus(const uint8_t *Data, size_t Size);
void WriteToOutputCorpus(const Unit &U);
void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix);
void PrintStats(const char *Where, const char *End = "\n");
bool HasMoreMallocsThanFrees = false;
size_t NumberOfLeakDetectionAttempts = 0;
- InputCorpus Corpus;
-
UserCallback CB;
+ InputCorpus &Corpus;
MutationDispatcher &MD;
FuzzingOptions Options;
+
system_clock::time_point ProcessStartTime = system_clock::now();
system_clock::time_point UnitStartTime;
long TimeOfLongestUnitInSeconds = 0;
//===----------------------------------------------------------------------===//
#include "FuzzerInternal.h"
+#include "FuzzerCorpus.h"
#include "FuzzerMutate.h"
#include "FuzzerTracePC.h"
#include "FuzzerRandom.h"
AllocTracer.Frees++;
}
-Fuzzer::Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options)
- : CB(CB), MD(MD), Options(Options) {
+Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
+ FuzzingOptions Options)
+ : CB(CB), Corpus(Corpus), MD(MD), Options(Options) {
SetDeathCallback();
InitializeTraceState();
assert(!F);
void Fuzzer::PrintFinalStats() {
if (Options.PrintCoverage)
TPC.PrintCoverage();
+ if (Options.PrintCorpusStats)
+ Corpus.PrintStats();
if (!Options.PrintFinalStats) return;
size_t ExecPerSec = execPerSec();
Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns);
Printf("INFO: -max_len is not provided, using %zd\n", Options.MaxLen);
}
-void Fuzzer::ReadDir(const std::string &Path, long *Epoch, size_t MaxSize) {
- Printf("Loading corpus: %s\n", Path.c_str());
- std::vector<Unit> V;
- ReadDirToVectorOfUnits(Path.c_str(), &V, Epoch, MaxSize);
- for (auto &U : V)
- Corpus.push_back(U);
-}
-
void Fuzzer::RereadOutputCorpus(size_t MaxSize) {
if (Options.OutputCorpus.empty() || !Options.Reload) return;
std::vector<Unit> AdditionalCorpus;
X.resize(MaxSize);
if (!Corpus.HasUnit(X)) {
if (RunOne(X)) {
- Corpus.push_back(X);
+ Corpus.AddToCorpus(X);
PrintStats("RELOAD");
}
}
for (const auto &U : *InitialCorpus) {
bool NewCoverage = RunOne(U);
if (!Options.PruneCorpus || NewCoverage) {
- Corpus.push_back(U);
+ Corpus.AddToCorpus(U);
if (Options.Verbosity >= 2)
Printf("NEW0: %zd L %zd\n", MaxCoverage.BlockCoverage, U.size());
}
return Res;
}
-void Fuzzer::RunOneAndUpdateCorpus(const uint8_t *Data, size_t Size) {
- if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
- return;
- if (RunOne(Data, Size))
- ReportNewCoverage({Data, Data + Size});
-}
-
size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
assert(InFuzzingThread());
*Data = CurrentUnitData;
PrintOneNewPC(PCs[i]);
}
-void Fuzzer::ReportNewCoverage(const Unit &U) {
- Corpus.push_back(U);
+void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) {
+ II->NumSuccessfullMutations++;
+ Corpus.AddToCorpus(U);
MD.RecordSuccessfulMutationSequence();
PrintStatusForNewUnit(U);
WriteToOutputCorpus(U);
LazyAllocateCurrentUnitData();
MD.StartMutationSequence();
- const auto &II = Corpus.ChooseUnitToMutate(MD.GetRand());
+ auto &II = Corpus.ChooseUnitToMutate(MD.GetRand());
const auto &U = II.U;
memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1));
assert(CurrentUnitData);
memcpy(CurrentUnitData, U.data(), Size);
for (int i = 0; i < Options.MutateDepth; i++) {
+ if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
+ break;
size_t NewSize = 0;
NewSize = MD.Mutate(CurrentUnitData, Size, Options.MaxLen);
assert(NewSize > 0 && "Mutator returned empty unit");
Size = NewSize;
if (i == 0)
StartTraceRecording();
- RunOneAndUpdateCorpus(CurrentUnitData, Size);
+ II.NumExecutedMutations++;
+ if (RunOne(CurrentUnitData, Size))
+ ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size});
StopTraceRecording();
TryDetectingAMemoryLeak(CurrentUnitData, Size,
/*DuringInitialCorpusExecution*/ false);
//===----------------------------------------------------------------------===//
#include <cstring>
-#include <unordered_set>
#include "FuzzerCorpus.h"
#include "FuzzerDefs.h"
bool OutputCSV = false;
bool PrintNewCovPcs = false;
bool PrintFinalStats = false;
+ bool PrintCorpusStats = false;
bool PrintCoverage = false;
bool DetectLeaks = true;
bool PruneCorpus = true;
PrintASCII(U.data(), U.size(), PrintAfter);
}
-std::string Sha1ToString(uint8_t Sha1[kSHA1NumBytes]) {
+std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]) {
std::stringstream SS;
for (int i = 0; i < kSHA1NumBytes; i++)
SS << std::hex << std::setfill('0') << std::setw(2) << (unsigned)Sha1[i];
// with ASan) involving C++ standard library types when using libcxx.
#define _LIBCPP_HAS_NO_ASAN
+#include "FuzzerCorpus.h"
#include "FuzzerInternal.h"
#include "FuzzerDictionary.h"
#include "FuzzerMutate.h"
size_t N = 10;
size_t TriesPerUnit = 1<<20;
for (size_t i = 0; i < N; i++)
- C.push_back(Unit{ static_cast<uint8_t>(i) });
+ C.AddToCorpus(Unit{ static_cast<uint8_t>(i) });
std::vector<size_t> Hist(N);
for (size_t i = 0; i < N * TriesPerUnit; i++) {