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