[libFuzzer] form mode: add -ignore_crashes flag, honor the max_total_time flag, print the number of ooms/timeouts/crashes, fix a typo
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@354175 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp
index 9f1621f..9c99d5f 100644
--- a/lib/fuzzer/FuzzerDriver.cpp
+++ b/lib/fuzzer/FuzzerDriver.cpp
@@ -606,6 +606,7 @@
Options.TimeoutExitCode = Flags.timeout_exitcode;
Options.IgnoreTimeouts = Flags.ignore_timeouts;
Options.IgnoreOOMs = Flags.ignore_ooms;
+ Options.IgnoreCrashes = Flags.ignore_crashes;
Options.MaxTotalTimeSec = Flags.max_total_time;
Options.DoCrossOver = Flags.cross_over;
Options.MutateDepth = Flags.mutate_depth;
diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def
index d194a89..79eb75c 100644
--- a/lib/fuzzer/FuzzerFlags.def
+++ b/lib/fuzzer/FuzzerFlags.def
@@ -45,6 +45,7 @@
"in a subprocess")
FUZZER_FLAG_INT(ignore_timeouts, 1, "Ignore timeouts in fork mode")
FUZZER_FLAG_INT(ignore_ooms, 1, "Ignore OOMs in fork mode")
+FUZZER_FLAG_INT(ignore_crashes, 0, "Ignore crashes in fork mode")
FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be "
"merged into the 1-st corpus. Only interesting units will be taken. "
"This flag can be used to minimize a corpus.")
diff --git a/lib/fuzzer/FuzzerFork.cpp b/lib/fuzzer/FuzzerFork.cpp
index eff9009..09da192 100644
--- a/lib/fuzzer/FuzzerFork.cpp
+++ b/lib/fuzzer/FuzzerFork.cpp
@@ -17,6 +17,7 @@
#include "FuzzerUtil.h"
#include <atomic>
+#include <chrono>
#include <fstream>
#include <mutex>
#include <queue>
@@ -76,10 +77,22 @@
Set<uint32_t> Features, Cov;
Vector<std::string> Files;
Random *Rand;
+ std::chrono::system_clock::time_point ProcessStartTime;
int Verbosity = 0;
+ size_t NumTimeouts = 0;
+ size_t NumOOMs = 0;
+ size_t NumCrashes = 0;
+
+
size_t NumRuns = 0;
+ size_t secondsSinceProcessStartUp() const {
+ return std::chrono::duration_cast<std::chrono::seconds>(
+ std::chrono::system_clock::now() - ProcessStartTime)
+ .count();
+ }
+
FuzzJob *CreateNewJob(size_t JobId) {
Command Cmd(Args);
Cmd.removeFlag("fork");
@@ -146,10 +159,12 @@
auto Stats = ParseFinalStatsFromLog(Job->LogPath);
NumRuns += Stats.number_of_executed_units;
- if (!FilesToAdd.empty())
- Printf("#%zd: cov: %zd ft: %zd corp: %zd exec/s %zd\n", NumRuns,
+ if (!FilesToAdd.empty() || Job->ExitCode != 0)
+ Printf("#%zd: cov: %zd ft: %zd corp: %zd exec/s %zd "
+ "oom/timeout/crash: %zd/%zd/%zd time: %zds\n", NumRuns,
Cov.size(), Features.size(), Files.size(),
- Stats.average_exec_per_sec);
+ Stats.average_exec_per_sec,
+ NumOOMs, NumTimeouts, NumCrashes, secondsSinceProcessStartUp());
}
};
@@ -187,14 +202,14 @@
void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
const Vector<std::string> &Args,
const Vector<std::string> &CorpusDirs, int NumJobs) {
- Printf("INFO: -fork=%d: doing fuzzing in a separate process in order to "
- "be more resistant to crashes, timeouts, and OOMs\n", NumJobs);
+ Printf("INFO: -fork=%d: fuzzing in separate process(s)\n", NumJobs);
GlobalEnv Env;
Env.Args = Args;
Env.CorpusDirs = CorpusDirs;
Env.Rand = &Rand;
Env.Verbosity = Options.Verbosity;
+ Env.ProcessStartTime = std::chrono::system_clock::now();
Vector<SizedFile> SeedFiles;
for (auto &Dir : CorpusDirs)
@@ -215,8 +230,8 @@
{}, &Env.Cov,
CFPath, false);
RemoveFile(CFPath);
- Printf("INFO: -fork=%d: %zd seeds, starting to fuzz; scratch: %s\n",
- NumJobs, Env.Files.size(), Env.TempDir.c_str());
+ Printf("INFO: -fork=%d: %zd seed inputs, starting to fuzz in %s\n", NumJobs,
+ Env.Files.size(), Env.TempDir.c_str());
int ExitCode = 0;
@@ -230,9 +245,11 @@
FuzzQ.Push(Env.CreateNewJob(JobId++));
}
- while (!Stop) {
+ while (true) {
auto Job = MergeQ.Pop();
if (!Job) {
+ if (Stop)
+ break;
SleepSeconds(1);
continue;
}
@@ -242,20 +259,42 @@
// Continue if our crash is one of the ignorred ones.
if (Options.IgnoreTimeouts && ExitCode == Options.TimeoutExitCode)
- ;
+ Env.NumTimeouts++;
else if (Options.IgnoreOOMs && ExitCode == Options.OOMExitCode)
- ;
+ Env.NumOOMs++;
else if (ExitCode == Options.InterruptExitCode)
Stop = true;
else if (ExitCode != 0) {
- // And exit if we don't ignore this crash.
- Printf("INFO: log from the inner process:\n%s",
- FileToString(Job->LogPath).c_str());
- Stop = true;
+ Env.NumCrashes++;
+ if (Options.IgnoreCrashes) {
+ std::ifstream In(Job->LogPath);
+ std::string Line;
+ while (std::getline(In, Line, '\n'))
+ if (Line.find("ERROR:") != Line.npos)
+ Printf("%s\n", Line.c_str());
+ } else {
+ // And exit if we don't ignore this crash.
+ Printf("INFO: log from the inner process:\n%s",
+ FileToString(Job->LogPath).c_str());
+ Stop = true;
+ }
}
RemoveFile(Job->LogPath);
delete Job;
- FuzzQ.Push(Env.CreateNewJob(JobId++));
+
+ // Stop if we are over the time budget.
+ // This is not precise, since other threads are still running
+ // and we will wait while joining them.
+ // We also don't stop instantly: other jobs need to finish.
+ if (Options.MaxTotalTimeSec > 0 && !Stop &&
+ Env.secondsSinceProcessStartUp() >= (size_t)Options.MaxTotalTimeSec) {
+ Printf("INFO: fuzzed for %zd seconds, wrapping up soon\n",
+ Env.secondsSinceProcessStartUp());
+ Stop = true;
+ }
+
+ if (!Stop)
+ FuzzQ.Push(Env.CreateNewJob(JobId++));
}
Stop = true;
@@ -265,7 +304,8 @@
RmDirRecursive(Env.TempDir);
// Use the exit code from the last child process.
- Printf("Fork: exiting: %d\n", ExitCode);
+ Printf("INFO: exiting: %d time: %zds\n", ExitCode,
+ Env.secondsSinceProcessStartUp());
exit(ExitCode);
}
diff --git a/lib/fuzzer/FuzzerIO.cpp b/lib/fuzzer/FuzzerIO.cpp
index 33d6568..290112a 100644
--- a/lib/fuzzer/FuzzerIO.cpp
+++ b/lib/fuzzer/FuzzerIO.cpp
@@ -136,7 +136,7 @@
}
void RmDirRecursive(const std::string &Dir) {
- IterateDirRecurisve(
+ IterateDirRecursive(
Dir, [](const std::string &Path) {},
[](const std::string &Path) { RmDir(Path); },
[](const std::string &Path) { RemoveFile(Path); });
diff --git a/lib/fuzzer/FuzzerIO.h b/lib/fuzzer/FuzzerIO.h
index 588cf93..e51b8d1 100644
--- a/lib/fuzzer/FuzzerIO.h
+++ b/lib/fuzzer/FuzzerIO.h
@@ -65,7 +65,7 @@
// Iterate files and dirs inside Dir, recursively.
// Call DirPreCallback/DirPostCallback on dirs before/after
// calling FileCallback on files.
-void IterateDirRecurisve(const std::string &Dir,
+void IterateDirRecursive(const std::string &Dir,
void (*DirPreCallback)(const std::string &Dir),
void (*DirPostCallback)(const std::string &Dir),
void (*FileCallback)(const std::string &Dir));
diff --git a/lib/fuzzer/FuzzerIOPosix.cpp b/lib/fuzzer/FuzzerIOPosix.cpp
index 93eaad6..92d19d3 100644
--- a/lib/fuzzer/FuzzerIOPosix.cpp
+++ b/lib/fuzzer/FuzzerIOPosix.cpp
@@ -79,7 +79,7 @@
}
-void IterateDirRecurisve(const std::string &Dir,
+void IterateDirRecursive(const std::string &Dir,
void (*DirPreCallback)(const std::string &Dir),
void (*DirPostCallback)(const std::string &Dir),
void (*FileCallback)(const std::string &Dir)) {
@@ -94,7 +94,7 @@
else if ((E->d_type == DT_DIR ||
(E->d_type == DT_UNKNOWN && IsDirectory(Path))) &&
*E->d_name != '.')
- IterateDirRecurisve(Path, DirPreCallback, DirPostCallback, FileCallback);
+ IterateDirRecursive(Path, DirPreCallback, DirPostCallback, FileCallback);
}
closedir(D);
DirPostCallback(Dir);
diff --git a/lib/fuzzer/FuzzerIOWindows.cpp b/lib/fuzzer/FuzzerIOWindows.cpp
index 00256ca..e49e8a4 100644
--- a/lib/fuzzer/FuzzerIOWindows.cpp
+++ b/lib/fuzzer/FuzzerIOWindows.cpp
@@ -141,7 +141,7 @@
}
-void IterateDirRecurisve(const std::string &Dir,
+void IterateDirRecursive(const std::string &Dir,
void (*DirPreCallback)(const std::string &Dir),
void (*DirPostCallback)(const std::string &Dir),
void (*FileCallback)(const std::string &Dir)) {
diff --git a/lib/fuzzer/FuzzerOptions.h b/lib/fuzzer/FuzzerOptions.h
index 628603f..7a607e8 100644
--- a/lib/fuzzer/FuzzerOptions.h
+++ b/lib/fuzzer/FuzzerOptions.h
@@ -23,8 +23,9 @@
int OOMExitCode = 71;
int InterruptExitCode = 72;
int ErrorExitCode = 77;
- bool IgnoreTimeouts = 1;
- bool IgnoreOOMs = 1;
+ bool IgnoreTimeouts = true;
+ bool IgnoreOOMs = true;
+ bool IgnoreCrashes = false;
int MaxTotalTimeSec = 0;
int RssLimitMb = 0;
int MallocLimitMb = 0;
diff --git a/test/fuzzer/fork.test b/test/fuzzer/fork.test
index c267bee..881880e 100644
--- a/test/fuzzer/fork.test
+++ b/test/fuzzer/fork.test
@@ -14,3 +14,7 @@
CRASH: SEGV on unknown address 0x000000000000
RUN: %cpp_compiler %S/ShallowOOMDeepCrash.cpp -o %t-ShallowOOMDeepCrash
RUN: not %run %t-ShallowOOMDeepCrash -fork=1 -rss_limit_mb=128 2>&1 | FileCheck %s --check-prefix=CRASH
+
+MAX_TOTAL_TIME: INFO: fuzzed for {{.*}} seconds, wrapping up soon
+MAX_TOTAL_TIME: INFO: exiting: {{.*}} time:
+RUN: not %run %t-ShallowOOMDeepCrash -fork=1 -rss_limit_mb=128 -ignore_crashes=1 -max_total_time=5 2>&1 | FileCheck %s --check-prefix=MAX_TOTAL_TIME