blob: 05a699e50688cb0d42c16b771faf00c188becf4f [file] [log] [blame]
Kostya Serebryany016852c2015-02-19 18:45:37 +00001//===- 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>
Kostya Serebryany52a788e2015-03-31 20:13:20 +000021#include <string>
22#include <sstream>
23#include <algorithm>
24#include <iterator>
Kostya Serebryany016852c2015-02-19 18:45:37 +000025
26namespace fuzzer {
27
28// Program arguments.
29struct FlagDescription {
30 const char *Name;
31 const char *Description;
32 int Default;
Kostya Serebryany52a788e2015-03-31 20:13:20 +000033 int *IntFlag;
34 const char **StrFlag;
Kostya Serebryany016852c2015-02-19 18:45:37 +000035};
36
37struct {
Kostya Serebryany52a788e2015-03-31 20:13:20 +000038#define FUZZER_FLAG_INT(Name, Default, Description) int Name;
39#define FUZZER_FLAG_STRING(Name, Description) const char *Name;
Kostya Serebryany016852c2015-02-19 18:45:37 +000040#include "FuzzerFlags.def"
Kostya Serebryany52a788e2015-03-31 20:13:20 +000041#undef FUZZER_FLAG_INT
42#undef FUZZER_FLAG_STRING
Kostya Serebryany016852c2015-02-19 18:45:37 +000043} Flags;
44
45static FlagDescription FlagDescriptions [] {
Kostya Serebryany52a788e2015-03-31 20:13:20 +000046#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 },
Kostya Serebryany016852c2015-02-19 18:45:37 +000050#include "FuzzerFlags.def"
Kostya Serebryany52a788e2015-03-31 20:13:20 +000051#undef FUZZER_FLAG_INT
52#undef FUZZER_FLAG_STRING
Kostya Serebryany016852c2015-02-19 18:45:37 +000053};
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) {
Kostya Serebryany52a788e2015-03-31 20:13:20 +000093 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 }
Kostya Serebryany016852c2015-02-19 18:45:37 +0000105 }
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) {
Kostya Serebryany52a788e2015-03-31 20:13:20 +0000113 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 }
Kostya Serebryany016852c2015-02-19 18:45:37 +0000119 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
Kostya Serebryany52a788e2015-03-31 20:13:20 +0000164std::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
Kostya Serebryany016852c2015-02-19 18:45:37 +0000184int 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;
Kostya Serebryanybe5e0ed2015-03-03 23:27:02 +0000203 Options.UseCounters = Flags.use_counters;
Kostya Serebryany016852c2015-02-19 18:45:37 +0000204 Options.UseFullCoverageSet = Flags.use_full_coverage_set;
Kostya Serebryany2e3622b2015-02-20 03:02:37 +0000205 Options.UseCoveragePairs = Flags.use_coverage_pairs;
Kostya Serebryany16d03bd2015-03-30 22:09:51 +0000206 Options.UseDFSan = Flags.dfsan;
Kostya Serebryany016852c2015-02-19 18:45:37 +0000207 Options.PreferSmallDuringInitialShuffle =
208 Flags.prefer_small_during_initial_shuffle;
Kostya Serebryany52a788e2015-03-31 20:13:20 +0000209 Options.Tokens = ReadTokensFile(Flags.tokens);
Kostya Serebryany016852c2015-02-19 18:45:37 +0000210 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
Kostya Serebryany52a788e2015-03-31 20:13:20 +0000228 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
Kostya Serebryany016852c2015-02-19 18:45:37 +0000238 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