1 //===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
9 // FuzzerDriver and flag parsing.
10 //===----------------------------------------------------------------------===//
12 #include "FuzzerInterface.h"
13 #include "FuzzerInternal.h"
29 struct FlagDescription {
31 const char *Description;
38 #define FUZZER_FLAG_INT(Name, Default, Description) int Name;
39 #define FUZZER_FLAG_STRING(Name, Description) const char *Name;
40 #include "FuzzerFlags.def"
41 #undef FUZZER_FLAG_INT
42 #undef FUZZER_FLAG_STRING
45 static FlagDescription FlagDescriptions [] {
46 #define FUZZER_FLAG_INT(Name, Default, Description) \
47 { #Name, Description, Default, &Flags.Name, nullptr},
48 #define FUZZER_FLAG_STRING(Name, Description) \
49 { #Name, Description, 0, nullptr, &Flags.Name },
50 #include "FuzzerFlags.def"
51 #undef FUZZER_FLAG_INT
52 #undef FUZZER_FLAG_STRING
55 static const size_t kNumFlags =
56 sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]);
58 static std::vector<std::string> inputs;
59 static const char *ProgName;
61 static void PrintHelp() {
62 std::cerr << "Usage: " << ProgName
63 << " [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n";
64 std::cerr << "\nFlags: (strictly in form -flag=value)\n";
65 size_t MaxFlagLen = 0;
66 for (size_t F = 0; F < kNumFlags; F++)
67 MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen);
69 for (size_t F = 0; F < kNumFlags; F++) {
70 const auto &D = FlagDescriptions[F];
71 std::cerr << " " << D.Name;
72 for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++)
75 std::cerr << D.Default << "\t" << D.Description << "\n";
79 static const char *FlagValue(const char *Param, const char *Name) {
80 size_t Len = strlen(Name);
81 if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 &&
82 Param[Len + 1] == '=')
83 return &Param[Len + 2];
87 static bool ParseOneFlag(const char *Param) {
88 if (Param[0] != '-') return false;
89 for (size_t F = 0; F < kNumFlags; F++) {
90 const char *Name = FlagDescriptions[F].Name;
91 const char *Str = FlagValue(Param, Name);
93 if (FlagDescriptions[F].IntFlag) {
94 int Val = std::stol(Str);
95 *FlagDescriptions[F].IntFlag = Val;
96 if (Flags.verbosity >= 2)
97 std::cerr << "Flag: " << Name << " " << Val << "\n";
99 } else if (FlagDescriptions[F].StrFlag) {
100 *FlagDescriptions[F].StrFlag = Str;
101 if (Flags.verbosity >= 2)
102 std::cerr << "Flag: " << Name << " " << Str << "\n";
111 // We don't use any library to minimize dependencies.
112 static void ParseFlags(int argc, char **argv) {
113 for (size_t F = 0; F < kNumFlags; F++) {
114 if (FlagDescriptions[F].IntFlag)
115 *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default;
116 if (FlagDescriptions[F].StrFlag)
117 *FlagDescriptions[F].StrFlag = nullptr;
119 for (int A = 1; A < argc; A++) {
120 if (ParseOneFlag(argv[A])) continue;
121 inputs.push_back(argv[A]);
125 static void WorkerThread(const std::string &Cmd, std::atomic<int> *Counter,
126 int NumJobs, std::atomic<bool> *HasErrors) {
127 static std::mutex CerrMutex;
129 int C = (*Counter)++;
130 if (C >= NumJobs) break;
131 std::string Log = "fuzz-" + std::to_string(C) + ".log";
132 std::string ToRun = Cmd + " > " + Log + " 2>&1\n";
135 int ExitCode = system(ToRun.c_str());
138 std::lock_guard<std::mutex> Lock(CerrMutex);
139 std::cerr << "================== Job " << C
140 << " exited with exit code " << ExitCode
141 << " =================\n";
142 fuzzer::CopyFileToErr(Log);
146 static int RunInMultipleProcesses(int argc, char **argv, int NumWorkers,
148 std::atomic<int> Counter(0);
149 std::atomic<bool> HasErrors(false);
151 for (int i = 0; i < argc; i++) {
152 if (FlagValue(argv[i], "jobs") || FlagValue(argv[i], "workers")) continue;
156 std::vector<std::thread> V;
157 for (int i = 0; i < NumWorkers; i++)
158 V.push_back(std::thread(WorkerThread, Cmd, &Counter, NumJobs, &HasErrors));
161 return HasErrors ? 1 : 0;
164 std::vector<std::string> ReadTokensFile(const char *TokensFilePath) {
165 if (!TokensFilePath) return {};
166 std::string TokensFileContents = FileToString(TokensFilePath);
167 std::istringstream ISS(TokensFileContents);
168 std::vector<std::string> Res = {std::istream_iterator<std::string>{ISS},
169 std::istream_iterator<std::string>{}};
176 int ApplyTokens(const Fuzzer &F, const char *InputFilePath) {
177 Unit U = FileToVector(InputFilePath);
178 auto T = F.SubstituteTokens(U);
180 std::cout << T.data();
184 int FuzzerDriver(int argc, char **argv, UserCallback Callback) {
185 using namespace fuzzer;
188 ParseFlags(argc, argv);
194 if (Flags.workers > 0 && Flags.jobs > 0)
195 return RunInMultipleProcesses(argc, argv, Flags.workers, Flags.jobs);
197 Fuzzer::FuzzingOptions Options;
198 Options.Verbosity = Flags.verbosity;
199 Options.MaxLen = Flags.max_len;
200 Options.DoCrossOver = Flags.cross_over;
201 Options.MutateDepth = Flags.mutate_depth;
202 Options.ExitOnFirst = Flags.exit_on_first;
203 Options.UseCounters = Flags.use_counters;
204 Options.UseFullCoverageSet = Flags.use_full_coverage_set;
205 Options.UseCoveragePairs = Flags.use_coverage_pairs;
206 Options.UseDFSan = Flags.dfsan;
207 Options.PreferSmallDuringInitialShuffle =
208 Flags.prefer_small_during_initial_shuffle;
209 Options.Tokens = ReadTokensFile(Flags.tokens);
210 Options.Reload = Flags.reload;
212 Options.MaxNumberOfRuns = Flags.runs;
214 Options.OutputCorpus = inputs[0];
215 Fuzzer F(Callback, Options);
217 unsigned seed = Flags.seed;
220 seed = time(0) * 10000 + getpid();
222 std::cerr << "Seed: " << seed << "\n";
226 if (Flags.timeout > 0)
227 SetTimer(Flags.timeout);
229 if (Flags.verbosity >= 2) {
230 std::cerr << "Tokens: {";
231 for (auto &T : Options.Tokens)
232 std::cerr << T << ",";
236 if (Flags.apply_tokens)
237 return ApplyTokens(F, Flags.apply_tokens);
239 F.RereadOutputCorpus();
240 for (auto &inp : inputs)
241 if (inp != Options.OutputCorpus)
242 F.ReadDir(inp, nullptr);
244 if (F.CorpusSize() == 0)
245 F.AddToCorpus(Unit()); // Can't fuzz empty corpus, so add an empty input.
246 F.ShuffleAndMinimize();
247 if (Flags.save_minimized_corpus)
249 F.Loop(Flags.iterations < 0 ? INT_MAX : Flags.iterations);
251 std::cerr << "Done " << F.getTotalNumberOfRuns()
252 << " runs in " << F.secondsSinceProcessStartUp()
257 } // namespace fuzzer