edfe09e8731042b3f891600c0bb47e50a31417e4
[oota-llvm.git] / lib / Fuzzer / FuzzerDriver.cpp
1 //===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 // FuzzerDriver and flag parsing.
10 //===----------------------------------------------------------------------===//
11
12 #include "FuzzerInterface.h"
13 #include "FuzzerInternal.h"
14
15 #include <cstring>
16 #include <chrono>
17 #include <unistd.h>
18 #include <iostream>
19 #include <thread>
20 #include <atomic>
21 #include <mutex>
22 #include <string>
23 #include <sstream>
24 #include <algorithm>
25 #include <iterator>
26
27 namespace fuzzer {
28
29 // Program arguments.
30 struct FlagDescription {
31   const char *Name;
32   const char *Description;
33   int   Default;
34   int   *IntFlag;
35   const char **StrFlag;
36 };
37
38 struct {
39 #define FUZZER_FLAG_INT(Name, Default, Description) int Name;
40 #define FUZZER_FLAG_STRING(Name, Description) const char *Name;
41 #include "FuzzerFlags.def"
42 #undef FUZZER_FLAG_INT
43 #undef FUZZER_FLAG_STRING
44 } Flags;
45
46 static FlagDescription FlagDescriptions [] {
47 #define FUZZER_FLAG_INT(Name, Default, Description)                            \
48   { #Name, Description, Default, &Flags.Name, nullptr},
49 #define FUZZER_FLAG_STRING(Name, Description)                                  \
50   { #Name, Description, 0, nullptr, &Flags.Name },
51 #include "FuzzerFlags.def"
52 #undef FUZZER_FLAG_INT
53 #undef FUZZER_FLAG_STRING
54 };
55
56 static const size_t kNumFlags =
57     sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]);
58
59 static std::vector<std::string> inputs;
60 static const char *ProgName;
61
62 static void PrintHelp() {
63   std::cerr << "Usage: " << ProgName
64             << " [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n";
65   std::cerr << "\nFlags: (strictly in form -flag=value)\n";
66   size_t MaxFlagLen = 0;
67   for (size_t F = 0; F < kNumFlags; F++)
68     MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen);
69
70   for (size_t F = 0; F < kNumFlags; F++) {
71     const auto &D = FlagDescriptions[F];
72     std::cerr << "  " << D.Name;
73     for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++)
74       std::cerr << " ";
75     std::cerr << "\t";
76     std::cerr << D.Default << "\t" << D.Description << "\n";
77   }
78   std::cerr << "\nFlags starting with '--' will be ignored and "
79             "will be passed verbatim to subprocesses.\n";
80 }
81
82 static const char *FlagValue(const char *Param, const char *Name) {
83   size_t Len = strlen(Name);
84   if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 &&
85       Param[Len + 1] == '=')
86       return &Param[Len + 2];
87   return nullptr;
88 }
89
90 static bool ParseOneFlag(const char *Param) {
91   if (Param[0] != '-') return false;
92   if (Param[1] == '-') {
93     static bool PrintedWarning = false;
94     if (!PrintedWarning) {
95       PrintedWarning = true;
96       std::cerr << "WARNING: libFuzzer ignores flags that start with '--'\n";
97     }
98     return true;
99   }
100   for (size_t F = 0; F < kNumFlags; F++) {
101     const char *Name = FlagDescriptions[F].Name;
102     const char *Str = FlagValue(Param, Name);
103     if (Str)  {
104       if (FlagDescriptions[F].IntFlag) {
105         int Val = std::stol(Str);
106         *FlagDescriptions[F].IntFlag = Val;
107         if (Flags.verbosity >= 2)
108           std::cerr << "Flag: " << Name << " " << Val << "\n";
109         return true;
110       } else if (FlagDescriptions[F].StrFlag) {
111         *FlagDescriptions[F].StrFlag = Str;
112         if (Flags.verbosity >= 2)
113           std::cerr << "Flag: " << Name << " " << Str << "\n";
114         return true;
115       }
116     }
117   }
118   PrintHelp();
119   exit(1);
120 }
121
122 // We don't use any library to minimize dependencies.
123 static void ParseFlags(int argc, char **argv) {
124   for (size_t F = 0; F < kNumFlags; F++) {
125     if (FlagDescriptions[F].IntFlag)
126       *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default;
127     if (FlagDescriptions[F].StrFlag)
128       *FlagDescriptions[F].StrFlag = nullptr;
129   }
130   for (int A = 1; A < argc; A++) {
131     if (ParseOneFlag(argv[A])) continue;
132     inputs.push_back(argv[A]);
133   }
134 }
135
136 static std::mutex Mu;
137
138 static void PulseThread() {
139   while (true) {
140     std::this_thread::sleep_for(std::chrono::seconds(600));
141     std::lock_guard<std::mutex> Lock(Mu);
142     std::cerr << "pulse...\n";
143   }
144 }
145
146 static void WorkerThread(const std::string &Cmd, std::atomic<int> *Counter,
147                         int NumJobs, std::atomic<bool> *HasErrors) {
148   while (true) {
149     int C = (*Counter)++;
150     if (C >= NumJobs) break;
151     std::string Log = "fuzz-" + std::to_string(C) + ".log";
152     std::string ToRun = Cmd + " > " + Log + " 2>&1\n";
153     if (Flags.verbosity)
154       std::cerr << ToRun;
155     int ExitCode = system(ToRun.c_str());
156     if (ExitCode != 0)
157       *HasErrors = true;
158     std::lock_guard<std::mutex> Lock(Mu);
159     std::cerr << "================== Job " << C
160               << " exited with exit code " << ExitCode
161               << " =================\n";
162     fuzzer::CopyFileToErr(Log);
163   }
164 }
165
166 static int RunInMultipleProcesses(int argc, char **argv, int NumWorkers,
167                                   int NumJobs) {
168   std::atomic<int> Counter(0);
169   std::atomic<bool> HasErrors(false);
170   std::string Cmd;
171   for (int i = 0; i < argc; i++) {
172     if (FlagValue(argv[i], "jobs") || FlagValue(argv[i], "workers")) continue;
173     Cmd += argv[i];
174     Cmd += " ";
175   }
176   std::vector<std::thread> V;
177   std::thread Pulse(PulseThread);
178   Pulse.detach();
179   for (int i = 0; i < NumWorkers; i++)
180     V.push_back(std::thread(WorkerThread, Cmd, &Counter, NumJobs, &HasErrors));
181   for (auto &T : V)
182     T.join();
183   return HasErrors ? 1 : 0;
184 }
185
186 std::vector<std::string> ReadTokensFile(const char *TokensFilePath) {
187   if (!TokensFilePath) return {};
188   std::string TokensFileContents = FileToString(TokensFilePath);
189   std::istringstream ISS(TokensFileContents);
190   std::vector<std::string> Res = {std::istream_iterator<std::string>{ISS},
191                                   std::istream_iterator<std::string>{}};
192   Res.push_back(" ");
193   Res.push_back("\t");
194   Res.push_back("\n");
195   return Res;
196 }
197
198 int ApplyTokens(const Fuzzer &F, const char *InputFilePath) {
199   Unit U = FileToVector(InputFilePath);
200   auto T = F.SubstituteTokens(U);
201   T.push_back(0);
202   std::cout << T.data();
203   return 0;
204 }
205
206 int FuzzerDriver(int argc, char **argv, UserCallback Callback) {
207   using namespace fuzzer;
208
209   ProgName = argv[0];
210   ParseFlags(argc, argv);
211   if (Flags.help) {
212     PrintHelp();
213     return 0;
214   }
215
216   if (Flags.jobs > 0 && Flags.workers == 0) {
217     Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs);
218     if (Flags.workers > 1)
219       std::cerr << "Running " << Flags.workers << " workers\n";
220   }
221
222   if (Flags.workers > 0 && Flags.jobs > 0)
223     return RunInMultipleProcesses(argc, argv, Flags.workers, Flags.jobs);
224
225   Fuzzer::FuzzingOptions Options;
226   Options.Verbosity = Flags.verbosity;
227   Options.MaxLen = Flags.max_len;
228   Options.UnitTimeoutSec = Flags.timeout;
229   Options.DoCrossOver = Flags.cross_over;
230   Options.MutateDepth = Flags.mutate_depth;
231   Options.ExitOnFirst = Flags.exit_on_first;
232   Options.UseCounters = Flags.use_counters;
233   Options.UseTraces = Flags.use_traces;
234   Options.UseFullCoverageSet = Flags.use_full_coverage_set;
235   Options.UseCoveragePairs = Flags.use_coverage_pairs;
236   Options.PreferSmallDuringInitialShuffle =
237       Flags.prefer_small_during_initial_shuffle;
238   Options.Tokens = ReadTokensFile(Flags.tokens);
239   Options.Reload = Flags.reload;
240   if (Flags.runs >= 0)
241     Options.MaxNumberOfRuns = Flags.runs;
242   if (!inputs.empty())
243     Options.OutputCorpus = inputs[0];
244   if (Flags.sync_command)
245     Options.SyncCommand = Flags.sync_command;
246   Options.SyncTimeout = Flags.sync_timeout;
247   Fuzzer F(Callback, Options);
248
249   unsigned seed = Flags.seed;
250   // Initialize seed.
251   if (seed == 0)
252     seed = time(0) * 10000 + getpid();
253   if (Flags.verbosity)
254     std::cerr << "Seed: " << seed << "\n";
255   srand(seed);
256
257   // Timer
258   if (Flags.timeout > 0)
259     SetTimer(Flags.timeout / 2 + 1);
260
261   if (Flags.verbosity >= 2) {
262     std::cerr << "Tokens: {";
263     for (auto &T : Options.Tokens)
264       std::cerr << T << ",";
265     std::cerr << "}\n";
266   }
267
268   if (Flags.apply_tokens)
269     return ApplyTokens(F, Flags.apply_tokens);
270
271   F.RereadOutputCorpus();
272   for (auto &inp : inputs)
273     if (inp != Options.OutputCorpus)
274       F.ReadDir(inp, nullptr);
275
276   if (F.CorpusSize() == 0)
277     F.AddToCorpus(Unit());  // Can't fuzz empty corpus, so add an empty input.
278   F.ShuffleAndMinimize();
279   if (Flags.save_minimized_corpus)
280     F.SaveCorpus();
281   F.Loop(Flags.iterations < 0 ? INT_MAX : Flags.iterations);
282   if (Flags.verbosity)
283     std::cerr << "Done " << F.getTotalNumberOfRuns()
284               << " runs in " << F.secondsSinceProcessStartUp()
285               << " seconds\n";
286   return 0;
287 }
288
289 }  // namespace fuzzer