[libFuzzer] Encapsulate commands in a class.
Summary:
To be more portable (especially w.r.t. platforms without system()),
commands should be managed programmatically rather than via string
manipulation on the command line. This change introduces
Fuzzer::Command, with methods to manage arguments and flags, set output
options, and execute the command.
Patch By: aarongreen
Reviewers: kcc, morehouse
Reviewed By: kcc, morehouse
Subscribers: llvm-commits, mgorny
Differential Revision: https://reviews.llvm.org/D40103
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer@319680 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/FuzzerDriver.cpp b/FuzzerDriver.cpp
index ccb9b0c..41eb50e 100644
--- a/FuzzerDriver.cpp
+++ b/FuzzerDriver.cpp
@@ -9,6 +9,7 @@
// FuzzerDriver and flag parsing.
//===----------------------------------------------------------------------===//
+#include "FuzzerCommand.h"
#include "FuzzerCorpus.h"
#include "FuzzerIO.h"
#include "FuzzerInterface.h"
@@ -206,16 +207,20 @@
}
}
-static void WorkerThread(const std::string &Cmd, std::atomic<unsigned> *Counter,
+static void WorkerThread(const Command &BaseCmd, std::atomic<unsigned> *Counter,
unsigned NumJobs, std::atomic<bool> *HasErrors) {
while (true) {
unsigned C = (*Counter)++;
if (C >= NumJobs) break;
std::string Log = "fuzz-" + std::to_string(C) + ".log";
- std::string ToRun = Cmd + " > " + Log + " 2>&1\n";
- if (Flags.verbosity)
- Printf("%s", ToRun.c_str());
- int ExitCode = ExecuteCommand(ToRun);
+ Command Cmd(BaseCmd);
+ Cmd.setOutputFile(Log);
+ Cmd.combineOutAndErr();
+ if (Flags.verbosity) {
+ std::string CommandLine = Cmd.toString();
+ Printf("%s", CommandLine.c_str());
+ }
+ int ExitCode = ExecuteCommand(Cmd);
if (ExitCode != 0)
*HasErrors = true;
std::lock_guard<std::mutex> Lock(Mu);
@@ -240,12 +245,14 @@
unsigned NumWorkers, unsigned NumJobs) {
std::atomic<unsigned> Counter(0);
std::atomic<bool> HasErrors(false);
- std::string Cmd = CloneArgsWithoutX(Args, "jobs", "workers");
+ Command Cmd(Args);
+ Cmd.removeFlag("jobs");
+ Cmd.removeFlag("workers");
Vector<std::thread> V;
std::thread Pulse(PulseThread);
Pulse.detach();
for (unsigned i = 0; i < NumWorkers; i++)
- V.push_back(std::thread(WorkerThread, Cmd, &Counter, NumJobs, &HasErrors));
+ V.push_back(std::thread(WorkerThread, std::ref(Cmd), &Counter, NumJobs, &HasErrors));
for (auto &T : V)
T.join();
return HasErrors ? 1 : 0;
@@ -303,20 +310,19 @@
}
std::string InputFilePath = Inputs->at(0);
std::string OutputFilePath = Flags.exact_artifact_path;
- std::string BaseCmd =
- CloneArgsWithoutX(Args, "cleanse_crash", "cleanse_crash");
+ Command Cmd(Args);
+ Cmd.removeFlag("cleanse_crash");
- auto InputPos = BaseCmd.find(" " + InputFilePath + " ");
- assert(InputPos != std::string::npos);
- BaseCmd.erase(InputPos, InputFilePath.size() + 1);
+ assert(Cmd.hasArgument(InputFilePath));
+ Cmd.removeArgument(InputFilePath);
auto LogFilePath = DirPlusFile(
TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt");
auto TmpFilePath = DirPlusFile(
TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".repro");
- auto LogFileRedirect = " > " + LogFilePath + " 2>&1 ";
-
- auto Cmd = BaseCmd + " " + TmpFilePath + LogFileRedirect;
+ Cmd.addArgument(TmpFilePath);
+ Cmd.setOutputFile(LogFilePath);
+ Cmd.combineOutAndErr();
std::string CurrentFilePath = InputFilePath;
auto U = FileToVector(CurrentFilePath);
@@ -361,22 +367,22 @@
exit(1);
}
std::string InputFilePath = Inputs->at(0);
- auto BaseCmd = SplitBefore(
- "-ignore_remaining_args=1",
- CloneArgsWithoutX(Args, "minimize_crash", "exact_artifact_path"));
- auto InputPos = BaseCmd.first.find(" " + InputFilePath + " ");
- assert(InputPos != std::string::npos);
- BaseCmd.first.erase(InputPos, InputFilePath.size() + 1);
+ Command BaseCmd(Args);
+ BaseCmd.removeFlag("minimize_crash");
+ BaseCmd.removeFlag("exact_artifact_path");
+ assert(BaseCmd.hasArgument(InputFilePath));
+ BaseCmd.removeArgument(InputFilePath);
if (Flags.runs <= 0 && Flags.max_total_time == 0) {
Printf("INFO: you need to specify -runs=N or "
"-max_total_time=N with -minimize_crash=1\n"
"INFO: defaulting to -max_total_time=600\n");
- BaseCmd.first += " -max_total_time=600";
+ BaseCmd.addFlag("max_total_time", "600");
}
auto LogFilePath = DirPlusFile(
TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt");
- auto LogFileRedirect = " > " + LogFilePath + " 2>&1 ";
+ BaseCmd.setOutputFile(LogFilePath);
+ BaseCmd.combineOutAndErr();
std::string CurrentFilePath = InputFilePath;
while (true) {
@@ -384,10 +390,11 @@
Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n",
CurrentFilePath.c_str(), U.size());
- auto Cmd = BaseCmd.first + " " + CurrentFilePath + LogFileRedirect + " " +
- BaseCmd.second;
+ Command Cmd(BaseCmd);
+ Cmd.addArgument(CurrentFilePath);
- Printf("CRASH_MIN: executing: %s\n", Cmd.c_str());
+ std::string CommandLine = Cmd.toString();
+ Printf("CRASH_MIN: executing: %s\n", CommandLine.c_str());
int ExitCode = ExecuteCommand(Cmd);
if (ExitCode == 0) {
Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str());
@@ -404,9 +411,10 @@
Flags.exact_artifact_path
? Flags.exact_artifact_path
: Options.ArtifactPrefix + "minimized-from-" + Hash(U);
- Cmd += " -minimize_crash_internal_step=1 -exact_artifact_path=" +
- ArtifactPath;
- Printf("CRASH_MIN: executing: %s\n", Cmd.c_str());
+ Cmd.addFlag("minimize_crash_internal_step", "1");
+ Cmd.addFlag("exact_artifact_path", ArtifactPath);
+ CommandLine = Cmd.toString();
+ Printf("CRASH_MIN: executing: %s\n", CommandLine.c_str());
ExitCode = ExecuteCommand(Cmd);
CopyFileToErr(LogFilePath);
if (ExitCode == 0) {