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 <thread> 19 #include <atomic> 20 #include <mutex> 21 #include <string> 22 #include <sstream> 23 #include <algorithm> 24 #include <iterator> 25 26 namespace fuzzer { 27 28 // Program arguments. 29 struct FlagDescription { 30 const char *Name; 31 const char *Description; 32 int Default; 33 int *IntFlag; 34 const char **StrFlag; 35 unsigned int *UIntFlag; 36 }; 37 38 struct { 39 #define FUZZER_FLAG_INT(Name, Default, Description) int Name; 40 #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name; 41 #define FUZZER_FLAG_STRING(Name, Description) const char *Name; 42 #include "FuzzerFlags.def" 43 #undef FUZZER_FLAG_INT 44 #undef FUZZER_FLAG_UNSIGNED 45 #undef FUZZER_FLAG_STRING 46 } Flags; 47 48 static const FlagDescription FlagDescriptions [] { 49 #define FUZZER_FLAG_INT(Name, Default, Description) \ 50 {#Name, Description, Default, &Flags.Name, nullptr, nullptr}, 51 #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) \ 52 {#Name, Description, static_cast<int>(Default), \ 53 nullptr, nullptr, &Flags.Name}, 54 #define FUZZER_FLAG_STRING(Name, Description) \ 55 {#Name, Description, 0, nullptr, &Flags.Name, nullptr}, 56 #include "FuzzerFlags.def" 57 #undef FUZZER_FLAG_INT 58 #undef FUZZER_FLAG_UNSIGNED 59 #undef FUZZER_FLAG_STRING 60 }; 61 62 static const size_t kNumFlags = 63 sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]); 64 65 static std::vector<std::string> *Inputs; 66 static std::string *ProgName; 67 68 static void PrintHelp() { 69 Printf("Usage: %s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", 70 ProgName->c_str()); 71 Printf("\nFlags: (strictly in form -flag=value)\n"); 72 size_t MaxFlagLen = 0; 73 for (size_t F = 0; F < kNumFlags; F++) 74 MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen); 75 76 for (size_t F = 0; F < kNumFlags; F++) { 77 const auto &D = FlagDescriptions[F]; 78 Printf(" %s", D.Name); 79 for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++) 80 Printf(" "); 81 Printf("\t"); 82 Printf("%d\t%s\n", D.Default, D.Description); 83 } 84 Printf("\nFlags starting with '--' will be ignored and " 85 "will be passed verbatim to subprocesses.\n"); 86 } 87 88 static const char *FlagValue(const char *Param, const char *Name) { 89 size_t Len = strlen(Name); 90 if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 && 91 Param[Len + 1] == '=') 92 return &Param[Len + 2]; 93 return nullptr; 94 } 95 96 static bool ParseOneFlag(const char *Param) { 97 if (Param[0] != '-') return false; 98 if (Param[1] == '-') { 99 static bool PrintedWarning = false; 100 if (!PrintedWarning) { 101 PrintedWarning = true; 102 Printf("WARNING: libFuzzer ignores flags that start with '--'\n"); 103 } 104 return true; 105 } 106 for (size_t F = 0; F < kNumFlags; F++) { 107 const char *Name = FlagDescriptions[F].Name; 108 const char *Str = FlagValue(Param, Name); 109 if (Str) { 110 if (FlagDescriptions[F].IntFlag) { 111 int Val = std::stol(Str); 112 *FlagDescriptions[F].IntFlag = Val; 113 if (Flags.verbosity >= 2) 114 Printf("Flag: %s %d\n", Name, Val);; 115 return true; 116 } else if (FlagDescriptions[F].UIntFlag) { 117 unsigned int Val = std::stoul(Str); 118 *FlagDescriptions[F].UIntFlag = Val; 119 if (Flags.verbosity >= 2) 120 Printf("Flag: %s %u\n", Name, Val); 121 return true; 122 } else if (FlagDescriptions[F].StrFlag) { 123 *FlagDescriptions[F].StrFlag = Str; 124 if (Flags.verbosity >= 2) 125 Printf("Flag: %s %s\n", Name, Str); 126 return true; 127 } 128 } 129 } 130 PrintHelp(); 131 exit(1); 132 } 133 134 // We don't use any library to minimize dependencies. 135 static void ParseFlags(const std::vector<std::string> &Args) { 136 for (size_t F = 0; F < kNumFlags; F++) { 137 if (FlagDescriptions[F].IntFlag) 138 *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default; 139 if (FlagDescriptions[F].UIntFlag) 140 *FlagDescriptions[F].UIntFlag = 141 static_cast<unsigned int>(FlagDescriptions[F].Default); 142 if (FlagDescriptions[F].StrFlag) 143 *FlagDescriptions[F].StrFlag = nullptr; 144 } 145 Inputs = new std::vector<std::string>; 146 for (size_t A = 1; A < Args.size(); A++) { 147 if (ParseOneFlag(Args[A].c_str())) continue; 148 Inputs->push_back(Args[A]); 149 } 150 } 151 152 static std::mutex Mu; 153 154 static void PulseThread() { 155 while (true) { 156 std::this_thread::sleep_for(std::chrono::seconds(600)); 157 std::lock_guard<std::mutex> Lock(Mu); 158 Printf("pulse...\n"); 159 } 160 } 161 162 static void WorkerThread(const std::string &Cmd, std::atomic<int> *Counter, 163 int NumJobs, std::atomic<bool> *HasErrors) { 164 while (true) { 165 int C = (*Counter)++; 166 if (C >= NumJobs) break; 167 std::string Log = "fuzz-" + std::to_string(C) + ".log"; 168 std::string ToRun = Cmd + " > " + Log + " 2>&1\n"; 169 if (Flags.verbosity) 170 Printf("%s", ToRun.c_str()); 171 int ExitCode = ExecuteCommand(ToRun.c_str()); 172 if (ExitCode != 0) 173 *HasErrors = true; 174 std::lock_guard<std::mutex> Lock(Mu); 175 Printf("================== Job %d exited with exit code %d ============\n", 176 C, ExitCode); 177 fuzzer::CopyFileToErr(Log); 178 } 179 } 180 181 static int RunInMultipleProcesses(const std::vector<std::string> &Args, 182 int NumWorkers, int NumJobs) { 183 std::atomic<int> Counter(0); 184 std::atomic<bool> HasErrors(false); 185 std::string Cmd; 186 for (auto &S : Args) { 187 if (FlagValue(S.c_str(), "jobs") || FlagValue(S.c_str(), "workers")) 188 continue; 189 Cmd += S + " "; 190 } 191 std::vector<std::thread> V; 192 std::thread Pulse(PulseThread); 193 Pulse.detach(); 194 for (int i = 0; i < NumWorkers; i++) 195 V.push_back(std::thread(WorkerThread, Cmd, &Counter, NumJobs, &HasErrors)); 196 for (auto &T : V) 197 T.join(); 198 return HasErrors ? 1 : 0; 199 } 200 201 int RunOneTest(Fuzzer *F, const char *InputFilePath) { 202 Unit U = FileToVector(InputFilePath); 203 Unit PreciseSizedU(U); 204 assert(PreciseSizedU.size() == PreciseSizedU.capacity()); 205 F->ExecuteCallback(PreciseSizedU); 206 return 0; 207 } 208 209 int FuzzerDriver(int argc, char **argv, UserCallback Callback) { 210 FuzzerRandomLibc Rand(0); 211 SimpleUserSuppliedFuzzer SUSF(&Rand, Callback); 212 return FuzzerDriver(argc, argv, SUSF); 213 } 214 215 int FuzzerDriver(int argc, char **argv, UserSuppliedFuzzer &USF) { 216 std::vector<std::string> Args(argv, argv + argc); 217 return FuzzerDriver(Args, USF); 218 } 219 220 int FuzzerDriver(const std::vector<std::string> &Args, UserCallback Callback) { 221 FuzzerRandomLibc Rand(0); 222 SimpleUserSuppliedFuzzer SUSF(&Rand, Callback); 223 return FuzzerDriver(Args, SUSF); 224 } 225 226 int FuzzerDriver(const std::vector<std::string> &Args, 227 UserSuppliedFuzzer &USF) { 228 using namespace fuzzer; 229 assert(!Args.empty()); 230 ProgName = new std::string(Args[0]); 231 ParseFlags(Args); 232 if (Flags.help) { 233 PrintHelp(); 234 return 0; 235 } 236 237 if (Flags.jobs > 0 && Flags.workers == 0) { 238 Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs); 239 if (Flags.workers > 1) 240 Printf("Running %d workers\n", Flags.workers); 241 } 242 243 if (Flags.workers > 0 && Flags.jobs > 0) 244 return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs); 245 246 Fuzzer::FuzzingOptions Options; 247 Options.Verbosity = Flags.verbosity; 248 Options.MaxLen = Flags.max_len; 249 Options.UnitTimeoutSec = Flags.timeout; 250 Options.MaxTotalTimeSec = Flags.max_total_time; 251 Options.DoCrossOver = Flags.cross_over; 252 Options.MutateDepth = Flags.mutate_depth; 253 Options.ExitOnFirst = Flags.exit_on_first; 254 Options.UseCounters = Flags.use_counters; 255 Options.UseIndirCalls = Flags.use_indir_calls; 256 Options.UseTraces = Flags.use_traces; 257 Options.ShuffleAtStartUp = Flags.shuffle; 258 Options.PreferSmallDuringInitialShuffle = 259 Flags.prefer_small_during_initial_shuffle; 260 Options.Reload = Flags.reload; 261 Options.OnlyASCII = Flags.only_ascii; 262 Options.TBMDepth = Flags.tbm_depth; 263 Options.TBMWidth = Flags.tbm_width; 264 Options.OutputCSV = Flags.output_csv; 265 if (Flags.runs >= 0) 266 Options.MaxNumberOfRuns = Flags.runs; 267 if (!Inputs->empty()) 268 Options.OutputCorpus = (*Inputs)[0]; 269 if (Flags.sync_command) 270 Options.SyncCommand = Flags.sync_command; 271 Options.SyncTimeout = Flags.sync_timeout; 272 Options.ReportSlowUnits = Flags.report_slow_units; 273 if (Flags.artifact_prefix) 274 Options.ArtifactPrefix = Flags.artifact_prefix; 275 if (Flags.exact_artifact_path) 276 Options.ExactArtifactPath = Flags.exact_artifact_path; 277 std::vector<Unit> Dictionary; 278 if (Flags.dict) 279 if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary)) 280 return 1; 281 if (Flags.verbosity > 0 && !Dictionary.empty()) 282 Printf("Dictionary: %zd entries\n", Dictionary.size()); 283 Options.SaveArtifacts = !Flags.test_single_input; 284 285 Fuzzer F(USF, Options); 286 287 for (auto &U: Dictionary) 288 USF.GetMD().AddWordToDictionary(U.data(), U.size()); 289 290 // Timer 291 if (Flags.timeout > 0) 292 SetTimer(Flags.timeout / 2 + 1); 293 294 if (Flags.test_single_input) { 295 RunOneTest(&F, Flags.test_single_input); 296 exit(0); 297 } 298 299 if (Flags.save_minimized_corpus) { 300 Printf("The flag -save_minimized_corpus is deprecated; use -merge=1\n"); 301 exit(1); 302 } 303 304 if (Flags.merge) { 305 F.Merge(*Inputs); 306 exit(0); 307 } 308 309 unsigned Seed = Flags.seed; 310 // Initialize Seed. 311 if (Seed == 0) 312 Seed = time(0) * 10000 + getpid(); 313 if (Flags.verbosity) 314 Printf("Seed: %u\n", Seed); 315 USF.GetRand().ResetSeed(Seed); 316 317 F.RereadOutputCorpus(); 318 for (auto &inp : *Inputs) 319 if (inp != Options.OutputCorpus) 320 F.ReadDir(inp, nullptr); 321 322 if (F.CorpusSize() == 0) 323 F.AddToCorpus(Unit()); // Can't fuzz empty corpus, so add an empty input. 324 F.ShuffleAndMinimize(); 325 if (Flags.drill) 326 F.Drill(); 327 else 328 F.Loop(); 329 330 if (Flags.verbosity) 331 Printf("Done %d runs in %zd second(s)\n", F.getTotalNumberOfRuns(), 332 F.secondsSinceProcessStartUp()); 333 334 exit(0); // Don't let F destroy itself. 335 } 336 337 } // namespace fuzzer 338