1 //===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // FuzzerDriver and flag parsing. 9 //===----------------------------------------------------------------------===// 10 11 #include "FuzzerCommand.h" 12 #include "FuzzerCorpus.h" 13 #include "FuzzerIO.h" 14 #include "FuzzerInterface.h" 15 #include "FuzzerInternal.h" 16 #include "FuzzerMutate.h" 17 #include "FuzzerRandom.h" 18 #include "FuzzerTracePC.h" 19 #include "FuzzerMerge.h" 20 #include <algorithm> 21 #include <atomic> 22 #include <chrono> 23 #include <cstdlib> 24 #include <cstring> 25 #include <mutex> 26 #include <string> 27 #include <thread> 28 #include <fstream> 29 30 // This function should be present in the libFuzzer so that the client 31 // binary can test for its existence. 32 #if LIBFUZZER_MSVC 33 extern "C" void __libfuzzer_is_present() {} 34 #pragma comment(linker, "/include:__libfuzzer_is_present") 35 #else 36 extern "C" __attribute__((used)) void __libfuzzer_is_present() {} 37 #endif // LIBFUZZER_MSVC 38 39 namespace fuzzer { 40 41 // Program arguments. 42 struct FlagDescription { 43 const char *Name; 44 const char *Description; 45 int Default; 46 int *IntFlag; 47 const char **StrFlag; 48 unsigned int *UIntFlag; 49 }; 50 51 struct { 52 #define FUZZER_DEPRECATED_FLAG(Name) 53 #define FUZZER_FLAG_INT(Name, Default, Description) int Name; 54 #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name; 55 #define FUZZER_FLAG_STRING(Name, Description) const char *Name; 56 #include "FuzzerFlags.def" 57 #undef FUZZER_DEPRECATED_FLAG 58 #undef FUZZER_FLAG_INT 59 #undef FUZZER_FLAG_UNSIGNED 60 #undef FUZZER_FLAG_STRING 61 } Flags; 62 63 static const FlagDescription FlagDescriptions [] { 64 #define FUZZER_DEPRECATED_FLAG(Name) \ 65 {#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr}, 66 #define FUZZER_FLAG_INT(Name, Default, Description) \ 67 {#Name, Description, Default, &Flags.Name, nullptr, nullptr}, 68 #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) \ 69 {#Name, Description, static_cast<int>(Default), \ 70 nullptr, nullptr, &Flags.Name}, 71 #define FUZZER_FLAG_STRING(Name, Description) \ 72 {#Name, Description, 0, nullptr, &Flags.Name, nullptr}, 73 #include "FuzzerFlags.def" 74 #undef FUZZER_DEPRECATED_FLAG 75 #undef FUZZER_FLAG_INT 76 #undef FUZZER_FLAG_UNSIGNED 77 #undef FUZZER_FLAG_STRING 78 }; 79 80 static const size_t kNumFlags = 81 sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]); 82 83 static Vector<std::string> *Inputs; 84 static std::string *ProgName; 85 86 static void PrintHelp() { 87 Printf("Usage:\n"); 88 auto Prog = ProgName->c_str(); 89 Printf("\nTo run fuzzing pass 0 or more directories.\n"); 90 Printf("%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog); 91 92 Printf("\nTo run individual tests without fuzzing pass 1 or more files:\n"); 93 Printf("%s [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n", Prog); 94 95 Printf("\nFlags: (strictly in form -flag=value)\n"); 96 size_t MaxFlagLen = 0; 97 for (size_t F = 0; F < kNumFlags; F++) 98 MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen); 99 100 for (size_t F = 0; F < kNumFlags; F++) { 101 const auto &D = FlagDescriptions[F]; 102 if (strstr(D.Description, "internal flag") == D.Description) continue; 103 Printf(" %s", D.Name); 104 for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++) 105 Printf(" "); 106 Printf("\t"); 107 Printf("%d\t%s\n", D.Default, D.Description); 108 } 109 Printf("\nFlags starting with '--' will be ignored and " 110 "will be passed verbatim to subprocesses.\n"); 111 } 112 113 static const char *FlagValue(const char *Param, const char *Name) { 114 size_t Len = strlen(Name); 115 if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 && 116 Param[Len + 1] == '=') 117 return &Param[Len + 2]; 118 return nullptr; 119 } 120 121 // Avoid calling stol as it triggers a bug in clang/glibc build. 122 static long MyStol(const char *Str) { 123 long Res = 0; 124 long Sign = 1; 125 if (*Str == '-') { 126 Str++; 127 Sign = -1; 128 } 129 for (size_t i = 0; Str[i]; i++) { 130 char Ch = Str[i]; 131 if (Ch < '0' || Ch > '9') 132 return Res; 133 Res = Res * 10 + (Ch - '0'); 134 } 135 return Res * Sign; 136 } 137 138 static bool ParseOneFlag(const char *Param) { 139 if (Param[0] != '-') return false; 140 if (Param[1] == '-') { 141 static bool PrintedWarning = false; 142 if (!PrintedWarning) { 143 PrintedWarning = true; 144 Printf("INFO: libFuzzer ignores flags that start with '--'\n"); 145 } 146 for (size_t F = 0; F < kNumFlags; F++) 147 if (FlagValue(Param + 1, FlagDescriptions[F].Name)) 148 Printf("WARNING: did you mean '%s' (single dash)?\n", Param + 1); 149 return true; 150 } 151 for (size_t F = 0; F < kNumFlags; F++) { 152 const char *Name = FlagDescriptions[F].Name; 153 const char *Str = FlagValue(Param, Name); 154 if (Str) { 155 if (FlagDescriptions[F].IntFlag) { 156 int Val = MyStol(Str); 157 *FlagDescriptions[F].IntFlag = Val; 158 if (Flags.verbosity >= 2) 159 Printf("Flag: %s %d\n", Name, Val); 160 return true; 161 } else if (FlagDescriptions[F].UIntFlag) { 162 unsigned int Val = std::stoul(Str); 163 *FlagDescriptions[F].UIntFlag = Val; 164 if (Flags.verbosity >= 2) 165 Printf("Flag: %s %u\n", Name, Val); 166 return true; 167 } else if (FlagDescriptions[F].StrFlag) { 168 *FlagDescriptions[F].StrFlag = Str; 169 if (Flags.verbosity >= 2) 170 Printf("Flag: %s %s\n", Name, Str); 171 return true; 172 } else { // Deprecated flag. 173 Printf("Flag: %s: deprecated, don't use\n", Name); 174 return true; 175 } 176 } 177 } 178 Printf("\n\nWARNING: unrecognized flag '%s'; " 179 "use -help=1 to list all flags\n\n", Param); 180 return true; 181 } 182 183 // We don't use any library to minimize dependencies. 184 static void ParseFlags(const Vector<std::string> &Args) { 185 for (size_t F = 0; F < kNumFlags; F++) { 186 if (FlagDescriptions[F].IntFlag) 187 *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default; 188 if (FlagDescriptions[F].UIntFlag) 189 *FlagDescriptions[F].UIntFlag = 190 static_cast<unsigned int>(FlagDescriptions[F].Default); 191 if (FlagDescriptions[F].StrFlag) 192 *FlagDescriptions[F].StrFlag = nullptr; 193 } 194 Inputs = new Vector<std::string>; 195 for (size_t A = 1; A < Args.size(); A++) { 196 if (ParseOneFlag(Args[A].c_str())) { 197 if (Flags.ignore_remaining_args) 198 break; 199 continue; 200 } 201 Inputs->push_back(Args[A]); 202 } 203 } 204 205 static std::mutex Mu; 206 207 static void PulseThread() { 208 while (true) { 209 SleepSeconds(600); 210 std::lock_guard<std::mutex> Lock(Mu); 211 Printf("pulse...\n"); 212 } 213 } 214 215 static void WorkerThread(const Command &BaseCmd, std::atomic<unsigned> *Counter, 216 unsigned NumJobs, std::atomic<bool> *HasErrors) { 217 while (true) { 218 unsigned C = (*Counter)++; 219 if (C >= NumJobs) break; 220 std::string Log = "fuzz-" + std::to_string(C) + ".log"; 221 Command Cmd(BaseCmd); 222 Cmd.setOutputFile(Log); 223 Cmd.combineOutAndErr(); 224 if (Flags.verbosity) { 225 std::string CommandLine = Cmd.toString(); 226 Printf("%s\n", CommandLine.c_str()); 227 } 228 int ExitCode = ExecuteCommand(Cmd); 229 if (ExitCode != 0) 230 *HasErrors = true; 231 std::lock_guard<std::mutex> Lock(Mu); 232 Printf("================== Job %u exited with exit code %d ============\n", 233 C, ExitCode); 234 fuzzer::CopyFileToErr(Log); 235 } 236 } 237 238 std::string CloneArgsWithoutX(const Vector<std::string> &Args, 239 const char *X1, const char *X2) { 240 std::string Cmd; 241 for (auto &S : Args) { 242 if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2)) 243 continue; 244 Cmd += S + " "; 245 } 246 return Cmd; 247 } 248 249 static int RunInMultipleProcesses(const Vector<std::string> &Args, 250 unsigned NumWorkers, unsigned NumJobs) { 251 std::atomic<unsigned> Counter(0); 252 std::atomic<bool> HasErrors(false); 253 Command Cmd(Args); 254 Cmd.removeFlag("jobs"); 255 Cmd.removeFlag("workers"); 256 Vector<std::thread> V; 257 std::thread Pulse(PulseThread); 258 Pulse.detach(); 259 for (unsigned i = 0; i < NumWorkers; i++) 260 V.push_back(std::thread(WorkerThread, std::ref(Cmd), &Counter, NumJobs, &HasErrors)); 261 for (auto &T : V) 262 T.join(); 263 return HasErrors ? 1 : 0; 264 } 265 266 static void RssThread(Fuzzer *F, size_t RssLimitMb) { 267 while (true) { 268 SleepSeconds(1); 269 size_t Peak = GetPeakRSSMb(); 270 if (Peak > RssLimitMb) 271 F->RssLimitCallback(); 272 } 273 } 274 275 static void StartRssThread(Fuzzer *F, size_t RssLimitMb) { 276 if (!RssLimitMb) return; 277 std::thread T(RssThread, F, RssLimitMb); 278 T.detach(); 279 } 280 281 int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) { 282 Unit U = FileToVector(InputFilePath); 283 if (MaxLen && MaxLen < U.size()) 284 U.resize(MaxLen); 285 F->ExecuteCallback(U.data(), U.size()); 286 F->TryDetectingAMemoryLeak(U.data(), U.size(), true); 287 return 0; 288 } 289 290 static bool AllInputsAreFiles() { 291 if (Inputs->empty()) return false; 292 for (auto &Path : *Inputs) 293 if (!IsFile(Path)) 294 return false; 295 return true; 296 } 297 298 static std::string GetDedupTokenFromFile(const std::string &Path) { 299 auto S = FileToString(Path); 300 auto Beg = S.find("DEDUP_TOKEN:"); 301 if (Beg == std::string::npos) 302 return ""; 303 auto End = S.find('\n', Beg); 304 if (End == std::string::npos) 305 return ""; 306 return S.substr(Beg, End - Beg); 307 } 308 309 static std::string TempPath(const char *Extension) { 310 return DirPlusFile(TmpDir(), 311 "libFuzzerTemp." + std::to_string(GetPid()) + Extension); 312 } 313 314 int CleanseCrashInput(const Vector<std::string> &Args, 315 const FuzzingOptions &Options) { 316 if (Inputs->size() != 1 || !Flags.exact_artifact_path) { 317 Printf("ERROR: -cleanse_crash should be given one input file and" 318 " -exact_artifact_path\n"); 319 exit(1); 320 } 321 std::string InputFilePath = Inputs->at(0); 322 std::string OutputFilePath = Flags.exact_artifact_path; 323 Command Cmd(Args); 324 Cmd.removeFlag("cleanse_crash"); 325 326 assert(Cmd.hasArgument(InputFilePath)); 327 Cmd.removeArgument(InputFilePath); 328 329 auto LogFilePath = TempPath(".txt"); 330 auto TmpFilePath = TempPath(".repro"); 331 Cmd.addArgument(TmpFilePath); 332 Cmd.setOutputFile(LogFilePath); 333 Cmd.combineOutAndErr(); 334 335 std::string CurrentFilePath = InputFilePath; 336 auto U = FileToVector(CurrentFilePath); 337 size_t Size = U.size(); 338 339 const Vector<uint8_t> ReplacementBytes = {' ', 0xff}; 340 for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) { 341 bool Changed = false; 342 for (size_t Idx = 0; Idx < Size; Idx++) { 343 Printf("CLEANSE[%d]: Trying to replace byte %zd of %zd\n", NumAttempts, 344 Idx, Size); 345 uint8_t OriginalByte = U[Idx]; 346 if (ReplacementBytes.end() != std::find(ReplacementBytes.begin(), 347 ReplacementBytes.end(), 348 OriginalByte)) 349 continue; 350 for (auto NewByte : ReplacementBytes) { 351 U[Idx] = NewByte; 352 WriteToFile(U, TmpFilePath); 353 auto ExitCode = ExecuteCommand(Cmd); 354 RemoveFile(TmpFilePath); 355 if (!ExitCode) { 356 U[Idx] = OriginalByte; 357 } else { 358 Changed = true; 359 Printf("CLEANSE: Replaced byte %zd with 0x%x\n", Idx, NewByte); 360 WriteToFile(U, OutputFilePath); 361 break; 362 } 363 } 364 } 365 if (!Changed) break; 366 } 367 RemoveFile(LogFilePath); 368 return 0; 369 } 370 371 int MinimizeCrashInput(const Vector<std::string> &Args, 372 const FuzzingOptions &Options) { 373 if (Inputs->size() != 1) { 374 Printf("ERROR: -minimize_crash should be given one input file\n"); 375 exit(1); 376 } 377 std::string InputFilePath = Inputs->at(0); 378 Command BaseCmd(Args); 379 BaseCmd.removeFlag("minimize_crash"); 380 BaseCmd.removeFlag("exact_artifact_path"); 381 assert(BaseCmd.hasArgument(InputFilePath)); 382 BaseCmd.removeArgument(InputFilePath); 383 if (Flags.runs <= 0 && Flags.max_total_time == 0) { 384 Printf("INFO: you need to specify -runs=N or " 385 "-max_total_time=N with -minimize_crash=1\n" 386 "INFO: defaulting to -max_total_time=600\n"); 387 BaseCmd.addFlag("max_total_time", "600"); 388 } 389 390 auto LogFilePath = TempPath(".txt"); 391 BaseCmd.setOutputFile(LogFilePath); 392 BaseCmd.combineOutAndErr(); 393 394 std::string CurrentFilePath = InputFilePath; 395 while (true) { 396 Unit U = FileToVector(CurrentFilePath); 397 Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n", 398 CurrentFilePath.c_str(), U.size()); 399 400 Command Cmd(BaseCmd); 401 Cmd.addArgument(CurrentFilePath); 402 403 std::string CommandLine = Cmd.toString(); 404 Printf("CRASH_MIN: executing: %s\n", CommandLine.c_str()); 405 int ExitCode = ExecuteCommand(Cmd); 406 if (ExitCode == 0) { 407 Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str()); 408 exit(1); 409 } 410 Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize " 411 "it further\n", 412 CurrentFilePath.c_str(), U.size()); 413 auto DedupToken1 = GetDedupTokenFromFile(LogFilePath); 414 if (!DedupToken1.empty()) 415 Printf("CRASH_MIN: DedupToken1: %s\n", DedupToken1.c_str()); 416 417 std::string ArtifactPath = 418 Flags.exact_artifact_path 419 ? Flags.exact_artifact_path 420 : Options.ArtifactPrefix + "minimized-from-" + Hash(U); 421 Cmd.addFlag("minimize_crash_internal_step", "1"); 422 Cmd.addFlag("exact_artifact_path", ArtifactPath); 423 CommandLine = Cmd.toString(); 424 Printf("CRASH_MIN: executing: %s\n", CommandLine.c_str()); 425 ExitCode = ExecuteCommand(Cmd); 426 CopyFileToErr(LogFilePath); 427 if (ExitCode == 0) { 428 if (Flags.exact_artifact_path) { 429 CurrentFilePath = Flags.exact_artifact_path; 430 WriteToFile(U, CurrentFilePath); 431 } 432 Printf("CRASH_MIN: failed to minimize beyond %s (%d bytes), exiting\n", 433 CurrentFilePath.c_str(), U.size()); 434 break; 435 } 436 auto DedupToken2 = GetDedupTokenFromFile(LogFilePath); 437 if (!DedupToken2.empty()) 438 Printf("CRASH_MIN: DedupToken2: %s\n", DedupToken2.c_str()); 439 440 if (DedupToken1 != DedupToken2) { 441 if (Flags.exact_artifact_path) { 442 CurrentFilePath = Flags.exact_artifact_path; 443 WriteToFile(U, CurrentFilePath); 444 } 445 Printf("CRASH_MIN: mismatch in dedup tokens" 446 " (looks like a different bug). Won't minimize further\n"); 447 break; 448 } 449 450 CurrentFilePath = ArtifactPath; 451 Printf("*********************************\n"); 452 } 453 RemoveFile(LogFilePath); 454 return 0; 455 } 456 457 int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) { 458 assert(Inputs->size() == 1); 459 std::string InputFilePath = Inputs->at(0); 460 Unit U = FileToVector(InputFilePath); 461 Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size()); 462 if (U.size() < 2) { 463 Printf("INFO: The input is small enough, exiting\n"); 464 exit(0); 465 } 466 F->SetMaxInputLen(U.size()); 467 F->SetMaxMutationLen(U.size() - 1); 468 F->MinimizeCrashLoop(U); 469 Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n"); 470 exit(0); 471 return 0; 472 } 473 474 // This is just a skeleton of an experimental -fork=1 feature. 475 void FuzzWithFork(const FuzzingOptions &Options, 476 const Vector<std::string> &Args, 477 const Vector<std::string> &Corpora) { 478 Printf("INFO: -fork=1: doing fuzzing in a separate process in order to " 479 "be more resistant to crashes, timeouts, and OOMs\n"); 480 481 Vector<SizedFile> Corpus; 482 for (auto &Dir : Corpora) 483 GetSizedFilesFromDir(Dir, &Corpus); 484 std::sort(Corpus.begin(), Corpus.end()); 485 486 Vector<std::string> Files; 487 Set<uint32_t> Features; 488 if (!Corpus.empty()) { 489 auto CFPath = TempPath(".fork"); 490 CrashResistantMerge(Args, {}, Corpus, &Files, {}, &Features, CFPath); 491 RemoveFile(CFPath); 492 } 493 Printf("INFO: -fork=1: %zd seeds, starting to fuzz\n", Files.size()); 494 495 Command Cmd(Args); 496 Cmd.removeFlag("fork"); 497 for (auto &C : Corpora) // Remove all corpora from the args. 498 Cmd.removeArgument(C); 499 if (Files.size() >= 2) 500 Cmd.addFlag("seed_inputs", 501 Files.back() + "," + Files[Files.size() - 2]); 502 Cmd.addFlag("runs", "1000000"); 503 Cmd.addFlag("max_total_time", "30"); 504 for (size_t i = 0; i < 1000; i++) { 505 Printf("RUN %s\n", Cmd.toString().c_str()); 506 int ExitCode = ExecuteCommand(Cmd); 507 if (ExitCode == Options.InterruptExitCode) 508 exit(0); 509 if (ExitCode == Options.TimeoutExitCode || ExitCode == Options.OOMExitCode) 510 continue; 511 if (ExitCode != 0) break; 512 } 513 514 exit(0); 515 } 516 517 void Merge(Fuzzer *F, FuzzingOptions &Options, const Vector<std::string> &Args, 518 const Vector<std::string> &Corpora, const char *CFPathOrNull) { 519 if (Corpora.size() < 2) { 520 Printf("INFO: Merge requires two or more corpus dirs\n"); 521 exit(0); 522 } 523 524 Vector<SizedFile> OldCorpus, NewCorpus; 525 GetSizedFilesFromDir(Corpora[0], &OldCorpus); 526 for (size_t i = 1; i < Corpora.size(); i++) 527 GetSizedFilesFromDir(Corpora[i], &NewCorpus); 528 std::sort(OldCorpus.begin(), OldCorpus.end()); 529 std::sort(NewCorpus.begin(), NewCorpus.end()); 530 531 std::string CFPath = CFPathOrNull ? CFPathOrNull : TempPath(".txt"); 532 Vector<std::string> NewFiles; 533 Set<uint32_t> NewFeatures; 534 CrashResistantMerge(Args, OldCorpus, NewCorpus, &NewFiles, {}, &NewFeatures, 535 CFPath); 536 for (auto &Path : NewFiles) 537 F->WriteToOutputCorpus(FileToVector(Path, Options.MaxLen)); 538 // We are done, delete the control file if it was a temporary one. 539 if (!Flags.merge_control_file) 540 RemoveFile(CFPath); 541 542 exit(0); 543 } 544 545 int AnalyzeDictionary(Fuzzer *F, const Vector<Unit>& Dict, 546 UnitVector& Corpus) { 547 Printf("Started dictionary minimization (up to %d tests)\n", 548 Dict.size() * Corpus.size() * 2); 549 550 // Scores and usage count for each dictionary unit. 551 Vector<int> Scores(Dict.size()); 552 Vector<int> Usages(Dict.size()); 553 554 Vector<size_t> InitialFeatures; 555 Vector<size_t> ModifiedFeatures; 556 for (auto &C : Corpus) { 557 // Get coverage for the testcase without modifications. 558 F->ExecuteCallback(C.data(), C.size()); 559 InitialFeatures.clear(); 560 TPC.CollectFeatures([&](size_t Feature) { 561 InitialFeatures.push_back(Feature); 562 }); 563 564 for (size_t i = 0; i < Dict.size(); ++i) { 565 Vector<uint8_t> Data = C; 566 auto StartPos = std::search(Data.begin(), Data.end(), 567 Dict[i].begin(), Dict[i].end()); 568 // Skip dictionary unit, if the testcase does not contain it. 569 if (StartPos == Data.end()) 570 continue; 571 572 ++Usages[i]; 573 while (StartPos != Data.end()) { 574 // Replace all occurrences of dictionary unit in the testcase. 575 auto EndPos = StartPos + Dict[i].size(); 576 for (auto It = StartPos; It != EndPos; ++It) 577 *It ^= 0xFF; 578 579 StartPos = std::search(EndPos, Data.end(), 580 Dict[i].begin(), Dict[i].end()); 581 } 582 583 // Get coverage for testcase with masked occurrences of dictionary unit. 584 F->ExecuteCallback(Data.data(), Data.size()); 585 ModifiedFeatures.clear(); 586 TPC.CollectFeatures([&](size_t Feature) { 587 ModifiedFeatures.push_back(Feature); 588 }); 589 590 if (InitialFeatures == ModifiedFeatures) 591 --Scores[i]; 592 else 593 Scores[i] += 2; 594 } 595 } 596 597 Printf("###### Useless dictionary elements. ######\n"); 598 for (size_t i = 0; i < Dict.size(); ++i) { 599 // Dictionary units with positive score are treated as useful ones. 600 if (Scores[i] > 0) 601 continue; 602 603 Printf("\""); 604 PrintASCII(Dict[i].data(), Dict[i].size(), "\""); 605 Printf(" # Score: %d, Used: %d\n", Scores[i], Usages[i]); 606 } 607 Printf("###### End of useless dictionary elements. ######\n"); 608 return 0; 609 } 610 611 int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { 612 using namespace fuzzer; 613 assert(argc && argv && "Argument pointers cannot be nullptr"); 614 std::string Argv0((*argv)[0]); 615 EF = new ExternalFunctions(); 616 if (EF->LLVMFuzzerInitialize) 617 EF->LLVMFuzzerInitialize(argc, argv); 618 if (EF->__msan_scoped_disable_interceptor_checks) 619 EF->__msan_scoped_disable_interceptor_checks(); 620 const Vector<std::string> Args(*argv, *argv + *argc); 621 assert(!Args.empty()); 622 ProgName = new std::string(Args[0]); 623 if (Argv0 != *ProgName) { 624 Printf("ERROR: argv[0] has been modified in LLVMFuzzerInitialize\n"); 625 exit(1); 626 } 627 ParseFlags(Args); 628 if (Flags.help) { 629 PrintHelp(); 630 return 0; 631 } 632 633 if (Flags.close_fd_mask & 2) 634 DupAndCloseStderr(); 635 if (Flags.close_fd_mask & 1) 636 CloseStdout(); 637 638 if (Flags.jobs > 0 && Flags.workers == 0) { 639 Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs); 640 if (Flags.workers > 1) 641 Printf("Running %u workers\n", Flags.workers); 642 } 643 644 if (Flags.workers > 0 && Flags.jobs > 0) 645 return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs); 646 647 FuzzingOptions Options; 648 Options.Verbosity = Flags.verbosity; 649 Options.MaxLen = Flags.max_len; 650 Options.LenControl = Flags.len_control; 651 Options.UnitTimeoutSec = Flags.timeout; 652 Options.ErrorExitCode = Flags.error_exitcode; 653 Options.TimeoutExitCode = Flags.timeout_exitcode; 654 Options.MaxTotalTimeSec = Flags.max_total_time; 655 Options.DoCrossOver = Flags.cross_over; 656 Options.MutateDepth = Flags.mutate_depth; 657 Options.ReduceDepth = Flags.reduce_depth; 658 Options.UseCounters = Flags.use_counters; 659 Options.UseMemmem = Flags.use_memmem; 660 Options.UseCmp = Flags.use_cmp; 661 Options.UseValueProfile = Flags.use_value_profile; 662 Options.Shrink = Flags.shrink; 663 Options.ReduceInputs = Flags.reduce_inputs; 664 Options.ShuffleAtStartUp = Flags.shuffle; 665 Options.PreferSmall = Flags.prefer_small; 666 Options.ReloadIntervalSec = Flags.reload; 667 Options.OnlyASCII = Flags.only_ascii; 668 Options.DetectLeaks = Flags.detect_leaks; 669 Options.PurgeAllocatorIntervalSec = Flags.purge_allocator_interval; 670 Options.TraceMalloc = Flags.trace_malloc; 671 Options.RssLimitMb = Flags.rss_limit_mb; 672 Options.MallocLimitMb = Flags.malloc_limit_mb; 673 if (!Options.MallocLimitMb) 674 Options.MallocLimitMb = Options.RssLimitMb; 675 if (Flags.runs >= 0) 676 Options.MaxNumberOfRuns = Flags.runs; 677 if (!Inputs->empty() && !Flags.minimize_crash_internal_step) 678 Options.OutputCorpus = (*Inputs)[0]; 679 Options.ReportSlowUnits = Flags.report_slow_units; 680 if (Flags.artifact_prefix) 681 Options.ArtifactPrefix = Flags.artifact_prefix; 682 if (Flags.exact_artifact_path) 683 Options.ExactArtifactPath = Flags.exact_artifact_path; 684 Vector<Unit> Dictionary; 685 if (Flags.dict) 686 if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary)) 687 return 1; 688 if (Flags.verbosity > 0 && !Dictionary.empty()) 689 Printf("Dictionary: %zd entries\n", Dictionary.size()); 690 bool DoPlainRun = AllInputsAreFiles(); 691 Options.SaveArtifacts = 692 !DoPlainRun || Flags.minimize_crash_internal_step; 693 Options.PrintNewCovPcs = Flags.print_pcs; 694 Options.PrintNewCovFuncs = Flags.print_funcs; 695 Options.PrintFinalStats = Flags.print_final_stats; 696 Options.PrintCorpusStats = Flags.print_corpus_stats; 697 Options.PrintCoverage = Flags.print_coverage; 698 if (Flags.exit_on_src_pos) 699 Options.ExitOnSrcPos = Flags.exit_on_src_pos; 700 if (Flags.exit_on_item) 701 Options.ExitOnItem = Flags.exit_on_item; 702 if (Flags.focus_function) 703 Options.FocusFunction = Flags.focus_function; 704 if (Flags.data_flow_trace) 705 Options.DataFlowTrace = Flags.data_flow_trace; 706 Options.LazyCounters = Flags.lazy_counters; 707 708 unsigned Seed = Flags.seed; 709 // Initialize Seed. 710 if (Seed == 0) 711 Seed = 712 std::chrono::system_clock::now().time_since_epoch().count() + GetPid(); 713 if (Flags.verbosity) 714 Printf("INFO: Seed: %u\n", Seed); 715 716 Random Rand(Seed); 717 auto *MD = new MutationDispatcher(Rand, Options); 718 auto *Corpus = new InputCorpus(Options.OutputCorpus); 719 auto *F = new Fuzzer(Callback, *Corpus, *MD, Options); 720 721 for (auto &U: Dictionary) 722 if (U.size() <= Word::GetMaxSize()) 723 MD->AddWordToManualDictionary(Word(U.data(), U.size())); 724 725 StartRssThread(F, Flags.rss_limit_mb); 726 727 Options.HandleAbrt = Flags.handle_abrt; 728 Options.HandleBus = Flags.handle_bus; 729 Options.HandleFpe = Flags.handle_fpe; 730 Options.HandleIll = Flags.handle_ill; 731 Options.HandleInt = Flags.handle_int; 732 Options.HandleSegv = Flags.handle_segv; 733 Options.HandleTerm = Flags.handle_term; 734 Options.HandleXfsz = Flags.handle_xfsz; 735 Options.HandleUsr1 = Flags.handle_usr1; 736 Options.HandleUsr2 = Flags.handle_usr2; 737 SetSignalHandler(Options); 738 739 std::atexit(Fuzzer::StaticExitCallback); 740 741 if (Flags.minimize_crash) 742 return MinimizeCrashInput(Args, Options); 743 744 if (Flags.minimize_crash_internal_step) 745 return MinimizeCrashInputInternalStep(F, Corpus); 746 747 if (Flags.cleanse_crash) 748 return CleanseCrashInput(Args, Options); 749 750 if (DoPlainRun) { 751 Options.SaveArtifacts = false; 752 int Runs = std::max(1, Flags.runs); 753 Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName->c_str(), 754 Inputs->size(), Runs); 755 for (auto &Path : *Inputs) { 756 auto StartTime = system_clock::now(); 757 Printf("Running: %s\n", Path.c_str()); 758 for (int Iter = 0; Iter < Runs; Iter++) 759 RunOneTest(F, Path.c_str(), Options.MaxLen); 760 auto StopTime = system_clock::now(); 761 auto MS = duration_cast<milliseconds>(StopTime - StartTime).count(); 762 Printf("Executed %s in %zd ms\n", Path.c_str(), (long)MS); 763 } 764 Printf("***\n" 765 "*** NOTE: fuzzing was not performed, you have only\n" 766 "*** executed the target code on a fixed set of inputs.\n" 767 "***\n"); 768 F->PrintFinalStats(); 769 exit(0); 770 } 771 772 if (Flags.fork) 773 FuzzWithFork(Options, Args, *Inputs); 774 775 if (Flags.merge) 776 Merge(F, Options, Args, *Inputs, Flags.merge_control_file); 777 778 if (Flags.merge_inner) { 779 const size_t kDefaultMaxMergeLen = 1 << 20; 780 if (Options.MaxLen == 0) 781 F->SetMaxInputLen(kDefaultMaxMergeLen); 782 assert(Flags.merge_control_file); 783 F->CrashResistantMergeInternalStep(Flags.merge_control_file); 784 exit(0); 785 } 786 787 if (Flags.analyze_dict) { 788 size_t MaxLen = INT_MAX; // Large max length. 789 UnitVector InitialCorpus; 790 for (auto &Inp : *Inputs) { 791 Printf("Loading corpus dir: %s\n", Inp.c_str()); 792 ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr, 793 MaxLen, /*ExitOnError=*/false); 794 } 795 796 if (Dictionary.empty() || Inputs->empty()) { 797 Printf("ERROR: can't analyze dict without dict and corpus provided\n"); 798 return 1; 799 } 800 if (AnalyzeDictionary(F, Dictionary, InitialCorpus)) { 801 Printf("Dictionary analysis failed\n"); 802 exit(1); 803 } 804 Printf("Dictionary analysis succeeded\n"); 805 exit(0); 806 } 807 808 // Parse -seed_inputs=file1,file2,... 809 Vector<std::string> ExtraSeedFiles; 810 if (Flags.seed_inputs) { 811 std::string s = Flags.seed_inputs; 812 size_t comma_pos; 813 while ((comma_pos = s.find_last_of(',')) != std::string::npos) { 814 ExtraSeedFiles.push_back(s.substr(comma_pos + 1)); 815 s = s.substr(0, comma_pos); 816 } 817 ExtraSeedFiles.push_back(s); 818 } 819 820 F->Loop(*Inputs, ExtraSeedFiles); 821 822 if (Flags.verbosity) 823 Printf("Done %zd runs in %zd second(s)\n", F->getTotalNumberOfRuns(), 824 F->secondsSinceProcessStartUp()); 825 F->PrintFinalStats(); 826 827 exit(0); // Don't let F destroy itself. 828 } 829 830 // Storage for global ExternalFunctions object. 831 ExternalFunctions *EF = nullptr; 832 833 } // namespace fuzzer 834