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 <algorithm> 16 #include <atomic> 17 #include <chrono> 18 #include <cstring> 19 #include <mutex> 20 #include <string> 21 #include <thread> 22 #include <unistd.h> 23 24 // This function should be present in the libFuzzer so that the client 25 // binary can test for its existence. 26 extern "C" __attribute__((used)) void __libfuzzer_is_present() {} 27 28 namespace fuzzer { 29 30 // Program arguments. 31 struct FlagDescription { 32 const char *Name; 33 const char *Description; 34 int Default; 35 int *IntFlag; 36 const char **StrFlag; 37 unsigned int *UIntFlag; 38 }; 39 40 struct { 41 #define FUZZER_DEPRECATED_FLAG(Name) 42 #define FUZZER_FLAG_INT(Name, Default, Description) int Name; 43 #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name; 44 #define FUZZER_FLAG_STRING(Name, Description) const char *Name; 45 #include "FuzzerFlags.def" 46 #undef FUZZER_DEPRECATED_FLAG 47 #undef FUZZER_FLAG_INT 48 #undef FUZZER_FLAG_UNSIGNED 49 #undef FUZZER_FLAG_STRING 50 } Flags; 51 52 static const FlagDescription FlagDescriptions [] { 53 #define FUZZER_DEPRECATED_FLAG(Name) \ 54 {#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr}, 55 #define FUZZER_FLAG_INT(Name, Default, Description) \ 56 {#Name, Description, Default, &Flags.Name, nullptr, nullptr}, 57 #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) \ 58 {#Name, Description, static_cast<int>(Default), \ 59 nullptr, nullptr, &Flags.Name}, 60 #define FUZZER_FLAG_STRING(Name, Description) \ 61 {#Name, Description, 0, nullptr, &Flags.Name, nullptr}, 62 #include "FuzzerFlags.def" 63 #undef FUZZER_DEPRECATED_FLAG 64 #undef FUZZER_FLAG_INT 65 #undef FUZZER_FLAG_UNSIGNED 66 #undef FUZZER_FLAG_STRING 67 }; 68 69 static const size_t kNumFlags = 70 sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]); 71 72 static std::vector<std::string> *Inputs; 73 static std::string *ProgName; 74 75 static void PrintHelp() { 76 Printf("Usage:\n"); 77 auto Prog = ProgName->c_str(); 78 Printf("\nTo run fuzzing pass 0 or more directories.\n"); 79 Printf("%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog); 80 81 Printf("\nTo run individual tests without fuzzing pass 1 or more files:\n"); 82 Printf("%s [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n", Prog); 83 84 Printf("\nFlags: (strictly in form -flag=value)\n"); 85 size_t MaxFlagLen = 0; 86 for (size_t F = 0; F < kNumFlags; F++) 87 MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen); 88 89 for (size_t F = 0; F < kNumFlags; F++) { 90 const auto &D = FlagDescriptions[F]; 91 Printf(" %s", D.Name); 92 for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++) 93 Printf(" "); 94 Printf("\t"); 95 Printf("%d\t%s\n", D.Default, D.Description); 96 } 97 Printf("\nFlags starting with '--' will be ignored and " 98 "will be passed verbatim to subprocesses.\n"); 99 } 100 101 static const char *FlagValue(const char *Param, const char *Name) { 102 size_t Len = strlen(Name); 103 if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 && 104 Param[Len + 1] == '=') 105 return &Param[Len + 2]; 106 return nullptr; 107 } 108 109 // Avoid calling stol as it triggers a bug in clang/glibc build. 110 static long MyStol(const char *Str) { 111 long Res = 0; 112 long Sign = 1; 113 if (*Str == '-') { 114 Str++; 115 Sign = -1; 116 } 117 for (size_t i = 0; Str[i]; i++) { 118 char Ch = Str[i]; 119 if (Ch < '0' || Ch > '9') 120 return Res; 121 Res = Res * 10 + (Ch - '0'); 122 } 123 return Res * Sign; 124 } 125 126 static bool ParseOneFlag(const char *Param) { 127 if (Param[0] != '-') return false; 128 if (Param[1] == '-') { 129 static bool PrintedWarning = false; 130 if (!PrintedWarning) { 131 PrintedWarning = true; 132 Printf("INFO: libFuzzer ignores flags that start with '--'\n"); 133 } 134 for (size_t F = 0; F < kNumFlags; F++) 135 if (FlagValue(Param + 1, FlagDescriptions[F].Name)) 136 Printf("WARNING: did you mean '%s' (single dash)?\n", Param + 1); 137 return true; 138 } 139 for (size_t F = 0; F < kNumFlags; F++) { 140 const char *Name = FlagDescriptions[F].Name; 141 const char *Str = FlagValue(Param, Name); 142 if (Str) { 143 if (FlagDescriptions[F].IntFlag) { 144 int Val = MyStol(Str); 145 *FlagDescriptions[F].IntFlag = Val; 146 if (Flags.verbosity >= 2) 147 Printf("Flag: %s %d\n", Name, Val);; 148 return true; 149 } else if (FlagDescriptions[F].UIntFlag) { 150 unsigned int Val = std::stoul(Str); 151 *FlagDescriptions[F].UIntFlag = Val; 152 if (Flags.verbosity >= 2) 153 Printf("Flag: %s %u\n", Name, Val); 154 return true; 155 } else if (FlagDescriptions[F].StrFlag) { 156 *FlagDescriptions[F].StrFlag = Str; 157 if (Flags.verbosity >= 2) 158 Printf("Flag: %s %s\n", Name, Str); 159 return true; 160 } else { // Deprecated flag. 161 Printf("Flag: %s: deprecated, don't use\n", Name); 162 return true; 163 } 164 } 165 } 166 Printf("\n\nWARNING: unrecognized flag '%s'; " 167 "use -help=1 to list all flags\n\n", Param); 168 return true; 169 } 170 171 // We don't use any library to minimize dependencies. 172 static void ParseFlags(const std::vector<std::string> &Args) { 173 for (size_t F = 0; F < kNumFlags; F++) { 174 if (FlagDescriptions[F].IntFlag) 175 *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default; 176 if (FlagDescriptions[F].UIntFlag) 177 *FlagDescriptions[F].UIntFlag = 178 static_cast<unsigned int>(FlagDescriptions[F].Default); 179 if (FlagDescriptions[F].StrFlag) 180 *FlagDescriptions[F].StrFlag = nullptr; 181 } 182 Inputs = new std::vector<std::string>; 183 for (size_t A = 1; A < Args.size(); A++) { 184 if (ParseOneFlag(Args[A].c_str())) continue; 185 Inputs->push_back(Args[A]); 186 } 187 } 188 189 static std::mutex Mu; 190 191 static void PulseThread() { 192 while (true) { 193 SleepSeconds(600); 194 std::lock_guard<std::mutex> Lock(Mu); 195 Printf("pulse...\n"); 196 } 197 } 198 199 static void WorkerThread(const std::string &Cmd, std::atomic<int> *Counter, 200 int NumJobs, std::atomic<bool> *HasErrors) { 201 while (true) { 202 int C = (*Counter)++; 203 if (C >= NumJobs) break; 204 std::string Log = "fuzz-" + std::to_string(C) + ".log"; 205 std::string ToRun = Cmd + " > " + Log + " 2>&1\n"; 206 if (Flags.verbosity) 207 Printf("%s", ToRun.c_str()); 208 int ExitCode = ExecuteCommand(ToRun); 209 if (ExitCode != 0) 210 *HasErrors = true; 211 std::lock_guard<std::mutex> Lock(Mu); 212 Printf("================== Job %d exited with exit code %d ============\n", 213 C, ExitCode); 214 fuzzer::CopyFileToErr(Log); 215 } 216 } 217 218 static int RunInMultipleProcesses(const std::vector<std::string> &Args, 219 int NumWorkers, int NumJobs) { 220 std::atomic<int> Counter(0); 221 std::atomic<bool> HasErrors(false); 222 std::string Cmd; 223 for (auto &S : Args) { 224 if (FlagValue(S.c_str(), "jobs") || FlagValue(S.c_str(), "workers")) 225 continue; 226 Cmd += S + " "; 227 } 228 std::vector<std::thread> V; 229 std::thread Pulse(PulseThread); 230 Pulse.detach(); 231 for (int i = 0; i < NumWorkers; i++) 232 V.push_back(std::thread(WorkerThread, Cmd, &Counter, NumJobs, &HasErrors)); 233 for (auto &T : V) 234 T.join(); 235 return HasErrors ? 1 : 0; 236 } 237 238 static void RssThread(Fuzzer *F, size_t RssLimitMb) { 239 while (true) { 240 SleepSeconds(1); 241 size_t Peak = GetPeakRSSMb(); 242 if (Peak > RssLimitMb) 243 F->RssLimitCallback(); 244 } 245 } 246 247 static void StartRssThread(Fuzzer *F, size_t RssLimitMb) { 248 if (!RssLimitMb) return; 249 std::thread T(RssThread, F, RssLimitMb); 250 T.detach(); 251 } 252 253 int RunOneTest(Fuzzer *F, const char *InputFilePath) { 254 Unit U = FileToVector(InputFilePath); 255 Unit PreciseSizedU(U); 256 assert(PreciseSizedU.size() == PreciseSizedU.capacity()); 257 F->RunOne(PreciseSizedU.data(), PreciseSizedU.size()); 258 return 0; 259 } 260 261 static bool AllInputsAreFiles() { 262 if (Inputs->empty()) return false; 263 for (auto &Path : *Inputs) 264 if (!IsFile(Path)) 265 return false; 266 return true; 267 } 268 269 int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { 270 using namespace fuzzer; 271 assert(argc && argv && "Argument pointers cannot be nullptr"); 272 EF = new ExternalFunctions(); 273 if (EF->LLVMFuzzerInitialize) 274 EF->LLVMFuzzerInitialize(argc, argv); 275 const std::vector<std::string> Args(*argv, *argv + *argc); 276 assert(!Args.empty()); 277 ProgName = new std::string(Args[0]); 278 ParseFlags(Args); 279 if (Flags.help) { 280 PrintHelp(); 281 return 0; 282 } 283 284 if (Flags.close_fd_mask & 2) 285 DupAndCloseStderr(); 286 if (Flags.close_fd_mask & 1) 287 CloseStdout(); 288 289 if (Flags.jobs > 0 && Flags.workers == 0) { 290 Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs); 291 if (Flags.workers > 1) 292 Printf("Running %d workers\n", Flags.workers); 293 } 294 295 if (Flags.workers > 0 && Flags.jobs > 0) 296 return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs); 297 298 const size_t kMaxSaneLen = 1 << 20; 299 const size_t kMinDefaultLen = 64; 300 FuzzingOptions Options; 301 Options.Verbosity = Flags.verbosity; 302 Options.MaxLen = Flags.max_len; 303 Options.UnitTimeoutSec = Flags.timeout; 304 Options.TimeoutExitCode = Flags.timeout_exitcode; 305 Options.MaxTotalTimeSec = Flags.max_total_time; 306 Options.DoCrossOver = Flags.cross_over; 307 Options.MutateDepth = Flags.mutate_depth; 308 Options.UseCounters = Flags.use_counters; 309 Options.UseIndirCalls = Flags.use_indir_calls; 310 Options.UseTraces = Flags.use_traces; 311 Options.UseMemcmp = Flags.use_memcmp; 312 Options.ShuffleAtStartUp = Flags.shuffle; 313 Options.PreferSmall = Flags.prefer_small; 314 Options.Reload = Flags.reload; 315 Options.OnlyASCII = Flags.only_ascii; 316 Options.OutputCSV = Flags.output_csv; 317 Options.DetectLeaks = Flags.detect_leaks; 318 Options.RssLimitMb = Flags.rss_limit_mb; 319 if (Flags.runs >= 0) 320 Options.MaxNumberOfRuns = Flags.runs; 321 if (!Inputs->empty()) 322 Options.OutputCorpus = (*Inputs)[0]; 323 Options.ReportSlowUnits = Flags.report_slow_units; 324 if (Flags.artifact_prefix) 325 Options.ArtifactPrefix = Flags.artifact_prefix; 326 if (Flags.exact_artifact_path) 327 Options.ExactArtifactPath = Flags.exact_artifact_path; 328 std::vector<Unit> Dictionary; 329 if (Flags.dict) 330 if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary)) 331 return 1; 332 if (Flags.verbosity > 0 && !Dictionary.empty()) 333 Printf("Dictionary: %zd entries\n", Dictionary.size()); 334 bool DoPlainRun = AllInputsAreFiles(); 335 Options.SaveArtifacts = !DoPlainRun; 336 Options.PrintNewCovPcs = Flags.print_new_cov_pcs; 337 Options.PrintFinalStats = Flags.print_final_stats; 338 Options.TruncateUnits = Flags.truncate_units; 339 Options.PruneCorpus = Flags.prune_corpus; 340 341 unsigned Seed = Flags.seed; 342 // Initialize Seed. 343 if (Seed == 0) 344 Seed = (std::chrono::system_clock::now().time_since_epoch().count() << 10) + 345 getpid(); 346 if (Flags.verbosity) 347 Printf("INFO: Seed: %u\n", Seed); 348 349 Random Rand(Seed); 350 MutationDispatcher MD(Rand, Options); 351 Fuzzer F(Callback, MD, Options); 352 353 for (auto &U: Dictionary) 354 if (U.size() <= Word::GetMaxSize()) 355 MD.AddWordToManualDictionary(Word(U.data(), U.size())); 356 357 StartRssThread(&F, Flags.rss_limit_mb); 358 359 // Timer 360 if (Flags.timeout > 0) 361 SetTimer(Flags.timeout / 2 + 1); 362 if (Flags.handle_segv) SetSigSegvHandler(); 363 if (Flags.handle_bus) SetSigBusHandler(); 364 if (Flags.handle_abrt) SetSigAbrtHandler(); 365 if (Flags.handle_ill) SetSigIllHandler(); 366 if (Flags.handle_fpe) SetSigFpeHandler(); 367 if (Flags.handle_int) SetSigIntHandler(); 368 if (Flags.handle_term) SetSigTermHandler(); 369 370 if (DoPlainRun) { 371 Options.SaveArtifacts = false; 372 int Runs = std::max(1, Flags.runs); 373 Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName->c_str(), 374 Inputs->size(), Runs); 375 for (auto &Path : *Inputs) { 376 auto StartTime = system_clock::now(); 377 Printf("Running: %s\n", Path.c_str()); 378 for (int Iter = 0; Iter < Runs; Iter++) 379 RunOneTest(&F, Path.c_str()); 380 auto StopTime = system_clock::now(); 381 auto MS = duration_cast<milliseconds>(StopTime - StartTime).count(); 382 Printf("Executed %s in %zd ms\n", Path.c_str(), (long)MS); 383 } 384 F.PrintFinalStats(); 385 exit(0); 386 } 387 388 389 if (Flags.merge) { 390 if (Options.MaxLen == 0) 391 F.SetMaxLen(kMaxSaneLen); 392 F.Merge(*Inputs); 393 exit(0); 394 } 395 396 size_t TemporaryMaxLen = Options.MaxLen ? Options.MaxLen : kMaxSaneLen; 397 398 F.RereadOutputCorpus(TemporaryMaxLen); 399 for (auto &inp : *Inputs) 400 if (inp != Options.OutputCorpus) 401 F.ReadDir(inp, nullptr, TemporaryMaxLen); 402 403 if (Options.MaxLen == 0) 404 F.SetMaxLen( 405 std::min(std::max(kMinDefaultLen, F.MaxUnitSizeInCorpus()), kMaxSaneLen)); 406 407 if (F.CorpusSize() == 0) { 408 F.AddToCorpus(Unit()); // Can't fuzz empty corpus, so add an empty input. 409 if (Options.Verbosity) 410 Printf("INFO: A corpus is not provided, starting from an empty corpus\n"); 411 } 412 F.ShuffleAndMinimize(); 413 if (Flags.drill) 414 F.Drill(); 415 else 416 F.Loop(); 417 418 if (Flags.verbosity) 419 Printf("Done %d runs in %zd second(s)\n", F.getTotalNumberOfRuns(), 420 F.secondsSinceProcessStartUp()); 421 F.PrintFinalStats(); 422 423 exit(0); // Don't let F destroy itself. 424 } 425 426 // Storage for global ExternalFunctions object. 427 ExternalFunctions *EF = nullptr; 428 429 } // namespace fuzzer 430