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 <unistd.h>
17#include <iostream>
18#include <thread>
19#include <atomic>
20#include <mutex>
21#include <string>
22#include <sstream>
23#include <algorithm>
24#include <iterator>
25
26namespace fuzzer {
27
28// Program arguments.
29struct FlagDescription {
30  const char *Name;
31  const char *Description;
32  int   Default;
33  int   *IntFlag;
34  const char **StrFlag;
35};
36
37struct {
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
43} Flags;
44
45static 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
53};
54
55static const size_t kNumFlags =
56    sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]);
57
58static std::vector<std::string> inputs;
59static const char *ProgName;
60
61static 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);
68
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++)
73      std::cerr << " ";
74    std::cerr << "\t";
75    std::cerr << D.Default << "\t" << D.Description << "\n";
76  }
77}
78
79static 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];
84  return nullptr;
85}
86
87static 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);
92    if (Str)  {
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";
98        return true;
99      } else if (FlagDescriptions[F].StrFlag) {
100        *FlagDescriptions[F].StrFlag = Str;
101        if (Flags.verbosity >= 2)
102          std::cerr << "Flag: " << Name << " " << Str << "\n";
103        return true;
104      }
105    }
106  }
107  PrintHelp();
108  exit(1);
109}
110
111// We don't use any library to minimize dependencies.
112static 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;
118  }
119  for (int A = 1; A < argc; A++) {
120    if (ParseOneFlag(argv[A])) continue;
121    inputs.push_back(argv[A]);
122  }
123}
124
125static void WorkerThread(const std::string &Cmd, std::atomic<int> *Counter,
126                        int NumJobs, std::atomic<bool> *HasErrors) {
127  static std::mutex CerrMutex;
128  while (true) {
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";
133    if (Flags.verbosity)
134      std::cerr << ToRun;
135    int ExitCode = system(ToRun.c_str());
136    if (ExitCode != 0)
137      *HasErrors = true;
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);
143  }
144}
145
146static int RunInMultipleProcesses(int argc, char **argv, int NumWorkers,
147                                  int NumJobs) {
148  std::atomic<int> Counter(0);
149  std::atomic<bool> HasErrors(false);
150  std::string Cmd;
151  for (int i = 0; i < argc; i++) {
152    if (FlagValue(argv[i], "jobs") || FlagValue(argv[i], "workers")) continue;
153    Cmd += argv[i];
154    Cmd += " ";
155  }
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));
159  for (auto &T : V)
160    T.join();
161  return HasErrors ? 1 : 0;
162}
163
164std::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>{}};
170  Res.push_back(" ");
171  Res.push_back("\t");
172  Res.push_back("\n");
173  return Res;
174}
175
176int ApplyTokens(const Fuzzer &F, const char *InputFilePath) {
177  Unit U = FileToVector(InputFilePath);
178  auto T = F.SubstituteTokens(U);
179  T.push_back(0);
180  std::cout << T.data();
181  return 0;
182}
183
184int FuzzerDriver(int argc, char **argv, UserCallback Callback) {
185  using namespace fuzzer;
186
187  ProgName = argv[0];
188  ParseFlags(argc, argv);
189  if (Flags.help) {
190    PrintHelp();
191    return 0;
192  }
193
194  if (Flags.workers > 0 && Flags.jobs > 0)
195    return RunInMultipleProcesses(argc, argv, Flags.workers, Flags.jobs);
196
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  if (Flags.runs >= 0)
211    Options.MaxNumberOfRuns = Flags.runs;
212  if (!inputs.empty())
213    Options.OutputCorpus = inputs[0];
214  Fuzzer F(Callback, Options);
215
216  unsigned seed = Flags.seed;
217  // Initialize seed.
218  if (seed == 0)
219    seed = time(0) * 10000 + getpid();
220  if (Flags.verbosity)
221    std::cerr << "Seed: " << seed << "\n";
222  srand(seed);
223
224  // Timer
225  if (Flags.timeout > 0)
226    SetTimer(Flags.timeout);
227
228  if (Flags.verbosity >= 2) {
229    std::cerr << "Tokens: {";
230    for (auto &T : Options.Tokens)
231      std::cerr << T << ",";
232    std::cerr << "}\n";
233  }
234
235  if (Flags.apply_tokens)
236    return ApplyTokens(F, Flags.apply_tokens);
237
238  for (auto &inp : inputs)
239    F.ReadDir(inp);
240
241  if (F.CorpusSize() == 0)
242    F.AddToCorpus(Unit());  // Can't fuzz empty corpus, so add an empty input.
243  F.ShuffleAndMinimize();
244  if (Flags.save_minimized_corpus)
245    F.SaveCorpus();
246  F.Loop(Flags.iterations < 0 ? INT_MAX : Flags.iterations);
247  if (Flags.verbosity)
248    std::cerr << "Done " << F.getTotalNumberOfRuns()
249              << " runs in " << F.secondsSinceProcessStartUp()
250              << " seconds\n";
251  return 0;
252}
253
254}  // namespace fuzzer
255