forked from OSchip/llvm-project
[libFuzzer] Use custom allocators for STL containers in libFuzzer
Avoids ODR violations causing spurious ASAN container overflow warnings. Differential Revision: https://reviews.llvm.org/D37086 llvm-svn: 311830
This commit is contained in:
parent
de269f4620
commit
d50410bfb1
|
@ -35,7 +35,7 @@ struct InputInfo {
|
||||||
size_t NumSuccessfullMutations = 0;
|
size_t NumSuccessfullMutations = 0;
|
||||||
bool MayDeleteFile = false;
|
bool MayDeleteFile = false;
|
||||||
bool Reduced = false;
|
bool Reduced = false;
|
||||||
std::vector<uint32_t> UniqFeatureSet;
|
fuzzer::vector<uint32_t> UniqFeatureSet;
|
||||||
};
|
};
|
||||||
|
|
||||||
class InputCorpus {
|
class InputCorpus {
|
||||||
|
@ -71,7 +71,7 @@ class InputCorpus {
|
||||||
bool empty() const { return Inputs.empty(); }
|
bool empty() const { return Inputs.empty(); }
|
||||||
const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; }
|
const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; }
|
||||||
void AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile,
|
void AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile,
|
||||||
const std::vector<uint32_t> &FeatureSet) {
|
const fuzzer::vector<uint32_t> &FeatureSet) {
|
||||||
assert(!U.empty());
|
assert(!U.empty());
|
||||||
if (FeatureDebug)
|
if (FeatureDebug)
|
||||||
Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures);
|
Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures);
|
||||||
|
@ -100,7 +100,7 @@ class InputCorpus {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug-only
|
// Debug-only
|
||||||
void PrintFeatureSet(const std::vector<uint32_t> &FeatureSet) {
|
void PrintFeatureSet(const fuzzer::vector<uint32_t> &FeatureSet) {
|
||||||
if (!FeatureDebug) return;
|
if (!FeatureDebug) return;
|
||||||
Printf("{");
|
Printf("{");
|
||||||
for (uint32_t Feature: FeatureSet)
|
for (uint32_t Feature: FeatureSet)
|
||||||
|
@ -256,11 +256,11 @@ private:
|
||||||
}
|
}
|
||||||
std::piecewise_constant_distribution<double> CorpusDistribution;
|
std::piecewise_constant_distribution<double> CorpusDistribution;
|
||||||
|
|
||||||
std::vector<double> Intervals;
|
fuzzer::vector<double> Intervals;
|
||||||
std::vector<double> Weights;
|
fuzzer::vector<double> Weights;
|
||||||
|
|
||||||
std::unordered_set<std::string> Hashes;
|
std::unordered_set<std::string> Hashes;
|
||||||
std::vector<InputInfo*> Inputs;
|
fuzzer::vector<InputInfo*> Inputs;
|
||||||
|
|
||||||
size_t NumAddedFeatures = 0;
|
size_t NumAddedFeatures = 0;
|
||||||
size_t NumUpdatedFeatures = 0;
|
size_t NumUpdatedFeatures = 0;
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
// Platform detection.
|
// Platform detection.
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
@ -102,8 +104,19 @@ struct ExternalFunctions;
|
||||||
// Global interface to functions that may or may not be available.
|
// Global interface to functions that may or may not be available.
|
||||||
extern ExternalFunctions *EF;
|
extern ExternalFunctions *EF;
|
||||||
|
|
||||||
typedef std::vector<uint8_t> Unit;
|
// We are using a custom allocator to give a different symbol name to STL
|
||||||
typedef std::vector<Unit> UnitVector;
|
// containers in order to avoid ODR violations.
|
||||||
|
template<typename T>
|
||||||
|
class fuzzer_allocator: public std::allocator<T> {};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using vector = std::vector<T, fuzzer_allocator<T>>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using set = std::set<T, std::less<T>, fuzzer_allocator<T>>;
|
||||||
|
|
||||||
|
typedef fuzzer::vector<uint8_t> Unit;
|
||||||
|
typedef fuzzer::vector<Unit> UnitVector;
|
||||||
typedef int (*UserCallback)(const uint8_t *Data, size_t Size);
|
typedef int (*UserCallback)(const uint8_t *Data, size_t Size);
|
||||||
|
|
||||||
int FuzzerDriver(int *argc, char ***argv, UserCallback Callback);
|
int FuzzerDriver(int *argc, char ***argv, UserCallback Callback);
|
||||||
|
|
|
@ -120,7 +120,7 @@ private:
|
||||||
bool ParseOneDictionaryEntry(const std::string &Str, Unit *U);
|
bool ParseOneDictionaryEntry(const std::string &Str, Unit *U);
|
||||||
// Parses the dictionary file, fills Units, returns true iff all lines
|
// Parses the dictionary file, fills Units, returns true iff all lines
|
||||||
// were parsed succesfully.
|
// were parsed succesfully.
|
||||||
bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units);
|
bool ParseDictionaryFile(const std::string &Text, fuzzer::vector<Unit> *Units);
|
||||||
|
|
||||||
} // namespace fuzzer
|
} // namespace fuzzer
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ static const FlagDescription FlagDescriptions [] {
|
||||||
static const size_t kNumFlags =
|
static const size_t kNumFlags =
|
||||||
sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]);
|
sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]);
|
||||||
|
|
||||||
static std::vector<std::string> *Inputs;
|
static fuzzer::vector<std::string> *Inputs;
|
||||||
static std::string *ProgName;
|
static std::string *ProgName;
|
||||||
|
|
||||||
static void PrintHelp() {
|
static void PrintHelp() {
|
||||||
|
@ -175,7 +175,7 @@ static bool ParseOneFlag(const char *Param) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't use any library to minimize dependencies.
|
// We don't use any library to minimize dependencies.
|
||||||
static void ParseFlags(const std::vector<std::string> &Args) {
|
static void ParseFlags(const fuzzer::vector<std::string> &Args) {
|
||||||
for (size_t F = 0; F < kNumFlags; F++) {
|
for (size_t F = 0; F < kNumFlags; F++) {
|
||||||
if (FlagDescriptions[F].IntFlag)
|
if (FlagDescriptions[F].IntFlag)
|
||||||
*FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default;
|
*FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default;
|
||||||
|
@ -185,7 +185,7 @@ static void ParseFlags(const std::vector<std::string> &Args) {
|
||||||
if (FlagDescriptions[F].StrFlag)
|
if (FlagDescriptions[F].StrFlag)
|
||||||
*FlagDescriptions[F].StrFlag = nullptr;
|
*FlagDescriptions[F].StrFlag = nullptr;
|
||||||
}
|
}
|
||||||
Inputs = new std::vector<std::string>;
|
Inputs = new fuzzer::vector<std::string>;
|
||||||
for (size_t A = 1; A < Args.size(); A++) {
|
for (size_t A = 1; A < Args.size(); A++) {
|
||||||
if (ParseOneFlag(Args[A].c_str())) {
|
if (ParseOneFlag(Args[A].c_str())) {
|
||||||
if (Flags.ignore_remaining_args)
|
if (Flags.ignore_remaining_args)
|
||||||
|
@ -225,7 +225,7 @@ static void WorkerThread(const std::string &Cmd, std::atomic<unsigned> *Counter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CloneArgsWithoutX(const std::vector<std::string> &Args,
|
std::string CloneArgsWithoutX(const fuzzer::vector<std::string> &Args,
|
||||||
const char *X1, const char *X2) {
|
const char *X1, const char *X2) {
|
||||||
std::string Cmd;
|
std::string Cmd;
|
||||||
for (auto &S : Args) {
|
for (auto &S : Args) {
|
||||||
|
@ -236,12 +236,12 @@ std::string CloneArgsWithoutX(const std::vector<std::string> &Args,
|
||||||
return Cmd;
|
return Cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int RunInMultipleProcesses(const std::vector<std::string> &Args,
|
static int RunInMultipleProcesses(const fuzzer::vector<std::string> &Args,
|
||||||
unsigned NumWorkers, unsigned NumJobs) {
|
unsigned NumWorkers, unsigned NumJobs) {
|
||||||
std::atomic<unsigned> Counter(0);
|
std::atomic<unsigned> Counter(0);
|
||||||
std::atomic<bool> HasErrors(false);
|
std::atomic<bool> HasErrors(false);
|
||||||
std::string Cmd = CloneArgsWithoutX(Args, "jobs", "workers");
|
std::string Cmd = CloneArgsWithoutX(Args, "jobs", "workers");
|
||||||
std::vector<std::thread> V;
|
fuzzer::vector<std::thread> V;
|
||||||
std::thread Pulse(PulseThread);
|
std::thread Pulse(PulseThread);
|
||||||
Pulse.detach();
|
Pulse.detach();
|
||||||
for (unsigned i = 0; i < NumWorkers; i++)
|
for (unsigned i = 0; i < NumWorkers; i++)
|
||||||
|
@ -294,7 +294,7 @@ static std::string GetDedupTokenFromFile(const std::string &Path) {
|
||||||
return S.substr(Beg, End - Beg);
|
return S.substr(Beg, End - Beg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CleanseCrashInput(const std::vector<std::string> &Args,
|
int CleanseCrashInput(const fuzzer::vector<std::string> &Args,
|
||||||
const FuzzingOptions &Options) {
|
const FuzzingOptions &Options) {
|
||||||
if (Inputs->size() != 1 || !Flags.exact_artifact_path) {
|
if (Inputs->size() != 1 || !Flags.exact_artifact_path) {
|
||||||
Printf("ERROR: -cleanse_crash should be given one input file and"
|
Printf("ERROR: -cleanse_crash should be given one input file and"
|
||||||
|
@ -322,7 +322,7 @@ int CleanseCrashInput(const std::vector<std::string> &Args,
|
||||||
auto U = FileToVector(CurrentFilePath);
|
auto U = FileToVector(CurrentFilePath);
|
||||||
size_t Size = U.size();
|
size_t Size = U.size();
|
||||||
|
|
||||||
const std::vector<uint8_t> ReplacementBytes = {' ', 0xff};
|
const fuzzer::vector<uint8_t> ReplacementBytes = {' ', 0xff};
|
||||||
for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) {
|
for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) {
|
||||||
bool Changed = false;
|
bool Changed = false;
|
||||||
for (size_t Idx = 0; Idx < Size; Idx++) {
|
for (size_t Idx = 0; Idx < Size; Idx++) {
|
||||||
|
@ -354,7 +354,7 @@ int CleanseCrashInput(const std::vector<std::string> &Args,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MinimizeCrashInput(const std::vector<std::string> &Args,
|
int MinimizeCrashInput(const fuzzer::vector<std::string> &Args,
|
||||||
const FuzzingOptions &Options) {
|
const FuzzingOptions &Options) {
|
||||||
if (Inputs->size() != 1) {
|
if (Inputs->size() != 1) {
|
||||||
Printf("ERROR: -minimize_crash should be given one input file\n");
|
Printf("ERROR: -minimize_crash should be given one input file\n");
|
||||||
|
@ -456,17 +456,17 @@ int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AnalyzeDictionary(Fuzzer *F, const std::vector<Unit>& Dict,
|
int AnalyzeDictionary(Fuzzer *F, const fuzzer::vector<Unit>& Dict,
|
||||||
UnitVector& Corpus) {
|
UnitVector& Corpus) {
|
||||||
Printf("Started dictionary minimization (up to %d tests)\n",
|
Printf("Started dictionary minimization (up to %d tests)\n",
|
||||||
Dict.size() * Corpus.size() * 2);
|
Dict.size() * Corpus.size() * 2);
|
||||||
|
|
||||||
// Scores and usage count for each dictionary unit.
|
// Scores and usage count for each dictionary unit.
|
||||||
std::vector<int> Scores(Dict.size());
|
fuzzer::vector<int> Scores(Dict.size());
|
||||||
std::vector<int> Usages(Dict.size());
|
fuzzer::vector<int> Usages(Dict.size());
|
||||||
|
|
||||||
std::vector<size_t> InitialFeatures;
|
fuzzer::vector<size_t> InitialFeatures;
|
||||||
std::vector<size_t> ModifiedFeatures;
|
fuzzer::vector<size_t> ModifiedFeatures;
|
||||||
for (auto &C : Corpus) {
|
for (auto &C : Corpus) {
|
||||||
// Get coverage for the testcase without modifications.
|
// Get coverage for the testcase without modifications.
|
||||||
F->ExecuteCallback(C.data(), C.size());
|
F->ExecuteCallback(C.data(), C.size());
|
||||||
|
@ -531,7 +531,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
|
||||||
EF = new ExternalFunctions();
|
EF = new ExternalFunctions();
|
||||||
if (EF->LLVMFuzzerInitialize)
|
if (EF->LLVMFuzzerInitialize)
|
||||||
EF->LLVMFuzzerInitialize(argc, argv);
|
EF->LLVMFuzzerInitialize(argc, argv);
|
||||||
const std::vector<std::string> Args(*argv, *argv + *argc);
|
const fuzzer::vector<std::string> Args(*argv, *argv + *argc);
|
||||||
assert(!Args.empty());
|
assert(!Args.empty());
|
||||||
ProgName = new std::string(Args[0]);
|
ProgName = new std::string(Args[0]);
|
||||||
if (Argv0 != *ProgName) {
|
if (Argv0 != *ProgName) {
|
||||||
|
@ -593,7 +593,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
|
||||||
Options.ArtifactPrefix = Flags.artifact_prefix;
|
Options.ArtifactPrefix = Flags.artifact_prefix;
|
||||||
if (Flags.exact_artifact_path)
|
if (Flags.exact_artifact_path)
|
||||||
Options.ExactArtifactPath = Flags.exact_artifact_path;
|
Options.ExactArtifactPath = Flags.exact_artifact_path;
|
||||||
std::vector<Unit> Dictionary;
|
fuzzer::vector<Unit> Dictionary;
|
||||||
if (Flags.dict)
|
if (Flags.dict)
|
||||||
if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary))
|
if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -68,10 +68,10 @@ void WriteToFile(const Unit &U, const std::string &Path) {
|
||||||
fclose(Out);
|
fclose(Out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V,
|
void ReadDirToVectorOfUnits(const char *Path, fuzzer::vector<Unit> *V,
|
||||||
long *Epoch, size_t MaxSize, bool ExitOnError) {
|
long *Epoch, size_t MaxSize, bool ExitOnError) {
|
||||||
long E = Epoch ? *Epoch : 0;
|
long E = Epoch ? *Epoch : 0;
|
||||||
std::vector<std::string> Files;
|
fuzzer::vector<std::string> Files;
|
||||||
ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true);
|
ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true);
|
||||||
size_t NumLoaded = 0;
|
size_t NumLoaded = 0;
|
||||||
for (size_t i = 0; i < Files.size(); i++) {
|
for (size_t i = 0; i < Files.size(); i++) {
|
||||||
|
|
|
@ -27,7 +27,7 @@ void CopyFileToErr(const std::string &Path);
|
||||||
|
|
||||||
void WriteToFile(const Unit &U, const std::string &Path);
|
void WriteToFile(const Unit &U, const std::string &Path);
|
||||||
|
|
||||||
void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V,
|
void ReadDirToVectorOfUnits(const char *Path, fuzzer::vector<Unit> *V,
|
||||||
long *Epoch, size_t MaxSize, bool ExitOnError);
|
long *Epoch, size_t MaxSize, bool ExitOnError);
|
||||||
|
|
||||||
// Returns "Dir/FileName" or equivalent for the current OS.
|
// Returns "Dir/FileName" or equivalent for the current OS.
|
||||||
|
@ -55,7 +55,7 @@ void RawPrint(const char *Str);
|
||||||
bool IsFile(const std::string &Path);
|
bool IsFile(const std::string &Path);
|
||||||
|
|
||||||
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
||||||
std::vector<std::string> *V, bool TopDir);
|
fuzzer::vector<std::string> *V, bool TopDir);
|
||||||
|
|
||||||
char GetSeparator();
|
char GetSeparator();
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ bool IsFile(const std::string &Path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
||||||
std::vector<std::string> *V, bool TopDir) {
|
fuzzer::vector<std::string> *V, bool TopDir) {
|
||||||
auto E = GetEpoch(Dir);
|
auto E = GetEpoch(Dir);
|
||||||
if (Epoch)
|
if (Epoch)
|
||||||
if (E && *Epoch >= E) return;
|
if (E && *Epoch >= E) return;
|
||||||
|
|
|
@ -73,7 +73,7 @@ bool IsFile(const std::string &Path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
||||||
std::vector<std::string> *V, bool TopDir) {
|
fuzzer::vector<std::string> *V, bool TopDir) {
|
||||||
auto E = GetEpoch(Dir);
|
auto E = GetEpoch(Dir);
|
||||||
if (Epoch)
|
if (Epoch)
|
||||||
if (E && *Epoch >= E) return;
|
if (E && *Epoch >= E) return;
|
||||||
|
|
|
@ -69,9 +69,9 @@ public:
|
||||||
InputInfo *II = nullptr);
|
InputInfo *II = nullptr);
|
||||||
|
|
||||||
// Merge Corpora[1:] into Corpora[0].
|
// Merge Corpora[1:] into Corpora[0].
|
||||||
void Merge(const std::vector<std::string> &Corpora);
|
void Merge(const fuzzer::vector<std::string> &Corpora);
|
||||||
void CrashResistantMerge(const std::vector<std::string> &Args,
|
void CrashResistantMerge(const fuzzer::vector<std::string> &Args,
|
||||||
const std::vector<std::string> &Corpora,
|
const fuzzer::vector<std::string> &Corpora,
|
||||||
const char *CoverageSummaryInputPathOrNull,
|
const char *CoverageSummaryInputPathOrNull,
|
||||||
const char *CoverageSummaryOutputPathOrNull);
|
const char *CoverageSummaryOutputPathOrNull);
|
||||||
void CrashResistantMergeInternalStep(const std::string &ControlFilePath);
|
void CrashResistantMergeInternalStep(const std::string &ControlFilePath);
|
||||||
|
@ -139,7 +139,7 @@ private:
|
||||||
size_t MaxMutationLen = 0;
|
size_t MaxMutationLen = 0;
|
||||||
size_t TmpMaxMutationLen = 0;
|
size_t TmpMaxMutationLen = 0;
|
||||||
|
|
||||||
std::vector<uint32_t> UniqFeatureSetTmp;
|
fuzzer::vector<uint32_t> UniqFeatureSetTmp;
|
||||||
|
|
||||||
// Need to know our own thread.
|
// Need to know our own thread.
|
||||||
static thread_local bool IsMyThread;
|
static thread_local bool IsMyThread;
|
||||||
|
|
|
@ -350,7 +350,7 @@ void Fuzzer::CheckExitOnSrcPosOrItem() {
|
||||||
|
|
||||||
void Fuzzer::RereadOutputCorpus(size_t MaxSize) {
|
void Fuzzer::RereadOutputCorpus(size_t MaxSize) {
|
||||||
if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return;
|
if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return;
|
||||||
std::vector<Unit> AdditionalCorpus;
|
fuzzer::vector<Unit> AdditionalCorpus;
|
||||||
ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus,
|
ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus,
|
||||||
&EpochOfLastReadOfOutputCorpus, MaxSize,
|
&EpochOfLastReadOfOutputCorpus, MaxSize,
|
||||||
/*ExitOnError*/ false);
|
/*ExitOnError*/ false);
|
||||||
|
|
|
@ -74,7 +74,7 @@ bool Merger::Parse(std::istream &IS, bool ParseCoverage) {
|
||||||
size_t ExpectedStartMarker = 0;
|
size_t ExpectedStartMarker = 0;
|
||||||
const size_t kInvalidStartMarker = -1;
|
const size_t kInvalidStartMarker = -1;
|
||||||
size_t LastSeenStartMarker = kInvalidStartMarker;
|
size_t LastSeenStartMarker = kInvalidStartMarker;
|
||||||
std::vector<uint32_t> TmpFeatures;
|
fuzzer::vector<uint32_t> TmpFeatures;
|
||||||
while (std::getline(IS, Line, '\n')) {
|
while (std::getline(IS, Line, '\n')) {
|
||||||
std::istringstream ISS1(Line);
|
std::istringstream ISS1(Line);
|
||||||
std::string Marker;
|
std::string Marker;
|
||||||
|
@ -123,7 +123,7 @@ size_t Merger::ApproximateMemoryConsumption() const {
|
||||||
// Decides which files need to be merged (add thost to NewFiles).
|
// Decides which files need to be merged (add thost to NewFiles).
|
||||||
// Returns the number of new features added.
|
// Returns the number of new features added.
|
||||||
size_t Merger::Merge(const std::set<uint32_t> &InitialFeatures,
|
size_t Merger::Merge(const std::set<uint32_t> &InitialFeatures,
|
||||||
std::vector<std::string> *NewFiles) {
|
fuzzer::vector<std::string> *NewFiles) {
|
||||||
NewFiles->clear();
|
NewFiles->clear();
|
||||||
assert(NumFilesInFirstCorpus <= Files.size());
|
assert(NumFilesInFirstCorpus <= Files.size());
|
||||||
std::set<uint32_t> AllFeatures(InitialFeatures);
|
std::set<uint32_t> AllFeatures(InitialFeatures);
|
||||||
|
@ -138,7 +138,7 @@ size_t Merger::Merge(const std::set<uint32_t> &InitialFeatures,
|
||||||
// Remove all features that we already know from all other inputs.
|
// Remove all features that we already know from all other inputs.
|
||||||
for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) {
|
for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) {
|
||||||
auto &Cur = Files[i].Features;
|
auto &Cur = Files[i].Features;
|
||||||
std::vector<uint32_t> Tmp;
|
fuzzer::vector<uint32_t> Tmp;
|
||||||
std::set_difference(Cur.begin(), Cur.end(), AllFeatures.begin(),
|
std::set_difference(Cur.begin(), Cur.end(), AllFeatures.begin(),
|
||||||
AllFeatures.end(), std::inserter(Tmp, Tmp.begin()));
|
AllFeatures.end(), std::inserter(Tmp, Tmp.begin()));
|
||||||
Cur.swap(Tmp);
|
Cur.swap(Tmp);
|
||||||
|
@ -252,15 +252,15 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Outer process. Does not call the target code and thus sohuld not fail.
|
// Outer process. Does not call the target code and thus sohuld not fail.
|
||||||
void Fuzzer::CrashResistantMerge(const std::vector<std::string> &Args,
|
void Fuzzer::CrashResistantMerge(const fuzzer::vector<std::string> &Args,
|
||||||
const std::vector<std::string> &Corpora,
|
const fuzzer::vector<std::string> &Corpora,
|
||||||
const char *CoverageSummaryInputPathOrNull,
|
const char *CoverageSummaryInputPathOrNull,
|
||||||
const char *CoverageSummaryOutputPathOrNull) {
|
const char *CoverageSummaryOutputPathOrNull) {
|
||||||
if (Corpora.size() <= 1) {
|
if (Corpora.size() <= 1) {
|
||||||
Printf("Merge requires two or more corpus dirs\n");
|
Printf("Merge requires two or more corpus dirs\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::vector<std::string> AllFiles;
|
fuzzer::vector<std::string> AllFiles;
|
||||||
ListFilesInDirRecursive(Corpora[0], nullptr, &AllFiles, /*TopDir*/true);
|
ListFilesInDirRecursive(Corpora[0], nullptr, &AllFiles, /*TopDir*/true);
|
||||||
size_t NumFilesInFirstCorpus = AllFiles.size();
|
size_t NumFilesInFirstCorpus = AllFiles.size();
|
||||||
for (size_t i = 1; i < Corpora.size(); i++)
|
for (size_t i = 1; i < Corpora.size(); i++)
|
||||||
|
@ -318,7 +318,7 @@ void Fuzzer::CrashResistantMerge(const std::vector<std::string> &Args,
|
||||||
std::ofstream SummaryOut(CoverageSummaryOutputPathOrNull);
|
std::ofstream SummaryOut(CoverageSummaryOutputPathOrNull);
|
||||||
M.PrintSummary(SummaryOut);
|
M.PrintSummary(SummaryOut);
|
||||||
}
|
}
|
||||||
std::vector<std::string> NewFiles;
|
fuzzer::vector<std::string> NewFiles;
|
||||||
std::set<uint32_t> InitialFeatures;
|
std::set<uint32_t> InitialFeatures;
|
||||||
if (CoverageSummaryInputPathOrNull) {
|
if (CoverageSummaryInputPathOrNull) {
|
||||||
std::ifstream SummaryIn(CoverageSummaryInputPathOrNull);
|
std::ifstream SummaryIn(CoverageSummaryInputPathOrNull);
|
||||||
|
|
|
@ -52,11 +52,11 @@ namespace fuzzer {
|
||||||
struct MergeFileInfo {
|
struct MergeFileInfo {
|
||||||
std::string Name;
|
std::string Name;
|
||||||
size_t Size = 0;
|
size_t Size = 0;
|
||||||
std::vector<uint32_t> Features;
|
fuzzer::vector<uint32_t> Features;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Merger {
|
struct Merger {
|
||||||
std::vector<MergeFileInfo> Files;
|
fuzzer::vector<MergeFileInfo> Files;
|
||||||
size_t NumFilesInFirstCorpus = 0;
|
size_t NumFilesInFirstCorpus = 0;
|
||||||
size_t FirstNotProcessedFile = 0;
|
size_t FirstNotProcessedFile = 0;
|
||||||
std::string LastFailure;
|
std::string LastFailure;
|
||||||
|
@ -67,8 +67,8 @@ struct Merger {
|
||||||
void PrintSummary(std::ostream &OS);
|
void PrintSummary(std::ostream &OS);
|
||||||
std::set<uint32_t> ParseSummary(std::istream &IS);
|
std::set<uint32_t> ParseSummary(std::istream &IS);
|
||||||
size_t Merge(const std::set<uint32_t> &InitialFeatures,
|
size_t Merge(const std::set<uint32_t> &InitialFeatures,
|
||||||
std::vector<std::string> *NewFiles);
|
fuzzer::vector<std::string> *NewFiles);
|
||||||
size_t Merge(std::vector<std::string> *NewFiles) {
|
size_t Merge(fuzzer::vector<std::string> *NewFiles) {
|
||||||
return Merge(std::set<uint32_t>{}, NewFiles);
|
return Merge(std::set<uint32_t>{}, NewFiles);
|
||||||
}
|
}
|
||||||
size_t ApproximateMemoryConsumption() const;
|
size_t ApproximateMemoryConsumption() const;
|
||||||
|
|
|
@ -466,7 +466,7 @@ void MutationDispatcher::RecordSuccessfulMutationSequence() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MutationDispatcher::PrintRecommendedDictionary() {
|
void MutationDispatcher::PrintRecommendedDictionary() {
|
||||||
std::vector<DictionaryEntry> V;
|
fuzzer::vector<DictionaryEntry> V;
|
||||||
for (auto &DE : PersistentAutoDictionary)
|
for (auto &DE : PersistentAutoDictionary)
|
||||||
if (!ManualDictionary.ContainsWord(DE.GetW()))
|
if (!ManualDictionary.ContainsWord(DE.GetW()))
|
||||||
V.push_back(DE);
|
V.push_back(DE);
|
||||||
|
@ -506,7 +506,7 @@ size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size,
|
||||||
// Mutates Data in place, returns new size.
|
// Mutates Data in place, returns new size.
|
||||||
size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,
|
size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,
|
||||||
size_t MaxSize,
|
size_t MaxSize,
|
||||||
const std::vector<Mutator> &Mutators) {
|
const fuzzer::vector<Mutator> &Mutators) {
|
||||||
assert(MaxSize > 0);
|
assert(MaxSize > 0);
|
||||||
// Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize),
|
// Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize),
|
||||||
// in which case they will return 0.
|
// in which case they will return 0.
|
||||||
|
|
|
@ -96,7 +96,7 @@ private:
|
||||||
size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size,
|
size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size,
|
||||||
size_t MaxSize);
|
size_t MaxSize);
|
||||||
size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize,
|
size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize,
|
||||||
const std::vector<Mutator> &Mutators);
|
const fuzzer::vector<Mutator> &Mutators);
|
||||||
|
|
||||||
size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
|
size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
|
||||||
size_t ToSize, size_t MaxToSize);
|
size_t ToSize, size_t MaxToSize);
|
||||||
|
@ -128,21 +128,21 @@ private:
|
||||||
// entries that led to successfull discoveries in the past mutations.
|
// entries that led to successfull discoveries in the past mutations.
|
||||||
Dictionary PersistentAutoDictionary;
|
Dictionary PersistentAutoDictionary;
|
||||||
|
|
||||||
std::vector<Mutator> CurrentMutatorSequence;
|
fuzzer::vector<Mutator> CurrentMutatorSequence;
|
||||||
std::vector<DictionaryEntry *> CurrentDictionaryEntrySequence;
|
fuzzer::vector<DictionaryEntry *> CurrentDictionaryEntrySequence;
|
||||||
|
|
||||||
static const size_t kCmpDictionaryEntriesDequeSize = 16;
|
static const size_t kCmpDictionaryEntriesDequeSize = 16;
|
||||||
DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize];
|
DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize];
|
||||||
size_t CmpDictionaryEntriesDequeIdx = 0;
|
size_t CmpDictionaryEntriesDequeIdx = 0;
|
||||||
|
|
||||||
const InputCorpus *Corpus = nullptr;
|
const InputCorpus *Corpus = nullptr;
|
||||||
std::vector<uint8_t> MutateInPlaceHere;
|
fuzzer::vector<uint8_t> MutateInPlaceHere;
|
||||||
// CustomCrossOver needs its own buffer as a custom implementation may call
|
// CustomCrossOver needs its own buffer as a custom implementation may call
|
||||||
// LLVMFuzzerMutate, which in turn may resize MutateInPlaceHere.
|
// LLVMFuzzerMutate, which in turn may resize MutateInPlaceHere.
|
||||||
std::vector<uint8_t> CustomCrossOverInPlaceHere;
|
fuzzer::vector<uint8_t> CustomCrossOverInPlaceHere;
|
||||||
|
|
||||||
std::vector<Mutator> Mutators;
|
fuzzer::vector<Mutator> Mutators;
|
||||||
std::vector<Mutator> DefaultMutators;
|
fuzzer::vector<Mutator> DefaultMutators;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fuzzer
|
} // namespace fuzzer
|
||||||
|
|
|
@ -270,7 +270,7 @@ void TracePC::PrintCoverage() {
|
||||||
|
|
||||||
void TracePC::DumpCoverage() {
|
void TracePC::DumpCoverage() {
|
||||||
if (EF->__sanitizer_dump_coverage) {
|
if (EF->__sanitizer_dump_coverage) {
|
||||||
std::vector<uintptr_t> PCsCopy(GetNumPCs());
|
fuzzer::vector<uintptr_t> PCsCopy(GetNumPCs());
|
||||||
for (size_t i = 0; i < GetNumPCs(); i++)
|
for (size_t i = 0; i < GetNumPCs(); i++)
|
||||||
PCsCopy[i] = PCs()[i] ? GetPreviousInstructionPc(PCs()[i]) : 0;
|
PCsCopy[i] = PCs()[i] ? GetPreviousInstructionPc(PCs()[i]) : 0;
|
||||||
EF->__sanitizer_dump_coverage(PCsCopy.data(), PCsCopy.size());
|
EF->__sanitizer_dump_coverage(PCsCopy.data(), PCsCopy.size());
|
||||||
|
|
|
@ -124,7 +124,7 @@ bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units) {
|
bool ParseDictionaryFile(const std::string &Text, fuzzer::vector<Unit> *Units) {
|
||||||
if (Text.empty()) {
|
if (Text.empty()) {
|
||||||
Printf("ParseDictionaryFile: file does not exist or is empty\n");
|
Printf("ParseDictionaryFile: file does not exist or is empty\n");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -57,10 +57,10 @@ FILE *OpenProcessPipe(const char *Command, const char *Mode);
|
||||||
const void *SearchMemory(const void *haystack, size_t haystacklen,
|
const void *SearchMemory(const void *haystack, size_t haystacklen,
|
||||||
const void *needle, size_t needlelen);
|
const void *needle, size_t needlelen);
|
||||||
|
|
||||||
std::string CloneArgsWithoutX(const std::vector<std::string> &Args,
|
std::string CloneArgsWithoutX(const fuzzer::vector<std::string> &Args,
|
||||||
const char *X1, const char *X2);
|
const char *X1, const char *X2);
|
||||||
|
|
||||||
inline std::string CloneArgsWithoutX(const std::vector<std::string> &Args,
|
inline std::string CloneArgsWithoutX(const fuzzer::vector<std::string> &Args,
|
||||||
const char *X) {
|
const char *X) {
|
||||||
return CloneArgsWithoutX(Args, X, X);
|
return CloneArgsWithoutX(Args, X, X);
|
||||||
}
|
}
|
||||||
|
|
|
@ -526,7 +526,7 @@ TEST(FuzzerDictionary, ParseOneDictionaryEntry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FuzzerDictionary, ParseDictionaryFile) {
|
TEST(FuzzerDictionary, ParseDictionaryFile) {
|
||||||
std::vector<Unit> Units;
|
fuzzer::vector<Unit> Units;
|
||||||
EXPECT_FALSE(ParseDictionaryFile("zzz\n", &Units));
|
EXPECT_FALSE(ParseDictionaryFile("zzz\n", &Units));
|
||||||
EXPECT_FALSE(ParseDictionaryFile("", &Units));
|
EXPECT_FALSE(ParseDictionaryFile("", &Units));
|
||||||
EXPECT_TRUE(ParseDictionaryFile("\n", &Units));
|
EXPECT_TRUE(ParseDictionaryFile("\n", &Units));
|
||||||
|
@ -538,11 +538,11 @@ TEST(FuzzerDictionary, ParseDictionaryFile) {
|
||||||
EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units));
|
EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units));
|
||||||
EXPECT_EQ(Units.size(), 0U);
|
EXPECT_EQ(Units.size(), 0U);
|
||||||
EXPECT_TRUE(ParseDictionaryFile(" #zzzz\naaa=\"aa\"", &Units));
|
EXPECT_TRUE(ParseDictionaryFile(" #zzzz\naaa=\"aa\"", &Units));
|
||||||
EXPECT_EQ(Units, std::vector<Unit>({Unit({'a', 'a'})}));
|
EXPECT_EQ(Units, fuzzer::vector<Unit>({Unit({'a', 'a'})}));
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
ParseDictionaryFile(" #zzzz\naaa=\"aa\"\n\nabc=\"abc\"", &Units));
|
ParseDictionaryFile(" #zzzz\naaa=\"aa\"\n\nabc=\"abc\"", &Units));
|
||||||
EXPECT_EQ(Units,
|
EXPECT_EQ(Units,
|
||||||
std::vector<Unit>({Unit({'a', 'a'}), Unit({'a', 'b', 'c'})}));
|
fuzzer::vector<Unit>({Unit({'a', 'a'}), Unit({'a', 'b', 'c'})}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FuzzerUtil, Base64) {
|
TEST(FuzzerUtil, Base64) {
|
||||||
|
@ -566,7 +566,7 @@ TEST(Corpus, Distribution) {
|
||||||
for (size_t i = 0; i < N; i++)
|
for (size_t i = 0; i < N; i++)
|
||||||
C->AddToCorpus(Unit{ static_cast<uint8_t>(i) }, 1, false, {});
|
C->AddToCorpus(Unit{ static_cast<uint8_t>(i) }, 1, false, {});
|
||||||
|
|
||||||
std::vector<size_t> Hist(N);
|
fuzzer::vector<size_t> Hist(N);
|
||||||
for (size_t i = 0; i < N * TriesPerUnit; i++) {
|
for (size_t i = 0; i < N * TriesPerUnit; i++) {
|
||||||
Hist[C->ChooseUnitIdxToMutate(Rand)]++;
|
Hist[C->ChooseUnitIdxToMutate(Rand)]++;
|
||||||
}
|
}
|
||||||
|
@ -596,21 +596,21 @@ TEST(Merge, Bad) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQ(const std::vector<uint32_t> &A, const std::vector<uint32_t> &B) {
|
void EQ(const fuzzer::vector<uint32_t> &A, const fuzzer::vector<uint32_t> &B) {
|
||||||
EXPECT_EQ(A, B);
|
EXPECT_EQ(A, B);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQ(const std::vector<std::string> &A, const std::vector<std::string> &B) {
|
void EQ(const fuzzer::vector<std::string> &A, const fuzzer::vector<std::string> &B) {
|
||||||
std::set<std::string> a(A.begin(), A.end());
|
std::set<std::string> a(A.begin(), A.end());
|
||||||
std::set<std::string> b(B.begin(), B.end());
|
std::set<std::string> b(B.begin(), B.end());
|
||||||
EXPECT_EQ(a, b);
|
EXPECT_EQ(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Merge(const std::string &Input,
|
static void Merge(const std::string &Input,
|
||||||
const std::vector<std::string> Result,
|
const fuzzer::vector<std::string> Result,
|
||||||
size_t NumNewFeatures) {
|
size_t NumNewFeatures) {
|
||||||
Merger M;
|
Merger M;
|
||||||
std::vector<std::string> NewFiles;
|
fuzzer::vector<std::string> NewFiles;
|
||||||
EXPECT_TRUE(M.Parse(Input, true));
|
EXPECT_TRUE(M.Parse(Input, true));
|
||||||
std::stringstream SS;
|
std::stringstream SS;
|
||||||
M.PrintSummary(SS);
|
M.PrintSummary(SS);
|
||||||
|
@ -658,7 +658,7 @@ TEST(Merge, Good) {
|
||||||
EQ(M.Files[1].Features, {4, 5, 6});
|
EQ(M.Files[1].Features, {4, 5, 6});
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::string> NewFiles;
|
fuzzer::vector<std::string> NewFiles;
|
||||||
|
|
||||||
EXPECT_TRUE(M.Parse("3\n2\nAA\nBB\nC\n"
|
EXPECT_TRUE(M.Parse("3\n2\nAA\nBB\nC\n"
|
||||||
"STARTED 0 1000\nDONE 0 1 2 3\n"
|
"STARTED 0 1000\nDONE 0 1 2 3\n"
|
||||||
|
@ -739,7 +739,7 @@ TEST(Fuzzer, ForEachNonZeroByte) {
|
||||||
0, 0, 0, 0, 0, 0, 0, 8,
|
0, 0, 0, 0, 0, 0, 0, 8,
|
||||||
9, 9, 9, 9, 9, 9, 9, 9,
|
9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
};
|
};
|
||||||
typedef std::vector<std::pair<size_t, uint8_t> > Vec;
|
typedef fuzzer::vector<std::pair<size_t, uint8_t> > Vec;
|
||||||
Vec Res, Expected;
|
Vec Res, Expected;
|
||||||
auto CB = [&](size_t FirstFeature, size_t Idx, uint8_t V) {
|
auto CB = [&](size_t FirstFeature, size_t Idx, uint8_t V) {
|
||||||
Res.push_back({FirstFeature + Idx, V});
|
Res.push_back({FirstFeature + Idx, V});
|
||||||
|
|
Loading…
Reference in New Issue