Source code
Revision control
Copy as Markdown
Other Tools
commit f80733b3b1b5e05e7dfd7a071f60050fe20108c3
Author: Jesse Schwartzentruber <truber@mozilla.com>
Date: Mon Mar 1 15:47:38 2021 -0500
[libfuzzer] In most cases, return instead of exit().
diff --git a/FuzzerDataFlowTrace.cpp b/FuzzerDataFlowTrace.cpp
index 0e9cdf7e66b1..06ea287a3cfe 100644
--- a/FuzzerDataFlowTrace.cpp
+++ b/FuzzerDataFlowTrace.cpp
@@ -102,9 +102,11 @@ Vector<double> BlockCoverage::FunctionWeights(size_t NumFunctions) const {
return Res;
}
-void DataFlowTrace::ReadCoverage(const std::string &DirPath) {
+int DataFlowTrace::ReadCoverage(const std::string &DirPath) {
Vector<SizedFile> Files;
- GetSizedFilesFromDir(DirPath, &Files);
+ int Res = GetSizedFilesFromDir(DirPath, &Files);
+ if (Res != 0)
+ return Res;
for (auto &SF : Files) {
auto Name = Basename(SF.File);
if (Name == kFunctionsTxt) continue;
@@ -112,6 +114,7 @@ void DataFlowTrace::ReadCoverage(const std::string &DirPath) {
std::ifstream IF(SF.File);
Coverage.AppendCoverage(IF);
}
+ return 0;
}
static void DFTStringAppendToVector(Vector<uint8_t> *DFT,
@@ -157,12 +160,14 @@ static bool ParseDFTLine(const std::string &Line, size_t *FunctionNum,
return true;
}
-bool DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction,
+int DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction,
Vector<SizedFile> &CorporaFiles, Random &Rand) {
- if (DirPath.empty()) return false;
+ if (DirPath.empty()) return 0;
Printf("INFO: DataFlowTrace: reading from '%s'\n", DirPath.c_str());
Vector<SizedFile> Files;
- GetSizedFilesFromDir(DirPath, &Files);
+ int Res = GetSizedFilesFromDir(DirPath, &Files);
+ if (Res != 0)
+ return Res;
std::string L;
size_t FocusFuncIdx = SIZE_MAX;
Vector<std::string> FunctionNames;
@@ -181,14 +186,16 @@ bool DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction,
FocusFuncIdx = NumFunctions - 1;
}
if (!NumFunctions)
- return false;
+ return 0;
if (*FocusFunction == "auto") {
// AUTOFOCUS works like this:
// * reads the coverage data from the DFT files.
// * assigns weights to functions based on coverage.
// * chooses a random function according to the weights.
- ReadCoverage(DirPath);
+ Res = ReadCoverage(DirPath);
+ if (Res != 0)
+ return Res;
auto Weights = Coverage.FunctionWeights(NumFunctions);
Vector<double> Intervals(NumFunctions + 1);
std::iota(Intervals.begin(), Intervals.end(), 0);
@@ -209,7 +216,7 @@ bool DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction,
}
if (!NumFunctions || FocusFuncIdx == SIZE_MAX || Files.size() <= 1)
- return false;
+ return 0;
// Read traces.
size_t NumTraceFiles = 0;
@@ -228,8 +235,10 @@ bool DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction,
FunctionNum == FocusFuncIdx) {
NumTracesWithFocusFunction++;
- if (FunctionNum >= NumFunctions)
- return ParseError("N is greater than the number of functions", L);
+ if (FunctionNum >= NumFunctions) {
+ ParseError("N is greater than the number of functions", L);
+ return 0;
+ }
Traces[Name] = DFTStringToVector(DFTString);
// Print just a few small traces.
if (NumTracesWithFocusFunction <= 3 && DFTString.size() <= 16)
@@ -241,7 +250,7 @@ bool DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction,
Printf("INFO: DataFlowTrace: %zd trace files, %zd functions, "
"%zd traces with focus function\n",
NumTraceFiles, NumFunctions, NumTracesWithFocusFunction);
- return NumTraceFiles > 0;
+ return 0;
}
int CollectDataFlow(const std::string &DFTBinary, const std::string &DirPath,
diff --git a/FuzzerDataFlowTrace.h b/FuzzerDataFlowTrace.h
index d6e3de30a4ef..767bad24f1d0 100644
--- a/FuzzerDataFlowTrace.h
+++ b/FuzzerDataFlowTrace.h
@@ -113,8 +113,8 @@ class BlockCoverage {
class DataFlowTrace {
public:
- void ReadCoverage(const std::string &DirPath);
- bool Init(const std::string &DirPath, std::string *FocusFunction,
+ int ReadCoverage(const std::string &DirPath);
+ int Init(const std::string &DirPath, std::string *FocusFunction,
Vector<SizedFile> &CorporaFiles, Random &Rand);
void Clear() { Traces.clear(); }
const Vector<uint8_t> *Get(const std::string &InputSha1) const {
diff --git a/FuzzerDriver.cpp b/FuzzerDriver.cpp
index cd720200848b..bedad16efa7b 100644
--- a/FuzzerDriver.cpp
+++ b/FuzzerDriver.cpp
@@ -326,7 +326,7 @@ int CleanseCrashInput(const Vector<std::string> &Args,
if (Inputs->size() != 1 || !Flags.exact_artifact_path) {
Printf("ERROR: -cleanse_crash should be given one input file and"
" -exact_artifact_path\n");
- exit(1);
+ return 1;
}
std::string InputFilePath = Inputs->at(0);
std::string OutputFilePath = Flags.exact_artifact_path;
@@ -380,7 +380,7 @@ int MinimizeCrashInput(const Vector<std::string> &Args,
const FuzzingOptions &Options) {
if (Inputs->size() != 1) {
Printf("ERROR: -minimize_crash should be given one input file\n");
- exit(1);
+ return 1;
}
std::string InputFilePath = Inputs->at(0);
Command BaseCmd(Args);
@@ -411,7 +411,7 @@ int MinimizeCrashInput(const Vector<std::string> &Args,
bool Success = ExecuteCommand(Cmd, &CmdOutput);
if (Success) {
Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str());
- exit(1);
+ return 1;
}
Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize "
"it further\n",
@@ -466,42 +466,51 @@ int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) {
Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size());
if (U.size() < 2) {
Printf("INFO: The input is small enough, exiting\n");
- exit(0);
+ return 0;
}
F->SetMaxInputLen(U.size());
F->SetMaxMutationLen(U.size() - 1);
F->MinimizeCrashLoop(U);
Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n");
- exit(0);
return 0;
}
-void Merge(Fuzzer *F, FuzzingOptions &Options, const Vector<std::string> &Args,
+int Merge(Fuzzer *F, FuzzingOptions &Options, const Vector<std::string> &Args,
const Vector<std::string> &Corpora, const char *CFPathOrNull) {
if (Corpora.size() < 2) {
Printf("INFO: Merge requires two or more corpus dirs\n");
- exit(0);
+ return 0;
}
Vector<SizedFile> OldCorpus, NewCorpus;
- GetSizedFilesFromDir(Corpora[0], &OldCorpus);
- for (size_t i = 1; i < Corpora.size(); i++)
- GetSizedFilesFromDir(Corpora[i], &NewCorpus);
+ int Res = GetSizedFilesFromDir(Corpora[0], &OldCorpus);
+ if (Res != 0)
+ return Res;
+ for (size_t i = 1; i < Corpora.size(); i++) {
+ Res = GetSizedFilesFromDir(Corpora[i], &NewCorpus);
+ if (Res != 0)
+ return Res;
+ }
std::sort(OldCorpus.begin(), OldCorpus.end());
std::sort(NewCorpus.begin(), NewCorpus.end());
std::string CFPath = CFPathOrNull ? CFPathOrNull : TempPath("Merge", ".txt");
Vector<std::string> NewFiles;
Set<uint32_t> NewFeatures, NewCov;
- CrashResistantMerge(Args, OldCorpus, NewCorpus, &NewFiles, {}, &NewFeatures,
+ Res = CrashResistantMerge(Args, OldCorpus, NewCorpus, &NewFiles, {}, &NewFeatures,
{}, &NewCov, CFPath, true);
+ if (Res != 0)
+ return Res;
+
+ if (F->isGracefulExitRequested())
+ return 0;
for (auto &Path : NewFiles)
F->WriteToOutputCorpus(FileToVector(Path, Options.MaxLen));
// We are done, delete the control file if it was a temporary one.
if (!Flags.merge_control_file)
RemoveFile(CFPath);
- exit(0);
+ return 0;
}
int AnalyzeDictionary(Fuzzer *F, const Vector<Unit>& Dict,
@@ -570,10 +579,9 @@ int AnalyzeDictionary(Fuzzer *F, const Vector<Unit>& Dict,
return 0;
}
-Vector<std::string> ParseSeedInuts(const char *seed_inputs) {
+int ParseSeedInuts(const char *seed_inputs, Vector<std::string> &Files) {
// Parse -seed_inputs=file1,file2,... or -seed_inputs=@seed_inputs_file
- Vector<std::string> Files;
- if (!seed_inputs) return Files;
+ if (!seed_inputs) return 0;
std::string SeedInputs;
if (Flags.seed_inputs[0] == '@')
SeedInputs = FileToString(Flags.seed_inputs + 1); // File contains list.
@@ -581,7 +589,7 @@ Vector<std::string> ParseSeedInuts(const char *seed_inputs) {
SeedInputs = Flags.seed_inputs; // seed_inputs contains the list.
if (SeedInputs.empty()) {
Printf("seed_inputs is empty or @file does not exist.\n");
- exit(1);
+ return 1;
}
// Parse SeedInputs.
size_t comma_pos = 0;
@@ -590,7 +598,7 @@ Vector<std::string> ParseSeedInuts(const char *seed_inputs) {
SeedInputs = SeedInputs.substr(0, comma_pos);
}
Files.push_back(SeedInputs);
- return Files;
+ return 0;
}
static Vector<SizedFile> ReadCorpora(const Vector<std::string> &CorpusDirs,
@@ -624,7 +632,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
ProgName = new std::string(Args[0]);
if (Argv0 != *ProgName) {
Printf("ERROR: argv[0] has been modified in LLVMFuzzerInitialize\n");
- exit(1);
+ return 1;
}
ParseFlags(Args, EF);
if (Flags.help) {
@@ -723,7 +731,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
if (!Options.FocusFunction.empty()) {
Printf("ERROR: The parameters `--entropic` and `--focus_function` cannot "
"be used together.\n");
- exit(1);
+ return 1;
}
Printf("INFO: Running with entropic power schedule (0x%X, %d).\n",
Options.EntropicFeatureFrequencyThreshold,
@@ -809,22 +817,21 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
"*** executed the target code on a fixed set of inputs.\n"
"***\n");
F->PrintFinalStats();
- exit(0);
+ return 0;
}
if (Flags.fork)
- FuzzWithFork(F->GetMD().GetRand(), Options, Args, *Inputs, Flags.fork);
+ return FuzzWithFork(F->GetMD().GetRand(), Options, Args, *Inputs, Flags.fork);
if (Flags.merge)
- Merge(F, Options, Args, *Inputs, Flags.merge_control_file);
+ return Merge(F, Options, Args, *Inputs, Flags.merge_control_file);
if (Flags.merge_inner) {
const size_t kDefaultMaxMergeLen = 1 << 20;
if (Options.MaxLen == 0)
F->SetMaxInputLen(kDefaultMaxMergeLen);
assert(Flags.merge_control_file);
- F->CrashResistantMergeInternalStep(Flags.merge_control_file);
- exit(0);
+ return F->CrashResistantMergeInternalStep(Flags.merge_control_file);
}
if (Flags.analyze_dict) {
@@ -842,21 +849,31 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
}
if (AnalyzeDictionary(F, Dictionary, InitialCorpus)) {
Printf("Dictionary analysis failed\n");
- exit(1);
+ return 1;
}
Printf("Dictionary analysis succeeded\n");
- exit(0);
+ return 0;
}
- auto CorporaFiles = ReadCorpora(*Inputs, ParseSeedInuts(Flags.seed_inputs));
- F->Loop(CorporaFiles);
+ {
+ Vector<std::string> Files;
+ int Res = ParseSeedInuts(Flags.seed_inputs, Files);
+ if (Res != 0)
+ return Res;
+ auto CorporaFiles = ReadCorpora(*Inputs, Files);
+ Res = F->Loop(CorporaFiles);
+ if (Res != 0)
+ return Res;
+ if (F->isGracefulExitRequested())
+ return 0;
+ }
if (Flags.verbosity)
Printf("Done %zd runs in %zd second(s)\n", F->getTotalNumberOfRuns(),
F->secondsSinceProcessStartUp());
F->PrintFinalStats();
- exit(0); // Don't let F destroy itself.
+ return 0; // Don't let F destroy itself.
}
extern "C" ATTRIBUTE_INTERFACE int
diff --git a/FuzzerFork.cpp b/FuzzerFork.cpp
index d9e6b79443e0..ee2a99a250c1 100644
--- a/FuzzerFork.cpp
+++ b/FuzzerFork.cpp
@@ -177,14 +177,16 @@ struct GlobalEnv {
return Job;
}
- void RunOneMergeJob(FuzzJob *Job) {
+ int RunOneMergeJob(FuzzJob *Job) {
auto Stats = ParseFinalStatsFromLog(Job->LogPath);
NumRuns += Stats.number_of_executed_units;
Vector<SizedFile> TempFiles, MergeCandidates;
// Read all newly created inputs and their feature sets.
// Choose only those inputs that have new features.
- GetSizedFilesFromDir(Job->CorpusDir, &TempFiles);
+ int Res = GetSizedFilesFromDir(Job->CorpusDir, &TempFiles);
+ if (Res != 0)
+ return Res;
std::sort(TempFiles.begin(), TempFiles.end());
for (auto &F : TempFiles) {
auto FeatureFile = F.File;
@@ -207,12 +209,14 @@ struct GlobalEnv {
Stats.average_exec_per_sec, NumOOMs, NumTimeouts, NumCrashes,
secondsSinceProcessStartUp(), Job->JobId, Job->DftTimeInSeconds);
- if (MergeCandidates.empty()) return;
+ if (MergeCandidates.empty()) return 0;
Vector<std::string> FilesToAdd;
Set<uint32_t> NewFeatures, NewCov;
CrashResistantMerge(Args, {}, MergeCandidates, &FilesToAdd, Features,
&NewFeatures, Cov, &NewCov, Job->CFPath, false);
+ if (Fuzzer::isGracefulExitRequested())
+ return 0;
for (auto &Path : FilesToAdd) {
auto U = FileToVector(Path);
auto NewPath = DirPlusFile(MainCorpusDir, Hash(U));
@@ -226,7 +230,7 @@ struct GlobalEnv {
if (TPC.PcIsFuncEntry(TE))
PrintPC(" NEW_FUNC: %p %F %L\n", "",
TPC.GetNextInstructionPc(TE->PC));
-
+ return 0;
}
@@ -280,7 +284,7 @@ void WorkerThread(JobQueue *FuzzQ, JobQueue *MergeQ) {
}
// This is just a skeleton of an experimental -fork=1 feature.
-void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
+int FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
const Vector<std::string> &Args,
const Vector<std::string> &CorpusDirs, int NumJobs) {
Printf("INFO: -fork=%d: fuzzing in separate process(s)\n", NumJobs);
@@ -294,8 +298,12 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
Env.DataFlowBinary = Options.CollectDataFlow;
Vector<SizedFile> SeedFiles;
- for (auto &Dir : CorpusDirs)
- GetSizedFilesFromDir(Dir, &SeedFiles);
+ int Res;
+ for (auto &Dir : CorpusDirs) {
+ Res = GetSizedFilesFromDir(Dir, &SeedFiles);
+ if (Res != 0)
+ return Res;
+ }
std::sort(SeedFiles.begin(), SeedFiles.end());
Env.TempDir = TempPath("FuzzWithFork", ".dir");
Env.DFTDir = DirPlusFile(Env.TempDir, "DFT");
@@ -310,9 +318,14 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
Env.MainCorpusDir = CorpusDirs[0];
auto CFPath = DirPlusFile(Env.TempDir, "merge.txt");
- CrashResistantMerge(Env.Args, {}, SeedFiles, &Env.Files, {}, &Env.Features,
+ Res = CrashResistantMerge(Env.Args, {}, SeedFiles, &Env.Files, {}, &Env.Features,
{}, &Env.Cov,
CFPath, false);
+ if (Res != 0)
+ return Res;
+ if (Fuzzer::isGracefulExitRequested())
+ return 0;
+
RemoveFile(CFPath);
Printf("INFO: -fork=%d: %zd seed inputs, starting to fuzz in %s\n", NumJobs,
Env.Files.size(), Env.TempDir.c_str());
@@ -345,9 +358,14 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
StopJobs();
break;
}
- Fuzzer::MaybeExitGracefully();
+ if (Fuzzer::MaybeExitGracefully())
+ return 0;
- Env.RunOneMergeJob(Job.get());
+ Res = Env.RunOneMergeJob(Job.get());
+ if (Res != 0)
+ return Res;
+ if (Fuzzer::isGracefulExitRequested())
+ return 0;
// Continue if our crash is one of the ignorred ones.
if (Options.IgnoreTimeouts && ExitCode == Options.TimeoutExitCode)
@@ -403,7 +421,7 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
// Use the exit code from the last child process.
Printf("INFO: exiting: %d time: %zds\n", ExitCode,
Env.secondsSinceProcessStartUp());
- exit(ExitCode);
+ return ExitCode;
}
} // namespace fuzzer
diff --git a/FuzzerFork.h b/FuzzerFork.h
index b29a43e13fbc..1352171ad49d 100644
--- a/FuzzerFork.h
+++ b/FuzzerFork.h
@@ -16,7 +16,7 @@
#include <string>
namespace fuzzer {
-void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
+int FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
const Vector<std::string> &Args,
const Vector<std::string> &CorpusDirs, int NumJobs);
} // namespace fuzzer
diff --git a/FuzzerIO.cpp b/FuzzerIO.cpp
index 0053ef39f2b9..6be2be67c691 100644
--- a/FuzzerIO.cpp
+++ b/FuzzerIO.cpp
@@ -82,7 +82,9 @@ void ReadDirToVectorOfUnits(const char *Path, Vector<Unit> *V,
long *Epoch, size_t MaxSize, bool ExitOnError) {
long E = Epoch ? *Epoch : 0;
Vector<std::string> Files;
- ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true);
+ int Res = ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true);
+ if (ExitOnError && Res != 0)
+ exit(Res);
size_t NumLoaded = 0;
for (size_t i = 0; i < Files.size(); i++) {
auto &X = Files[i];
@@ -97,12 +99,15 @@ void ReadDirToVectorOfUnits(const char *Path, Vector<Unit> *V,
}
-void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V) {
+int GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V) {
Vector<std::string> Files;
- ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/true);
+ int Res = ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/true);
+ if (Res != 0)
+ return Res;
for (auto &File : Files)
if (size_t Size = FileSize(File))
V->push_back({File, Size});
+ return 0;
}
std::string DirPlusFile(const std::string &DirPath,
diff --git a/FuzzerIO.h b/FuzzerIO.h
index 6e4368b971fa..6c90ba637322 100644
--- a/FuzzerIO.h
+++ b/FuzzerIO.h
@@ -60,7 +60,7 @@ void RawPrint(const char *Str);
bool IsFile(const std::string &Path);
size_t FileSize(const std::string &Path);
-void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
+int ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
Vector<std::string> *V, bool TopDir);
void RmDirRecursive(const std::string &Dir);
@@ -79,7 +79,7 @@ struct SizedFile {
bool operator<(const SizedFile &B) const { return Size < B.Size; }
};
-void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V);
+int GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V);
char GetSeparator();
// Similar to the basename utility: returns the file name w/o the dir prefix.
diff --git a/FuzzerIOPosix.cpp b/FuzzerIOPosix.cpp
index 4b453d286c80..1a50295c010f 100644
--- a/FuzzerIOPosix.cpp
+++ b/FuzzerIOPosix.cpp
@@ -53,16 +53,16 @@ std::string Basename(const std::string &Path) {
return Path.substr(Pos + 1);
}
-void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
+int ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
Vector<std::string> *V, bool TopDir) {
auto E = GetEpoch(Dir);
if (Epoch)
- if (E && *Epoch >= E) return;
+ if (E && *Epoch >= E) return 0;
DIR *D = opendir(Dir.c_str());
if (!D) {
Printf("%s: %s; exiting\n", strerror(errno), Dir.c_str());
- exit(1);
+ return 1;
}
while (auto E = readdir(D)) {
std::string Path = DirPlusFile(Dir, E->d_name);
@@ -71,12 +71,16 @@ void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
V->push_back(Path);
else if ((E->d_type == DT_DIR ||
(E->d_type == DT_UNKNOWN && IsDirectory(Path))) &&
- *E->d_name != '.')
- ListFilesInDirRecursive(Path, Epoch, V, false);
+ *E->d_name != '.') {
+ int Res = ListFilesInDirRecursive(Path, Epoch, V, false);
+ if (Res != 0)
+ return Res;
+ }
}
closedir(D);
if (Epoch && TopDir)
*Epoch = E;
+ return 0;
}
diff --git a/FuzzerIOWindows.cpp b/FuzzerIOWindows.cpp
index 651283a551cf..0e977bd02557 100644
--- a/FuzzerIOWindows.cpp
+++ b/FuzzerIOWindows.cpp
@@ -98,11 +98,12 @@ size_t FileSize(const std::string &Path) {
return size.QuadPart;
}
-void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
+int ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
Vector<std::string> *V, bool TopDir) {
+ int Res;
auto E = GetEpoch(Dir);
if (Epoch)
- if (E && *Epoch >= E) return;
+ if (E && *Epoch >= E) return 0;
std::string Path(Dir);
assert(!Path.empty());
@@ -116,9 +117,9 @@ void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
if (FindHandle == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
- return;
+ return 0;
Printf("No such file or directory: %s; exiting\n", Dir.c_str());
- exit(1);
+ return 1;
}
do {
@@ -131,7 +132,9 @@ void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
FindInfo.cFileName[1] == '.'))
continue;
- ListFilesInDirRecursive(FileName, Epoch, V, false);
+ int Res = ListFilesInDirRecursive(FileName, Epoch, V, false);
+ if (Res != 0)
+ return Res;
}
else if (IsFile(FileName, FindInfo.dwFileAttributes))
V->push_back(FileName);
@@ -145,6 +148,7 @@ void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
if (Epoch && TopDir)
*Epoch = E;
+ return 0;
}
diff --git a/FuzzerInternal.h b/FuzzerInternal.h
index 1f7d671ed848..cc2650b58ef1 100644
--- a/FuzzerInternal.h
+++ b/FuzzerInternal.h
@@ -35,8 +35,8 @@ public:
Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
FuzzingOptions Options);
~Fuzzer();
- void Loop(Vector<SizedFile> &CorporaFiles);
- void ReadAndExecuteSeedCorpora(Vector<SizedFile> &CorporaFiles);
+ int Loop(Vector<SizedFile> &CorporaFiles);
+ int ReadAndExecuteSeedCorpora(Vector<SizedFile> &CorporaFiles);
void MinimizeCrashLoop(const Unit &U);
void RereadOutputCorpus(size_t MaxSize);
@@ -65,13 +65,16 @@ public:
static void StaticFileSizeExceedCallback();
static void StaticGracefulExitCallback();
+ static void GracefullyExit();
+ static bool isGracefulExitRequested();
+
int ExecuteCallback(const uint8_t *Data, size_t Size);
bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false,
InputInfo *II = nullptr, bool *FoundUniqFeatures = nullptr);
// Merge Corpora[1:] into Corpora[0].
void Merge(const Vector<std::string> &Corpora);
- void CrashResistantMergeInternalStep(const std::string &ControlFilePath);
+ int CrashResistantMergeInternalStep(const std::string &ControlFilePath);
MutationDispatcher &GetMD() { return MD; }
void PrintFinalStats();
void SetMaxInputLen(size_t MaxInputLen);
@@ -84,7 +87,7 @@ public:
bool DuringInitialCorpusExecution);
void HandleMalloc(size_t Size);
- static void MaybeExitGracefully();
+ static bool MaybeExitGracefully();
std::string WriteToOutputCorpus(const Unit &U);
private:
@@ -93,7 +96,7 @@ private:
void ExitCallback();
void CrashOnOverwrittenData();
void InterruptCallback();
- void MutateAndTestOne();
+ bool MutateAndTestOne();
void PurgeAllocator();
void ReportNewCoverage(InputInfo *II, const Unit &U);
void PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size);
diff --git a/FuzzerLoop.cpp b/FuzzerLoop.cpp
index 4c4e8c271b1f..e7dfc187dbfe 100644
--- a/FuzzerLoop.cpp
+++ b/FuzzerLoop.cpp
@@ -254,12 +254,20 @@ void Fuzzer::ExitCallback() {
_Exit(Options.ErrorExitCode);
}
-void Fuzzer::MaybeExitGracefully() {
- if (!F->GracefulExitRequested) return;
+bool Fuzzer::MaybeExitGracefully() {
+ if (!F->GracefulExitRequested) return false;
Printf("==%lu== INFO: libFuzzer: exiting as requested\n", GetPid());
RmDirRecursive(TempPath("FuzzWithFork", ".dir"));
F->PrintFinalStats();
- _Exit(0);
+ return true;
+}
+
+void Fuzzer::GracefullyExit() {
+ F->GracefulExitRequested = true;
+}
+
+bool Fuzzer::isGracefulExitRequested() {
+ return F->GracefulExitRequested;
}
void Fuzzer::InterruptCallback() {
@@ -663,7 +671,7 @@ void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
}
}
-void Fuzzer::MutateAndTestOne() {
+bool Fuzzer::MutateAndTestOne() {
MD.StartMutationSequence();
auto &II = Corpus.ChooseUnitToMutate(MD.GetRand());
@@ -685,7 +693,7 @@ void Fuzzer::MutateAndTestOne() {
for (int i = 0; i < Options.MutateDepth; i++) {
if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
break;
- MaybeExitGracefully();
+ if (MaybeExitGracefully()) return true;
size_t NewSize = 0;
if (II.HasFocusFunction && !II.DataFlowTraceForFocusFunction.empty() &&
Size <= CurrentMaxMutationLen)
@@ -719,6 +727,7 @@ void Fuzzer::MutateAndTestOne() {
}
II.NeedsEnergyUpdate = true;
+ return false;
}
void Fuzzer::PurgeAllocator() {
@@ -736,7 +745,7 @@ void Fuzzer::PurgeAllocator() {
LastAllocatorPurgeAttemptTime = system_clock::now();
}
-void Fuzzer::ReadAndExecuteSeedCorpora(Vector<SizedFile> &CorporaFiles) {
+int Fuzzer::ReadAndExecuteSeedCorpora(Vector<SizedFile> &CorporaFiles) {
const size_t kMaxSaneLen = 1 << 20;
const size_t kMinDefaultLen = 4096;
size_t MaxSize = 0;
@@ -795,16 +804,23 @@ void Fuzzer::ReadAndExecuteSeedCorpora(Vector<SizedFile> &CorporaFiles) {
if (Corpus.empty() && Options.MaxNumberOfRuns) {
Printf("ERROR: no interesting inputs were found. "
"Is the code instrumented for coverage? Exiting.\n");
- exit(1);
+ return 1;
}
+ return 0;
}
-void Fuzzer::Loop(Vector<SizedFile> &CorporaFiles) {
+int Fuzzer::Loop(Vector<SizedFile> &CorporaFiles) {
auto FocusFunctionOrAuto = Options.FocusFunction;
- DFT.Init(Options.DataFlowTrace, &FocusFunctionOrAuto, CorporaFiles,
+ int Res = DFT.Init(Options.DataFlowTrace, &FocusFunctionOrAuto, CorporaFiles,
MD.GetRand());
- TPC.SetFocusFunction(FocusFunctionOrAuto);
- ReadAndExecuteSeedCorpora(CorporaFiles);
+ if (Res != 0)
+ return Res;
+ Res = TPC.SetFocusFunction(FocusFunctionOrAuto);
+ if (Res != 0)
+ return Res;
+ Res = ReadAndExecuteSeedCorpora(CorporaFiles);
+ if (Res != 0)
+ return Res;
DFT.Clear(); // No need for DFT any more.
TPC.SetPrintNewPCs(Options.PrintNewCovPcs);
TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs);
@@ -842,13 +858,15 @@ void Fuzzer::Loop(Vector<SizedFile> &CorporaFiles) {
}
// Perform several mutations and runs.
- MutateAndTestOne();
+ if (MutateAndTestOne())
+ return 0;
PurgeAllocator();
}
PrintStats("DONE ", "\n");
MD.PrintRecommendedDictionary();
+ return 0;
}
void Fuzzer::MinimizeCrashLoop(const Unit &U) {
diff --git a/FuzzerMerge.cpp b/FuzzerMerge.cpp
index 919eea848580..0a185c7325bb 100644
--- a/FuzzerMerge.cpp
+++ b/FuzzerMerge.cpp
@@ -28,11 +28,12 @@ bool Merger::Parse(const std::string &Str, bool ParseCoverage) {
return Parse(SS, ParseCoverage);
}
-void Merger::ParseOrExit(std::istream &IS, bool ParseCoverage) {
+int Merger::ParseOrExit(std::istream &IS, bool ParseCoverage) {
if (!Parse(IS, ParseCoverage)) {
Printf("MERGE: failed to parse the control file (unexpected error)\n");
- exit(1);
+ return 1;
}
+ return 0;
}
// The control file example:
@@ -194,11 +195,13 @@ Set<uint32_t> Merger::AllFeatures() const {
}
// Inner process. May crash if the target crashes.
-void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
+int Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
Printf("MERGE-INNER: using the control file '%s'\n", CFPath.c_str());
Merger M;
std::ifstream IF(CFPath);
- M.ParseOrExit(IF, false);
+ int Res = M.ParseOrExit(IF, false);
+ if (Res != 0)
+ return Res;
IF.close();
if (!M.LastFailure.empty())
Printf("MERGE-INNER: '%s' caused a failure at the previous merge step\n",
@@ -216,7 +219,8 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
};
Set<const TracePC::PCTableEntry *> AllPCs;
for (size_t i = M.FirstNotProcessedFile; i < M.Files.size(); i++) {
- Fuzzer::MaybeExitGracefully();
+ if (Fuzzer::MaybeExitGracefully())
+ return 0;
auto U = FileToVector(M.Files[i].Name);
if (U.size() > MaxInputLen) {
U.resize(MaxInputLen);
@@ -261,12 +265,14 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
OF.flush();
}
PrintStatsWrapper("DONE ");
+ return 0;
}
-static size_t WriteNewControlFile(const std::string &CFPath,
+static int WriteNewControlFile(const std::string &CFPath,
const Vector<SizedFile> &OldCorpus,
const Vector<SizedFile> &NewCorpus,
- const Vector<MergeFileInfo> &KnownFiles) {
+ const Vector<MergeFileInfo> &KnownFiles,
+ size_t &NumFiles) {
std::unordered_set<std::string> FilesToSkip;
for (auto &SF: KnownFiles)
FilesToSkip.insert(SF.Name);
@@ -292,14 +298,15 @@ static size_t WriteNewControlFile(const std::string &CFPath,
if (!ControlFile) {
Printf("MERGE-OUTER: failed to write to the control file: %s\n",
CFPath.c_str());
- exit(1);
+ return 1;
}
- return FilesToUse.size();
+ NumFiles = FilesToUse.size();
+ return 0;
}
// Outer process. Does not call the target code and thus should not fail.
-void CrashResistantMerge(const Vector<std::string> &Args,
+int CrashResistantMerge(const Vector<std::string> &Args,
const Vector<SizedFile> &OldCorpus,
const Vector<SizedFile> &NewCorpus,
Vector<std::string> *NewFiles,
@@ -309,8 +316,9 @@ void CrashResistantMerge(const Vector<std::string> &Args,
Set<uint32_t> *NewCov,
const std::string &CFPath,
bool V /*Verbose*/) {
- if (NewCorpus.empty() && OldCorpus.empty()) return; // Nothing to merge.
+ if (NewCorpus.empty() && OldCorpus.empty()) return 0; // Nothing to merge.
size_t NumAttempts = 0;
+ int Res;
Vector<MergeFileInfo> KnownFiles;
if (FileSize(CFPath)) {
VPrintf(V, "MERGE-OUTER: non-empty control file provided: '%s'\n",
@@ -331,7 +339,8 @@ void CrashResistantMerge(const Vector<std::string> &Args,
VPrintf(
V,
"MERGE-OUTER: nothing to do, merge has been completed before\n");
- exit(0);
+ Fuzzer::GracefullyExit();
+ return 0;
}
// Number of input files likely changed, start merge from scratch, but
@@ -356,7 +365,9 @@ void CrashResistantMerge(const Vector<std::string> &Args,
"%zd files, %zd in the initial corpus, %zd processed earlier\n",
OldCorpus.size() + NewCorpus.size(), OldCorpus.size(),
KnownFiles.size());
- NumAttempts = WriteNewControlFile(CFPath, OldCorpus, NewCorpus, KnownFiles);
+ Res = WriteNewControlFile(CFPath, OldCorpus, NewCorpus, KnownFiles, NumAttempts);
+ if (Res != 0)
+ return Res;
}
// Execute the inner process until it passes.
@@ -366,7 +377,8 @@ void CrashResistantMerge(const Vector<std::string> &Args,
BaseCmd.removeFlag("fork");
BaseCmd.removeFlag("collect_data_flow");
for (size_t Attempt = 1; Attempt <= NumAttempts; Attempt++) {
- Fuzzer::MaybeExitGracefully();
+ if (Fuzzer::MaybeExitGracefully())
+ return 0;
VPrintf(V, "MERGE-OUTER: attempt %zd\n", Attempt);
Command Cmd(BaseCmd);
Cmd.addFlag("merge_control_file", CFPath);
@@ -388,7 +400,9 @@ void CrashResistantMerge(const Vector<std::string> &Args,
VPrintf(V, "MERGE-OUTER: the control file has %zd bytes\n",
(size_t)IF.tellg());
IF.seekg(0, IF.beg);
- M.ParseOrExit(IF, true);
+ Res = M.ParseOrExit(IF, true);
+ if (Res != 0)
+ return Res;
IF.close();
VPrintf(V,
"MERGE-OUTER: consumed %zdMb (%zdMb rss) to parse the control file\n",
@@ -399,6 +413,7 @@ void CrashResistantMerge(const Vector<std::string> &Args,
VPrintf(V, "MERGE-OUTER: %zd new files with %zd new features added; "
"%zd new coverage edges\n",
NewFiles->size(), NewFeatures->size(), NewCov->size());
+ return 0;
}
} // namespace fuzzer
diff --git a/FuzzerMerge.h b/FuzzerMerge.h
index e0c6bc539bdb..6dc1c4c45abf 100644
--- a/FuzzerMerge.h
+++ b/FuzzerMerge.h
@@ -63,7 +63,7 @@ struct Merger {
bool Parse(std::istream &IS, bool ParseCoverage);
bool Parse(const std::string &Str, bool ParseCoverage);
- void ParseOrExit(std::istream &IS, bool ParseCoverage);
+ int ParseOrExit(std::istream &IS, bool ParseCoverage);
size_t Merge(const Set<uint32_t> &InitialFeatures, Set<uint32_t> *NewFeatures,
const Set<uint32_t> &InitialCov, Set<uint32_t> *NewCov,
Vector<std::string> *NewFiles);
@@ -71,7 +71,7 @@ struct Merger {
Set<uint32_t> AllFeatures() const;
};
-void CrashResistantMerge(const Vector<std::string> &Args,
+int CrashResistantMerge(const Vector<std::string> &Args,
const Vector<SizedFile> &OldCorpus,
const Vector<SizedFile> &NewCorpus,
Vector<std::string> *NewFiles,
diff --git a/FuzzerTracePC.cpp b/FuzzerTracePC.cpp
index b2ca7693e540..fbceda39bc22 100644
--- a/FuzzerTracePC.cpp
+++ b/FuzzerTracePC.cpp
@@ -238,13 +238,13 @@ void TracePC::IterateCoveredFunctions(CallBack CB) {
}
}
-void TracePC::SetFocusFunction(const std::string &FuncName) {
+int TracePC::SetFocusFunction(const std::string &FuncName) {
// This function should be called once.
assert(!FocusFunctionCounterPtr);
// "auto" is not a valid function name. If this function is called with "auto"
// that means the auto focus functionality failed.
if (FuncName.empty() || FuncName == "auto")
- return;
+ return 0;
for (size_t M = 0; M < NumModules; M++) {
auto &PCTE = ModulePCTable[M];
size_t N = PCTE.Stop - PCTE.Start;
@@ -256,13 +256,13 @@ void TracePC::SetFocusFunction(const std::string &FuncName) {
if (FuncName != Name) continue;
Printf("INFO: Focus function is set to '%s'\n", Name.c_str());
FocusFunctionCounterPtr = Modules[M].Start() + I;
- return;
+ return 0;
}
}
Printf("ERROR: Failed to set focus function. Make sure the function name is "
"valid (%s) and symbolization is enabled.\n", FuncName.c_str());
- exit(1);
+ return 1;
}
bool TracePC::ObservedFocusFunction() {
diff --git a/FuzzerTracePC.h b/FuzzerTracePC.h
index 501f3b544971..b46ebb909dbf 100644
--- a/FuzzerTracePC.h
+++ b/FuzzerTracePC.h
@@ -116,7 +116,7 @@ class TracePC {
CB(PC);
}
- void SetFocusFunction(const std::string &FuncName);
+ int SetFocusFunction(const std::string &FuncName);
bool ObservedFocusFunction();
struct PCTableEntry {