110ab2aceSGeorge Karpenkov //===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===//
210ab2aceSGeorge Karpenkov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610ab2aceSGeorge Karpenkov //
710ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
810ab2aceSGeorge Karpenkov // FuzzerDriver and flag parsing.
910ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
1010ab2aceSGeorge Karpenkov 
1104304d12SMatt Morehouse #include "FuzzerCommand.h"
1210ab2aceSGeorge Karpenkov #include "FuzzerCorpus.h"
135c08e811SKostya Serebryany #include "FuzzerFork.h"
1410ab2aceSGeorge Karpenkov #include "FuzzerIO.h"
1510ab2aceSGeorge Karpenkov #include "FuzzerInterface.h"
1610ab2aceSGeorge Karpenkov #include "FuzzerInternal.h"
175c08e811SKostya Serebryany #include "FuzzerMerge.h"
1810ab2aceSGeorge Karpenkov #include "FuzzerMutate.h"
19226866e1SDokyung Song #include "FuzzerPlatform.h"
2010ab2aceSGeorge Karpenkov #include "FuzzerRandom.h"
2110ab2aceSGeorge Karpenkov #include "FuzzerTracePC.h"
2210ab2aceSGeorge Karpenkov #include <algorithm>
2310ab2aceSGeorge Karpenkov #include <atomic>
2410ab2aceSGeorge Karpenkov #include <chrono>
2510ab2aceSGeorge Karpenkov #include <cstdlib>
2610ab2aceSGeorge Karpenkov #include <cstring>
2710ab2aceSGeorge Karpenkov #include <mutex>
2810ab2aceSGeorge Karpenkov #include <string>
2910ab2aceSGeorge Karpenkov #include <thread>
30c5d72517SMarco Vanotti #include <fstream>
3110ab2aceSGeorge Karpenkov 
3210ab2aceSGeorge Karpenkov // This function should be present in the libFuzzer so that the client
3310ab2aceSGeorge Karpenkov // binary can test for its existence.
34b795c31dSJonathan Metzman #if LIBFUZZER_MSVC
__libfuzzer_is_present()35b795c31dSJonathan Metzman extern "C" void __libfuzzer_is_present() {}
36c12f1118SVitaly Buka #if defined(_M_IX86) || defined(__i386__)
37c12f1118SVitaly Buka #pragma comment(linker, "/include:___libfuzzer_is_present")
38c12f1118SVitaly Buka #else
39b795c31dSJonathan Metzman #pragma comment(linker, "/include:__libfuzzer_is_present")
40c12f1118SVitaly Buka #endif
41b795c31dSJonathan Metzman #else
__libfuzzer_is_present()4210ab2aceSGeorge Karpenkov extern "C" __attribute__((used)) void __libfuzzer_is_present() {}
43b795c31dSJonathan Metzman #endif  // LIBFUZZER_MSVC
4410ab2aceSGeorge Karpenkov 
4510ab2aceSGeorge Karpenkov namespace fuzzer {
4610ab2aceSGeorge Karpenkov 
4710ab2aceSGeorge Karpenkov // Program arguments.
4810ab2aceSGeorge Karpenkov struct FlagDescription {
4910ab2aceSGeorge Karpenkov   const char *Name;
5010ab2aceSGeorge Karpenkov   const char *Description;
5110ab2aceSGeorge Karpenkov   int   Default;
5210ab2aceSGeorge Karpenkov   int   *IntFlag;
5310ab2aceSGeorge Karpenkov   const char **StrFlag;
5410ab2aceSGeorge Karpenkov   unsigned int *UIntFlag;
5510ab2aceSGeorge Karpenkov };
5610ab2aceSGeorge Karpenkov 
5710ab2aceSGeorge Karpenkov struct {
5810ab2aceSGeorge Karpenkov #define FUZZER_DEPRECATED_FLAG(Name)
5910ab2aceSGeorge Karpenkov #define FUZZER_FLAG_INT(Name, Default, Description) int Name;
6010ab2aceSGeorge Karpenkov #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name;
6110ab2aceSGeorge Karpenkov #define FUZZER_FLAG_STRING(Name, Description) const char *Name;
6210ab2aceSGeorge Karpenkov #include "FuzzerFlags.def"
6310ab2aceSGeorge Karpenkov #undef FUZZER_DEPRECATED_FLAG
6410ab2aceSGeorge Karpenkov #undef FUZZER_FLAG_INT
6510ab2aceSGeorge Karpenkov #undef FUZZER_FLAG_UNSIGNED
6610ab2aceSGeorge Karpenkov #undef FUZZER_FLAG_STRING
6710ab2aceSGeorge Karpenkov } Flags;
6810ab2aceSGeorge Karpenkov 
6910ab2aceSGeorge Karpenkov static const FlagDescription FlagDescriptions [] {
7010ab2aceSGeorge Karpenkov #define FUZZER_DEPRECATED_FLAG(Name)                                           \
7110ab2aceSGeorge Karpenkov   {#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr},
7210ab2aceSGeorge Karpenkov #define FUZZER_FLAG_INT(Name, Default, Description)                            \
7310ab2aceSGeorge Karpenkov   {#Name, Description, Default, &Flags.Name, nullptr, nullptr},
7410ab2aceSGeorge Karpenkov #define FUZZER_FLAG_UNSIGNED(Name, Default, Description)                       \
7510ab2aceSGeorge Karpenkov   {#Name,   Description, static_cast<int>(Default),                            \
7610ab2aceSGeorge Karpenkov    nullptr, nullptr, &Flags.Name},
7710ab2aceSGeorge Karpenkov #define FUZZER_FLAG_STRING(Name, Description)                                  \
7810ab2aceSGeorge Karpenkov   {#Name, Description, 0, nullptr, &Flags.Name, nullptr},
7910ab2aceSGeorge Karpenkov #include "FuzzerFlags.def"
8010ab2aceSGeorge Karpenkov #undef FUZZER_DEPRECATED_FLAG
8110ab2aceSGeorge Karpenkov #undef FUZZER_FLAG_INT
8210ab2aceSGeorge Karpenkov #undef FUZZER_FLAG_UNSIGNED
8310ab2aceSGeorge Karpenkov #undef FUZZER_FLAG_STRING
8410ab2aceSGeorge Karpenkov };
8510ab2aceSGeorge Karpenkov 
8610ab2aceSGeorge Karpenkov static const size_t kNumFlags =
8710ab2aceSGeorge Karpenkov     sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]);
8810ab2aceSGeorge Karpenkov 
897c921753SKostya Serebryany static std::vector<std::string> *Inputs;
9010ab2aceSGeorge Karpenkov static std::string *ProgName;
9110ab2aceSGeorge Karpenkov 
PrintHelp()9210ab2aceSGeorge Karpenkov static void PrintHelp() {
9310ab2aceSGeorge Karpenkov   Printf("Usage:\n");
9410ab2aceSGeorge Karpenkov   auto Prog = ProgName->c_str();
9510ab2aceSGeorge Karpenkov   Printf("\nTo run fuzzing pass 0 or more directories.\n");
9610ab2aceSGeorge Karpenkov   Printf("%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog);
9710ab2aceSGeorge Karpenkov 
9810ab2aceSGeorge Karpenkov   Printf("\nTo run individual tests without fuzzing pass 1 or more files:\n");
9910ab2aceSGeorge Karpenkov   Printf("%s [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n", Prog);
10010ab2aceSGeorge Karpenkov 
10110ab2aceSGeorge Karpenkov   Printf("\nFlags: (strictly in form -flag=value)\n");
10210ab2aceSGeorge Karpenkov   size_t MaxFlagLen = 0;
10310ab2aceSGeorge Karpenkov   for (size_t F = 0; F < kNumFlags; F++)
10410ab2aceSGeorge Karpenkov     MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen);
10510ab2aceSGeorge Karpenkov 
10610ab2aceSGeorge Karpenkov   for (size_t F = 0; F < kNumFlags; F++) {
10710ab2aceSGeorge Karpenkov     const auto &D = FlagDescriptions[F];
10810ab2aceSGeorge Karpenkov     if (strstr(D.Description, "internal flag") == D.Description) continue;
10910ab2aceSGeorge Karpenkov     Printf(" %s", D.Name);
11010ab2aceSGeorge Karpenkov     for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++)
11110ab2aceSGeorge Karpenkov       Printf(" ");
11210ab2aceSGeorge Karpenkov     Printf("\t");
11310ab2aceSGeorge Karpenkov     Printf("%d\t%s\n", D.Default, D.Description);
11410ab2aceSGeorge Karpenkov   }
11510ab2aceSGeorge Karpenkov   Printf("\nFlags starting with '--' will be ignored and "
11610ab2aceSGeorge Karpenkov             "will be passed verbatim to subprocesses.\n");
11710ab2aceSGeorge Karpenkov }
11810ab2aceSGeorge Karpenkov 
FlagValue(const char * Param,const char * Name)11910ab2aceSGeorge Karpenkov static const char *FlagValue(const char *Param, const char *Name) {
12010ab2aceSGeorge Karpenkov   size_t Len = strlen(Name);
12110ab2aceSGeorge Karpenkov   if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 &&
12210ab2aceSGeorge Karpenkov       Param[Len + 1] == '=')
12310ab2aceSGeorge Karpenkov       return &Param[Len + 2];
12410ab2aceSGeorge Karpenkov   return nullptr;
12510ab2aceSGeorge Karpenkov }
12610ab2aceSGeorge Karpenkov 
12710ab2aceSGeorge Karpenkov // Avoid calling stol as it triggers a bug in clang/glibc build.
MyStol(const char * Str)12810ab2aceSGeorge Karpenkov static long MyStol(const char *Str) {
12910ab2aceSGeorge Karpenkov   long Res = 0;
13010ab2aceSGeorge Karpenkov   long Sign = 1;
13110ab2aceSGeorge Karpenkov   if (*Str == '-') {
13210ab2aceSGeorge Karpenkov     Str++;
13310ab2aceSGeorge Karpenkov     Sign = -1;
13410ab2aceSGeorge Karpenkov   }
13510ab2aceSGeorge Karpenkov   for (size_t i = 0; Str[i]; i++) {
13610ab2aceSGeorge Karpenkov     char Ch = Str[i];
13710ab2aceSGeorge Karpenkov     if (Ch < '0' || Ch > '9')
13810ab2aceSGeorge Karpenkov       return Res;
13910ab2aceSGeorge Karpenkov     Res = Res * 10 + (Ch - '0');
14010ab2aceSGeorge Karpenkov   }
14110ab2aceSGeorge Karpenkov   return Res * Sign;
14210ab2aceSGeorge Karpenkov }
14310ab2aceSGeorge Karpenkov 
ParseOneFlag(const char * Param)14410ab2aceSGeorge Karpenkov static bool ParseOneFlag(const char *Param) {
14510ab2aceSGeorge Karpenkov   if (Param[0] != '-') return false;
14610ab2aceSGeorge Karpenkov   if (Param[1] == '-') {
14710ab2aceSGeorge Karpenkov     static bool PrintedWarning = false;
14810ab2aceSGeorge Karpenkov     if (!PrintedWarning) {
14910ab2aceSGeorge Karpenkov       PrintedWarning = true;
15010ab2aceSGeorge Karpenkov       Printf("INFO: libFuzzer ignores flags that start with '--'\n");
15110ab2aceSGeorge Karpenkov     }
15210ab2aceSGeorge Karpenkov     for (size_t F = 0; F < kNumFlags; F++)
15310ab2aceSGeorge Karpenkov       if (FlagValue(Param + 1, FlagDescriptions[F].Name))
15410ab2aceSGeorge Karpenkov         Printf("WARNING: did you mean '%s' (single dash)?\n", Param + 1);
15510ab2aceSGeorge Karpenkov     return true;
15610ab2aceSGeorge Karpenkov   }
15710ab2aceSGeorge Karpenkov   for (size_t F = 0; F < kNumFlags; F++) {
15810ab2aceSGeorge Karpenkov     const char *Name = FlagDescriptions[F].Name;
15910ab2aceSGeorge Karpenkov     const char *Str = FlagValue(Param, Name);
16010ab2aceSGeorge Karpenkov     if (Str)  {
16110ab2aceSGeorge Karpenkov       if (FlagDescriptions[F].IntFlag) {
1626708186cSAaron Green         auto Val = MyStol(Str);
1636708186cSAaron Green         *FlagDescriptions[F].IntFlag = static_cast<int>(Val);
16410ab2aceSGeorge Karpenkov         if (Flags.verbosity >= 2)
16510ab2aceSGeorge Karpenkov           Printf("Flag: %s %d\n", Name, Val);
16610ab2aceSGeorge Karpenkov         return true;
16710ab2aceSGeorge Karpenkov       } else if (FlagDescriptions[F].UIntFlag) {
1686708186cSAaron Green         auto Val = std::stoul(Str);
1696708186cSAaron Green         *FlagDescriptions[F].UIntFlag = static_cast<unsigned int>(Val);
17010ab2aceSGeorge Karpenkov         if (Flags.verbosity >= 2)
17110ab2aceSGeorge Karpenkov           Printf("Flag: %s %u\n", Name, Val);
17210ab2aceSGeorge Karpenkov         return true;
17310ab2aceSGeorge Karpenkov       } else if (FlagDescriptions[F].StrFlag) {
17410ab2aceSGeorge Karpenkov         *FlagDescriptions[F].StrFlag = Str;
17510ab2aceSGeorge Karpenkov         if (Flags.verbosity >= 2)
17610ab2aceSGeorge Karpenkov           Printf("Flag: %s %s\n", Name, Str);
17710ab2aceSGeorge Karpenkov         return true;
17810ab2aceSGeorge Karpenkov       } else {  // Deprecated flag.
17910ab2aceSGeorge Karpenkov         Printf("Flag: %s: deprecated, don't use\n", Name);
18010ab2aceSGeorge Karpenkov         return true;
18110ab2aceSGeorge Karpenkov       }
18210ab2aceSGeorge Karpenkov     }
18310ab2aceSGeorge Karpenkov   }
18410ab2aceSGeorge Karpenkov   Printf("\n\nWARNING: unrecognized flag '%s'; "
18510ab2aceSGeorge Karpenkov          "use -help=1 to list all flags\n\n", Param);
18610ab2aceSGeorge Karpenkov   return true;
18710ab2aceSGeorge Karpenkov }
18810ab2aceSGeorge Karpenkov 
18910ab2aceSGeorge Karpenkov // We don't use any library to minimize dependencies.
ParseFlags(const std::vector<std::string> & Args,const ExternalFunctions * EF)1907c921753SKostya Serebryany static void ParseFlags(const std::vector<std::string> &Args,
1910784e01aSMax Moroz                        const ExternalFunctions *EF) {
19210ab2aceSGeorge Karpenkov   for (size_t F = 0; F < kNumFlags; F++) {
19310ab2aceSGeorge Karpenkov     if (FlagDescriptions[F].IntFlag)
19410ab2aceSGeorge Karpenkov       *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default;
19510ab2aceSGeorge Karpenkov     if (FlagDescriptions[F].UIntFlag)
19610ab2aceSGeorge Karpenkov       *FlagDescriptions[F].UIntFlag =
19710ab2aceSGeorge Karpenkov           static_cast<unsigned int>(FlagDescriptions[F].Default);
19810ab2aceSGeorge Karpenkov     if (FlagDescriptions[F].StrFlag)
19910ab2aceSGeorge Karpenkov       *FlagDescriptions[F].StrFlag = nullptr;
20010ab2aceSGeorge Karpenkov   }
2010784e01aSMax Moroz 
2020784e01aSMax Moroz   // Disable len_control by default, if LLVMFuzzerCustomMutator is used.
20315f1d5d1SMax Moroz   if (EF->LLVMFuzzerCustomMutator) {
2040784e01aSMax Moroz     Flags.len_control = 0;
20515f1d5d1SMax Moroz     Printf("INFO: found LLVMFuzzerCustomMutator (%p). "
20615f1d5d1SMax Moroz            "Disabling -len_control by default.\n", EF->LLVMFuzzerCustomMutator);
20715f1d5d1SMax Moroz   }
2080784e01aSMax Moroz 
2097c921753SKostya Serebryany   Inputs = new std::vector<std::string>;
21010ab2aceSGeorge Karpenkov   for (size_t A = 1; A < Args.size(); A++) {
21110ab2aceSGeorge Karpenkov     if (ParseOneFlag(Args[A].c_str())) {
21210ab2aceSGeorge Karpenkov       if (Flags.ignore_remaining_args)
21310ab2aceSGeorge Karpenkov         break;
21410ab2aceSGeorge Karpenkov       continue;
21510ab2aceSGeorge Karpenkov     }
21610ab2aceSGeorge Karpenkov     Inputs->push_back(Args[A]);
21710ab2aceSGeorge Karpenkov   }
21810ab2aceSGeorge Karpenkov }
21910ab2aceSGeorge Karpenkov 
22010ab2aceSGeorge Karpenkov static std::mutex Mu;
22110ab2aceSGeorge Karpenkov 
PulseThread()22210ab2aceSGeorge Karpenkov static void PulseThread() {
22310ab2aceSGeorge Karpenkov   while (true) {
22410ab2aceSGeorge Karpenkov     SleepSeconds(600);
22510ab2aceSGeorge Karpenkov     std::lock_guard<std::mutex> Lock(Mu);
22610ab2aceSGeorge Karpenkov     Printf("pulse...\n");
22710ab2aceSGeorge Karpenkov   }
22810ab2aceSGeorge Karpenkov }
22910ab2aceSGeorge Karpenkov 
WorkerThread(const Command & BaseCmd,std::atomic<unsigned> * Counter,unsigned NumJobs,std::atomic<bool> * HasErrors)23004304d12SMatt Morehouse static void WorkerThread(const Command &BaseCmd, std::atomic<unsigned> *Counter,
23110ab2aceSGeorge Karpenkov                          unsigned NumJobs, std::atomic<bool> *HasErrors) {
23210ab2aceSGeorge Karpenkov   while (true) {
23310ab2aceSGeorge Karpenkov     unsigned C = (*Counter)++;
23410ab2aceSGeorge Karpenkov     if (C >= NumJobs) break;
23510ab2aceSGeorge Karpenkov     std::string Log = "fuzz-" + std::to_string(C) + ".log";
23604304d12SMatt Morehouse     Command Cmd(BaseCmd);
23704304d12SMatt Morehouse     Cmd.setOutputFile(Log);
23804304d12SMatt Morehouse     Cmd.combineOutAndErr();
23904304d12SMatt Morehouse     if (Flags.verbosity) {
24004304d12SMatt Morehouse       std::string CommandLine = Cmd.toString();
2417ac58ee3SKostya Serebryany       Printf("%s\n", CommandLine.c_str());
24204304d12SMatt Morehouse     }
24304304d12SMatt Morehouse     int ExitCode = ExecuteCommand(Cmd);
24410ab2aceSGeorge Karpenkov     if (ExitCode != 0)
24510ab2aceSGeorge Karpenkov       *HasErrors = true;
24610ab2aceSGeorge Karpenkov     std::lock_guard<std::mutex> Lock(Mu);
24710ab2aceSGeorge Karpenkov     Printf("================== Job %u exited with exit code %d ============\n",
24810ab2aceSGeorge Karpenkov            C, ExitCode);
24910ab2aceSGeorge Karpenkov     fuzzer::CopyFileToErr(Log);
25010ab2aceSGeorge Karpenkov   }
25110ab2aceSGeorge Karpenkov }
25210ab2aceSGeorge Karpenkov 
ValidateDirectoryExists(const std::string & Path,bool CreateDirectory)253711b9806SMatt Morehouse static void ValidateDirectoryExists(const std::string &Path,
254711b9806SMatt Morehouse                                     bool CreateDirectory) {
255711b9806SMatt Morehouse   if (Path.empty()) {
256711b9806SMatt Morehouse     Printf("ERROR: Provided directory path is an empty string\n");
257cb891279SMatt Morehouse     exit(1);
2582392ff09SMatt Morehouse   }
259711b9806SMatt Morehouse 
260711b9806SMatt Morehouse   if (IsDirectory(Path))
261711b9806SMatt Morehouse     return;
262711b9806SMatt Morehouse 
263711b9806SMatt Morehouse   if (CreateDirectory) {
264711b9806SMatt Morehouse     if (!MkDirRecursive(Path)) {
265711b9806SMatt Morehouse       Printf("ERROR: Failed to create directory \"%s\"\n", Path.c_str());
266711b9806SMatt Morehouse       exit(1);
267711b9806SMatt Morehouse     }
268711b9806SMatt Morehouse     return;
269711b9806SMatt Morehouse   }
270711b9806SMatt Morehouse 
271711b9806SMatt Morehouse   Printf("ERROR: The required directory \"%s\" does not exist\n", Path.c_str());
272711b9806SMatt Morehouse   exit(1);
27310670bdfSMatt Morehouse }
2742392ff09SMatt Morehouse 
CloneArgsWithoutX(const std::vector<std::string> & Args,const char * X1,const char * X2)2757c921753SKostya Serebryany std::string CloneArgsWithoutX(const std::vector<std::string> &Args,
27610ab2aceSGeorge Karpenkov                               const char *X1, const char *X2) {
27710ab2aceSGeorge Karpenkov   std::string Cmd;
27810ab2aceSGeorge Karpenkov   for (auto &S : Args) {
27910ab2aceSGeorge Karpenkov     if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2))
28010ab2aceSGeorge Karpenkov       continue;
28110ab2aceSGeorge Karpenkov     Cmd += S + " ";
28210ab2aceSGeorge Karpenkov   }
28310ab2aceSGeorge Karpenkov   return Cmd;
28410ab2aceSGeorge Karpenkov }
28510ab2aceSGeorge Karpenkov 
RunInMultipleProcesses(const std::vector<std::string> & Args,unsigned NumWorkers,unsigned NumJobs)2867c921753SKostya Serebryany static int RunInMultipleProcesses(const std::vector<std::string> &Args,
28710ab2aceSGeorge Karpenkov                                   unsigned NumWorkers, unsigned NumJobs) {
28810ab2aceSGeorge Karpenkov   std::atomic<unsigned> Counter(0);
28910ab2aceSGeorge Karpenkov   std::atomic<bool> HasErrors(false);
29004304d12SMatt Morehouse   Command Cmd(Args);
29104304d12SMatt Morehouse   Cmd.removeFlag("jobs");
29204304d12SMatt Morehouse   Cmd.removeFlag("workers");
2937c921753SKostya Serebryany   std::vector<std::thread> V;
29410ab2aceSGeorge Karpenkov   std::thread Pulse(PulseThread);
29510ab2aceSGeorge Karpenkov   Pulse.detach();
29610ab2aceSGeorge Karpenkov   for (unsigned i = 0; i < NumWorkers; i++)
2977c921753SKostya Serebryany     V.push_back(std::thread(WorkerThread, std::ref(Cmd), &Counter, NumJobs,
2987c921753SKostya Serebryany                             &HasErrors));
29910ab2aceSGeorge Karpenkov   for (auto &T : V)
30010ab2aceSGeorge Karpenkov     T.join();
30110ab2aceSGeorge Karpenkov   return HasErrors ? 1 : 0;
30210ab2aceSGeorge Karpenkov }
30310ab2aceSGeorge Karpenkov 
RssThread(Fuzzer * F,size_t RssLimitMb)30410ab2aceSGeorge Karpenkov static void RssThread(Fuzzer *F, size_t RssLimitMb) {
30510ab2aceSGeorge Karpenkov   while (true) {
30610ab2aceSGeorge Karpenkov     SleepSeconds(1);
30710ab2aceSGeorge Karpenkov     size_t Peak = GetPeakRSSMb();
30810ab2aceSGeorge Karpenkov     if (Peak > RssLimitMb)
30910ab2aceSGeorge Karpenkov       F->RssLimitCallback();
31010ab2aceSGeorge Karpenkov   }
31110ab2aceSGeorge Karpenkov }
31210ab2aceSGeorge Karpenkov 
StartRssThread(Fuzzer * F,size_t RssLimitMb)31310ab2aceSGeorge Karpenkov static void StartRssThread(Fuzzer *F, size_t RssLimitMb) {
31423bee0b0SJonathan Metzman   if (!RssLimitMb)
31523bee0b0SJonathan Metzman     return;
31610ab2aceSGeorge Karpenkov   std::thread T(RssThread, F, RssLimitMb);
31710ab2aceSGeorge Karpenkov   T.detach();
31810ab2aceSGeorge Karpenkov }
31910ab2aceSGeorge Karpenkov 
RunOneTest(Fuzzer * F,const char * InputFilePath,size_t MaxLen)32010ab2aceSGeorge Karpenkov int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) {
32110ab2aceSGeorge Karpenkov   Unit U = FileToVector(InputFilePath);
32210ab2aceSGeorge Karpenkov   if (MaxLen && MaxLen < U.size())
32310ab2aceSGeorge Karpenkov     U.resize(MaxLen);
32410ab2aceSGeorge Karpenkov   F->ExecuteCallback(U.data(), U.size());
325dc62d5ecSMax Moroz   if (Flags.print_full_coverage) {
326dc62d5ecSMax Moroz     // Leak detection is not needed when collecting full coverage data.
327dc62d5ecSMax Moroz     F->TPCUpdateObservedPCs();
328dc62d5ecSMax Moroz   } else {
32910ab2aceSGeorge Karpenkov     F->TryDetectingAMemoryLeak(U.data(), U.size(), true);
330dc62d5ecSMax Moroz   }
33110ab2aceSGeorge Karpenkov   return 0;
33210ab2aceSGeorge Karpenkov }
33310ab2aceSGeorge Karpenkov 
AllInputsAreFiles()33410ab2aceSGeorge Karpenkov static bool AllInputsAreFiles() {
33510ab2aceSGeorge Karpenkov   if (Inputs->empty()) return false;
33610ab2aceSGeorge Karpenkov   for (auto &Path : *Inputs)
33710ab2aceSGeorge Karpenkov     if (!IsFile(Path))
33810ab2aceSGeorge Karpenkov       return false;
33910ab2aceSGeorge Karpenkov   return true;
34010ab2aceSGeorge Karpenkov }
34110ab2aceSGeorge Karpenkov 
GetDedupTokenFromCmdOutput(const std::string & S)34285515c7fSYuanfang Chen static std::string GetDedupTokenFromCmdOutput(const std::string &S) {
34310ab2aceSGeorge Karpenkov   auto Beg = S.find("DEDUP_TOKEN:");
34410ab2aceSGeorge Karpenkov   if (Beg == std::string::npos)
34510ab2aceSGeorge Karpenkov     return "";
34610ab2aceSGeorge Karpenkov   auto End = S.find('\n', Beg);
34710ab2aceSGeorge Karpenkov   if (End == std::string::npos)
34810ab2aceSGeorge Karpenkov     return "";
34910ab2aceSGeorge Karpenkov   return S.substr(Beg, End - Beg);
35010ab2aceSGeorge Karpenkov }
35110ab2aceSGeorge Karpenkov 
CleanseCrashInput(const std::vector<std::string> & Args,const FuzzingOptions & Options)3527c921753SKostya Serebryany int CleanseCrashInput(const std::vector<std::string> &Args,
35310ab2aceSGeorge Karpenkov                       const FuzzingOptions &Options) {
35410ab2aceSGeorge Karpenkov   if (Inputs->size() != 1 || !Flags.exact_artifact_path) {
35510ab2aceSGeorge Karpenkov     Printf("ERROR: -cleanse_crash should be given one input file and"
35610ab2aceSGeorge Karpenkov           " -exact_artifact_path\n");
35710ab2aceSGeorge Karpenkov     exit(1);
35810ab2aceSGeorge Karpenkov   }
35910ab2aceSGeorge Karpenkov   std::string InputFilePath = Inputs->at(0);
36010ab2aceSGeorge Karpenkov   std::string OutputFilePath = Flags.exact_artifact_path;
36104304d12SMatt Morehouse   Command Cmd(Args);
36204304d12SMatt Morehouse   Cmd.removeFlag("cleanse_crash");
36310ab2aceSGeorge Karpenkov 
36404304d12SMatt Morehouse   assert(Cmd.hasArgument(InputFilePath));
36504304d12SMatt Morehouse   Cmd.removeArgument(InputFilePath);
36610ab2aceSGeorge Karpenkov 
3674f3c3bbbSYuanfang Chen   auto TmpFilePath = TempPath("CleanseCrashInput", ".repro");
36804304d12SMatt Morehouse   Cmd.addArgument(TmpFilePath);
36985515c7fSYuanfang Chen   Cmd.setOutputFile(getDevNull());
37004304d12SMatt Morehouse   Cmd.combineOutAndErr();
37110ab2aceSGeorge Karpenkov 
37210ab2aceSGeorge Karpenkov   std::string CurrentFilePath = InputFilePath;
37310ab2aceSGeorge Karpenkov   auto U = FileToVector(CurrentFilePath);
37410ab2aceSGeorge Karpenkov   size_t Size = U.size();
37510ab2aceSGeorge Karpenkov 
3767c921753SKostya Serebryany   const std::vector<uint8_t> ReplacementBytes = {' ', 0xff};
37710ab2aceSGeorge Karpenkov   for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) {
37810ab2aceSGeorge Karpenkov     bool Changed = false;
37910ab2aceSGeorge Karpenkov     for (size_t Idx = 0; Idx < Size; Idx++) {
38010ab2aceSGeorge Karpenkov       Printf("CLEANSE[%d]: Trying to replace byte %zd of %zd\n", NumAttempts,
38110ab2aceSGeorge Karpenkov              Idx, Size);
38210ab2aceSGeorge Karpenkov       uint8_t OriginalByte = U[Idx];
38310ab2aceSGeorge Karpenkov       if (ReplacementBytes.end() != std::find(ReplacementBytes.begin(),
38410ab2aceSGeorge Karpenkov                                               ReplacementBytes.end(),
38510ab2aceSGeorge Karpenkov                                               OriginalByte))
38610ab2aceSGeorge Karpenkov         continue;
38710ab2aceSGeorge Karpenkov       for (auto NewByte : ReplacementBytes) {
38810ab2aceSGeorge Karpenkov         U[Idx] = NewByte;
38910ab2aceSGeorge Karpenkov         WriteToFile(U, TmpFilePath);
39010ab2aceSGeorge Karpenkov         auto ExitCode = ExecuteCommand(Cmd);
39110ab2aceSGeorge Karpenkov         RemoveFile(TmpFilePath);
39210ab2aceSGeorge Karpenkov         if (!ExitCode) {
39310ab2aceSGeorge Karpenkov           U[Idx] = OriginalByte;
39410ab2aceSGeorge Karpenkov         } else {
39510ab2aceSGeorge Karpenkov           Changed = true;
39610ab2aceSGeorge Karpenkov           Printf("CLEANSE: Replaced byte %zd with 0x%x\n", Idx, NewByte);
39710ab2aceSGeorge Karpenkov           WriteToFile(U, OutputFilePath);
39810ab2aceSGeorge Karpenkov           break;
39910ab2aceSGeorge Karpenkov         }
40010ab2aceSGeorge Karpenkov       }
40110ab2aceSGeorge Karpenkov     }
40210ab2aceSGeorge Karpenkov     if (!Changed) break;
40310ab2aceSGeorge Karpenkov   }
40410ab2aceSGeorge Karpenkov   return 0;
40510ab2aceSGeorge Karpenkov }
40610ab2aceSGeorge Karpenkov 
MinimizeCrashInput(const std::vector<std::string> & Args,const FuzzingOptions & Options)4077c921753SKostya Serebryany int MinimizeCrashInput(const std::vector<std::string> &Args,
40810ab2aceSGeorge Karpenkov                        const FuzzingOptions &Options) {
40910ab2aceSGeorge Karpenkov   if (Inputs->size() != 1) {
41010ab2aceSGeorge Karpenkov     Printf("ERROR: -minimize_crash should be given one input file\n");
41110ab2aceSGeorge Karpenkov     exit(1);
41210ab2aceSGeorge Karpenkov   }
41310ab2aceSGeorge Karpenkov   std::string InputFilePath = Inputs->at(0);
41404304d12SMatt Morehouse   Command BaseCmd(Args);
41504304d12SMatt Morehouse   BaseCmd.removeFlag("minimize_crash");
41604304d12SMatt Morehouse   BaseCmd.removeFlag("exact_artifact_path");
41704304d12SMatt Morehouse   assert(BaseCmd.hasArgument(InputFilePath));
41804304d12SMatt Morehouse   BaseCmd.removeArgument(InputFilePath);
41910ab2aceSGeorge Karpenkov   if (Flags.runs <= 0 && Flags.max_total_time == 0) {
42010ab2aceSGeorge Karpenkov     Printf("INFO: you need to specify -runs=N or "
42110ab2aceSGeorge Karpenkov            "-max_total_time=N with -minimize_crash=1\n"
42210ab2aceSGeorge Karpenkov            "INFO: defaulting to -max_total_time=600\n");
42304304d12SMatt Morehouse     BaseCmd.addFlag("max_total_time", "600");
42410ab2aceSGeorge Karpenkov   }
42510ab2aceSGeorge Karpenkov 
42604304d12SMatt Morehouse   BaseCmd.combineOutAndErr();
42710ab2aceSGeorge Karpenkov 
42810ab2aceSGeorge Karpenkov   std::string CurrentFilePath = InputFilePath;
42910ab2aceSGeorge Karpenkov   while (true) {
43010ab2aceSGeorge Karpenkov     Unit U = FileToVector(CurrentFilePath);
43110ab2aceSGeorge Karpenkov     Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n",
43210ab2aceSGeorge Karpenkov            CurrentFilePath.c_str(), U.size());
43310ab2aceSGeorge Karpenkov 
43404304d12SMatt Morehouse     Command Cmd(BaseCmd);
43504304d12SMatt Morehouse     Cmd.addArgument(CurrentFilePath);
43610ab2aceSGeorge Karpenkov 
43785515c7fSYuanfang Chen     Printf("CRASH_MIN: executing: %s\n", Cmd.toString().c_str());
43885515c7fSYuanfang Chen     std::string CmdOutput;
4394caeb62eSYuanfang Chen     bool Success = ExecuteCommand(Cmd, &CmdOutput);
44085515c7fSYuanfang Chen     if (Success) {
44110ab2aceSGeorge Karpenkov       Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str());
44210ab2aceSGeorge Karpenkov       exit(1);
44310ab2aceSGeorge Karpenkov     }
44410ab2aceSGeorge Karpenkov     Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize "
44510ab2aceSGeorge Karpenkov            "it further\n",
44610ab2aceSGeorge Karpenkov            CurrentFilePath.c_str(), U.size());
44785515c7fSYuanfang Chen     auto DedupToken1 = GetDedupTokenFromCmdOutput(CmdOutput);
44810ab2aceSGeorge Karpenkov     if (!DedupToken1.empty())
44910ab2aceSGeorge Karpenkov       Printf("CRASH_MIN: DedupToken1: %s\n", DedupToken1.c_str());
45010ab2aceSGeorge Karpenkov 
45110ab2aceSGeorge Karpenkov     std::string ArtifactPath =
45210ab2aceSGeorge Karpenkov         Flags.exact_artifact_path
45310ab2aceSGeorge Karpenkov             ? Flags.exact_artifact_path
45410ab2aceSGeorge Karpenkov             : Options.ArtifactPrefix + "minimized-from-" + Hash(U);
45504304d12SMatt Morehouse     Cmd.addFlag("minimize_crash_internal_step", "1");
45604304d12SMatt Morehouse     Cmd.addFlag("exact_artifact_path", ArtifactPath);
45785515c7fSYuanfang Chen     Printf("CRASH_MIN: executing: %s\n", Cmd.toString().c_str());
45885515c7fSYuanfang Chen     CmdOutput.clear();
4594caeb62eSYuanfang Chen     Success = ExecuteCommand(Cmd, &CmdOutput);
46085515c7fSYuanfang Chen     Printf("%s", CmdOutput.c_str());
46185515c7fSYuanfang Chen     if (Success) {
46210ab2aceSGeorge Karpenkov       if (Flags.exact_artifact_path) {
46310ab2aceSGeorge Karpenkov         CurrentFilePath = Flags.exact_artifact_path;
46410ab2aceSGeorge Karpenkov         WriteToFile(U, CurrentFilePath);
46510ab2aceSGeorge Karpenkov       }
46610ab2aceSGeorge Karpenkov       Printf("CRASH_MIN: failed to minimize beyond %s (%d bytes), exiting\n",
46710ab2aceSGeorge Karpenkov              CurrentFilePath.c_str(), U.size());
46810ab2aceSGeorge Karpenkov       break;
46910ab2aceSGeorge Karpenkov     }
47085515c7fSYuanfang Chen     auto DedupToken2 = GetDedupTokenFromCmdOutput(CmdOutput);
47110ab2aceSGeorge Karpenkov     if (!DedupToken2.empty())
47210ab2aceSGeorge Karpenkov       Printf("CRASH_MIN: DedupToken2: %s\n", DedupToken2.c_str());
47310ab2aceSGeorge Karpenkov 
47410ab2aceSGeorge Karpenkov     if (DedupToken1 != DedupToken2) {
47510ab2aceSGeorge Karpenkov       if (Flags.exact_artifact_path) {
47610ab2aceSGeorge Karpenkov         CurrentFilePath = Flags.exact_artifact_path;
47710ab2aceSGeorge Karpenkov         WriteToFile(U, CurrentFilePath);
47810ab2aceSGeorge Karpenkov       }
47910ab2aceSGeorge Karpenkov       Printf("CRASH_MIN: mismatch in dedup tokens"
48010ab2aceSGeorge Karpenkov              " (looks like a different bug). Won't minimize further\n");
48110ab2aceSGeorge Karpenkov       break;
48210ab2aceSGeorge Karpenkov     }
48310ab2aceSGeorge Karpenkov 
48410ab2aceSGeorge Karpenkov     CurrentFilePath = ArtifactPath;
48510ab2aceSGeorge Karpenkov     Printf("*********************************\n");
48610ab2aceSGeorge Karpenkov   }
48710ab2aceSGeorge Karpenkov   return 0;
48810ab2aceSGeorge Karpenkov }
48910ab2aceSGeorge Karpenkov 
MinimizeCrashInputInternalStep(Fuzzer * F,InputCorpus * Corpus)49010ab2aceSGeorge Karpenkov int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) {
49110ab2aceSGeorge Karpenkov   assert(Inputs->size() == 1);
49210ab2aceSGeorge Karpenkov   std::string InputFilePath = Inputs->at(0);
49310ab2aceSGeorge Karpenkov   Unit U = FileToVector(InputFilePath);
49410ab2aceSGeorge Karpenkov   Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size());
49510ab2aceSGeorge Karpenkov   if (U.size() < 2) {
49610ab2aceSGeorge Karpenkov     Printf("INFO: The input is small enough, exiting\n");
49710ab2aceSGeorge Karpenkov     exit(0);
49810ab2aceSGeorge Karpenkov   }
49910ab2aceSGeorge Karpenkov   F->SetMaxInputLen(U.size());
50010ab2aceSGeorge Karpenkov   F->SetMaxMutationLen(U.size() - 1);
50110ab2aceSGeorge Karpenkov   F->MinimizeCrashLoop(U);
50210ab2aceSGeorge Karpenkov   Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n");
50310ab2aceSGeorge Karpenkov   exit(0);
50410ab2aceSGeorge Karpenkov   return 0;
50510ab2aceSGeorge Karpenkov }
50610ab2aceSGeorge Karpenkov 
Merge(Fuzzer * F,FuzzingOptions & Options,const std::vector<std::string> & Args,const std::vector<std::string> & Corpora,const char * CFPathOrNull)5077c921753SKostya Serebryany void Merge(Fuzzer *F, FuzzingOptions &Options,
5087c921753SKostya Serebryany            const std::vector<std::string> &Args,
5097c921753SKostya Serebryany            const std::vector<std::string> &Corpora, const char *CFPathOrNull) {
510114cfafeSKostya Serebryany   if (Corpora.size() < 2) {
511114cfafeSKostya Serebryany     Printf("INFO: Merge requires two or more corpus dirs\n");
512114cfafeSKostya Serebryany     exit(0);
513114cfafeSKostya Serebryany   }
514114cfafeSKostya Serebryany 
5157c921753SKostya Serebryany   std::vector<SizedFile> OldCorpus, NewCorpus;
516114cfafeSKostya Serebryany   GetSizedFilesFromDir(Corpora[0], &OldCorpus);
517114cfafeSKostya Serebryany   for (size_t i = 1; i < Corpora.size(); i++)
518114cfafeSKostya Serebryany     GetSizedFilesFromDir(Corpora[i], &NewCorpus);
519114cfafeSKostya Serebryany   std::sort(OldCorpus.begin(), OldCorpus.end());
520114cfafeSKostya Serebryany   std::sort(NewCorpus.begin(), NewCorpus.end());
521114cfafeSKostya Serebryany 
5224f3c3bbbSYuanfang Chen   std::string CFPath = CFPathOrNull ? CFPathOrNull : TempPath("Merge", ".txt");
5237c921753SKostya Serebryany   std::vector<std::string> NewFiles;
5247c921753SKostya Serebryany   std::set<uint32_t> NewFeatures, NewCov;
5250fda9dcbSKostya Serebryany   CrashResistantMerge(Args, OldCorpus, NewCorpus, &NewFiles, {}, &NewFeatures,
526e6597dbaSaristotelis                       {}, &NewCov, CFPath, true, Flags.set_cover_merge);
5270fda9dcbSKostya Serebryany   for (auto &Path : NewFiles)
528114cfafeSKostya Serebryany     F->WriteToOutputCorpus(FileToVector(Path, Options.MaxLen));
529114cfafeSKostya Serebryany   // We are done, delete the control file if it was a temporary one.
530114cfafeSKostya Serebryany   if (!Flags.merge_control_file)
531114cfafeSKostya Serebryany     RemoveFile(CFPath);
532114cfafeSKostya Serebryany 
533114cfafeSKostya Serebryany   exit(0);
534114cfafeSKostya Serebryany }
535114cfafeSKostya Serebryany 
AnalyzeDictionary(Fuzzer * F,const std::vector<Unit> & Dict,UnitVector & Corpus)5367c921753SKostya Serebryany int AnalyzeDictionary(Fuzzer *F, const std::vector<Unit> &Dict,
53710ab2aceSGeorge Karpenkov                       UnitVector &Corpus) {
53810ab2aceSGeorge Karpenkov   Printf("Started dictionary minimization (up to %d tests)\n",
53910ab2aceSGeorge Karpenkov          Dict.size() * Corpus.size() * 2);
54010ab2aceSGeorge Karpenkov 
54110ab2aceSGeorge Karpenkov   // Scores and usage count for each dictionary unit.
5427c921753SKostya Serebryany   std::vector<int> Scores(Dict.size());
5437c921753SKostya Serebryany   std::vector<int> Usages(Dict.size());
54410ab2aceSGeorge Karpenkov 
5457c921753SKostya Serebryany   std::vector<size_t> InitialFeatures;
5467c921753SKostya Serebryany   std::vector<size_t> ModifiedFeatures;
54710ab2aceSGeorge Karpenkov   for (auto &C : Corpus) {
54810ab2aceSGeorge Karpenkov     // Get coverage for the testcase without modifications.
54910ab2aceSGeorge Karpenkov     F->ExecuteCallback(C.data(), C.size());
55010ab2aceSGeorge Karpenkov     InitialFeatures.clear();
551bcd78491SKostya Serebryany     TPC.CollectFeatures([&](size_t Feature) {
55210ab2aceSGeorge Karpenkov       InitialFeatures.push_back(Feature);
55310ab2aceSGeorge Karpenkov     });
55410ab2aceSGeorge Karpenkov 
55510ab2aceSGeorge Karpenkov     for (size_t i = 0; i < Dict.size(); ++i) {
5567c921753SKostya Serebryany       std::vector<uint8_t> Data = C;
55710ab2aceSGeorge Karpenkov       auto StartPos = std::search(Data.begin(), Data.end(),
55810ab2aceSGeorge Karpenkov                                   Dict[i].begin(), Dict[i].end());
55910ab2aceSGeorge Karpenkov       // Skip dictionary unit, if the testcase does not contain it.
56010ab2aceSGeorge Karpenkov       if (StartPos == Data.end())
56110ab2aceSGeorge Karpenkov         continue;
56210ab2aceSGeorge Karpenkov 
56310ab2aceSGeorge Karpenkov       ++Usages[i];
56410ab2aceSGeorge Karpenkov       while (StartPos != Data.end()) {
56510ab2aceSGeorge Karpenkov         // Replace all occurrences of dictionary unit in the testcase.
56610ab2aceSGeorge Karpenkov         auto EndPos = StartPos + Dict[i].size();
56710ab2aceSGeorge Karpenkov         for (auto It = StartPos; It != EndPos; ++It)
56810ab2aceSGeorge Karpenkov           *It ^= 0xFF;
56910ab2aceSGeorge Karpenkov 
57010ab2aceSGeorge Karpenkov         StartPos = std::search(EndPos, Data.end(),
57110ab2aceSGeorge Karpenkov                                Dict[i].begin(), Dict[i].end());
57210ab2aceSGeorge Karpenkov       }
57310ab2aceSGeorge Karpenkov 
57410ab2aceSGeorge Karpenkov       // Get coverage for testcase with masked occurrences of dictionary unit.
57510ab2aceSGeorge Karpenkov       F->ExecuteCallback(Data.data(), Data.size());
57610ab2aceSGeorge Karpenkov       ModifiedFeatures.clear();
577bcd78491SKostya Serebryany       TPC.CollectFeatures([&](size_t Feature) {
57810ab2aceSGeorge Karpenkov         ModifiedFeatures.push_back(Feature);
57910ab2aceSGeorge Karpenkov       });
58010ab2aceSGeorge Karpenkov 
58110ab2aceSGeorge Karpenkov       if (InitialFeatures == ModifiedFeatures)
58210ab2aceSGeorge Karpenkov         --Scores[i];
58310ab2aceSGeorge Karpenkov       else
58410ab2aceSGeorge Karpenkov         Scores[i] += 2;
58510ab2aceSGeorge Karpenkov     }
58610ab2aceSGeorge Karpenkov   }
58710ab2aceSGeorge Karpenkov 
58810ab2aceSGeorge Karpenkov   Printf("###### Useless dictionary elements. ######\n");
58910ab2aceSGeorge Karpenkov   for (size_t i = 0; i < Dict.size(); ++i) {
59010ab2aceSGeorge Karpenkov     // Dictionary units with positive score are treated as useful ones.
59110ab2aceSGeorge Karpenkov     if (Scores[i] > 0)
59210ab2aceSGeorge Karpenkov        continue;
59310ab2aceSGeorge Karpenkov 
59410ab2aceSGeorge Karpenkov     Printf("\"");
59510ab2aceSGeorge Karpenkov     PrintASCII(Dict[i].data(), Dict[i].size(), "\"");
59610ab2aceSGeorge Karpenkov     Printf(" # Score: %d, Used: %d\n", Scores[i], Usages[i]);
59710ab2aceSGeorge Karpenkov   }
59810ab2aceSGeorge Karpenkov   Printf("###### End of useless dictionary elements. ######\n");
59910ab2aceSGeorge Karpenkov   return 0;
60010ab2aceSGeorge Karpenkov }
60110ab2aceSGeorge Karpenkov 
ParseSeedInuts(const char * seed_inputs)6027c921753SKostya Serebryany std::vector<std::string> ParseSeedInuts(const char *seed_inputs) {
603da96d921SKostya Serebryany   // Parse -seed_inputs=file1,file2,... or -seed_inputs=@seed_inputs_file
6047c921753SKostya Serebryany   std::vector<std::string> Files;
605da96d921SKostya Serebryany   if (!seed_inputs) return Files;
606da96d921SKostya Serebryany   std::string SeedInputs;
607da96d921SKostya Serebryany   if (Flags.seed_inputs[0] == '@')
608da96d921SKostya Serebryany     SeedInputs = FileToString(Flags.seed_inputs + 1); // File contains list.
609da96d921SKostya Serebryany   else
610da96d921SKostya Serebryany     SeedInputs = Flags.seed_inputs; // seed_inputs contains the list.
611da96d921SKostya Serebryany   if (SeedInputs.empty()) {
612da96d921SKostya Serebryany     Printf("seed_inputs is empty or @file does not exist.\n");
613da96d921SKostya Serebryany     exit(1);
614da96d921SKostya Serebryany   }
615da96d921SKostya Serebryany   // Parse SeedInputs.
616da96d921SKostya Serebryany   size_t comma_pos = 0;
617da96d921SKostya Serebryany   while ((comma_pos = SeedInputs.find_last_of(',')) != std::string::npos) {
618da96d921SKostya Serebryany     Files.push_back(SeedInputs.substr(comma_pos + 1));
619da96d921SKostya Serebryany     SeedInputs = SeedInputs.substr(0, comma_pos);
620da96d921SKostya Serebryany   }
621da96d921SKostya Serebryany   Files.push_back(SeedInputs);
622da96d921SKostya Serebryany   return Files;
623da96d921SKostya Serebryany }
624da96d921SKostya Serebryany 
6257c921753SKostya Serebryany static std::vector<SizedFile>
ReadCorpora(const std::vector<std::string> & CorpusDirs,const std::vector<std::string> & ExtraSeedFiles)6267c921753SKostya Serebryany ReadCorpora(const std::vector<std::string> &CorpusDirs,
6277c921753SKostya Serebryany             const std::vector<std::string> &ExtraSeedFiles) {
6287c921753SKostya Serebryany   std::vector<SizedFile> SizedFiles;
6294c7353c5SKostya Serebryany   size_t LastNumFiles = 0;
6304c7353c5SKostya Serebryany   for (auto &Dir : CorpusDirs) {
6314c7353c5SKostya Serebryany     GetSizedFilesFromDir(Dir, &SizedFiles);
6324c7353c5SKostya Serebryany     Printf("INFO: % 8zd files found in %s\n", SizedFiles.size() - LastNumFiles,
6334c7353c5SKostya Serebryany            Dir.c_str());
6344c7353c5SKostya Serebryany     LastNumFiles = SizedFiles.size();
6354c7353c5SKostya Serebryany   }
6364c7353c5SKostya Serebryany   for (auto &File : ExtraSeedFiles)
6374c7353c5SKostya Serebryany     if (auto Size = FileSize(File))
6384c7353c5SKostya Serebryany       SizedFiles.push_back({File, Size});
6394c7353c5SKostya Serebryany   return SizedFiles;
6404c7353c5SKostya Serebryany }
6414c7353c5SKostya Serebryany 
FuzzerDriver(int * argc,char *** argv,UserCallback Callback)64210ab2aceSGeorge Karpenkov int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
64310ab2aceSGeorge Karpenkov   using namespace fuzzer;
64410ab2aceSGeorge Karpenkov   assert(argc && argv && "Argument pointers cannot be nullptr");
64510ab2aceSGeorge Karpenkov   std::string Argv0((*argv)[0]);
64610ab2aceSGeorge Karpenkov   EF = new ExternalFunctions();
64710ab2aceSGeorge Karpenkov   if (EF->LLVMFuzzerInitialize)
64810ab2aceSGeorge Karpenkov     EF->LLVMFuzzerInitialize(argc, argv);
649a34c65e8SMatt Morehouse   if (EF->__msan_scoped_disable_interceptor_checks)
650a34c65e8SMatt Morehouse     EF->__msan_scoped_disable_interceptor_checks();
6517c921753SKostya Serebryany   const std::vector<std::string> Args(*argv, *argv + *argc);
65210ab2aceSGeorge Karpenkov   assert(!Args.empty());
65310ab2aceSGeorge Karpenkov   ProgName = new std::string(Args[0]);
65410ab2aceSGeorge Karpenkov   if (Argv0 != *ProgName) {
65510ab2aceSGeorge Karpenkov     Printf("ERROR: argv[0] has been modified in LLVMFuzzerInitialize\n");
65610ab2aceSGeorge Karpenkov     exit(1);
65710ab2aceSGeorge Karpenkov   }
6580784e01aSMax Moroz   ParseFlags(Args, EF);
65910ab2aceSGeorge Karpenkov   if (Flags.help) {
66010ab2aceSGeorge Karpenkov     PrintHelp();
66110ab2aceSGeorge Karpenkov     return 0;
66210ab2aceSGeorge Karpenkov   }
66310ab2aceSGeorge Karpenkov 
66410ab2aceSGeorge Karpenkov   if (Flags.close_fd_mask & 2)
66510ab2aceSGeorge Karpenkov     DupAndCloseStderr();
66610ab2aceSGeorge Karpenkov   if (Flags.close_fd_mask & 1)
66710ab2aceSGeorge Karpenkov     CloseStdout();
66810ab2aceSGeorge Karpenkov 
66910ab2aceSGeorge Karpenkov   if (Flags.jobs > 0 && Flags.workers == 0) {
67010ab2aceSGeorge Karpenkov     Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs);
67110ab2aceSGeorge Karpenkov     if (Flags.workers > 1)
67210ab2aceSGeorge Karpenkov       Printf("Running %u workers\n", Flags.workers);
67310ab2aceSGeorge Karpenkov   }
67410ab2aceSGeorge Karpenkov 
67510ab2aceSGeorge Karpenkov   if (Flags.workers > 0 && Flags.jobs > 0)
67610ab2aceSGeorge Karpenkov     return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs);
67710ab2aceSGeorge Karpenkov 
67810ab2aceSGeorge Karpenkov   FuzzingOptions Options;
67910ab2aceSGeorge Karpenkov   Options.Verbosity = Flags.verbosity;
68010ab2aceSGeorge Karpenkov   Options.MaxLen = Flags.max_len;
68136c89b3cSMatt Morehouse   Options.LenControl = Flags.len_control;
68262673c43SDokyung Song   Options.KeepSeed = Flags.keep_seed;
68310ab2aceSGeorge Karpenkov   Options.UnitTimeoutSec = Flags.timeout;
68410ab2aceSGeorge Karpenkov   Options.ErrorExitCode = Flags.error_exitcode;
68510ab2aceSGeorge Karpenkov   Options.TimeoutExitCode = Flags.timeout_exitcode;
686cdbb9dc9SKostya Serebryany   Options.IgnoreTimeouts = Flags.ignore_timeouts;
687cdbb9dc9SKostya Serebryany   Options.IgnoreOOMs = Flags.ignore_ooms;
6889982ee54SKostya Serebryany   Options.IgnoreCrashes = Flags.ignore_crashes;
68910ab2aceSGeorge Karpenkov   Options.MaxTotalTimeSec = Flags.max_total_time;
69010ab2aceSGeorge Karpenkov   Options.DoCrossOver = Flags.cross_over;
691b53243e1SDokyung Song   Options.CrossOverUniformDist = Flags.cross_over_uniform_dist;
69210ab2aceSGeorge Karpenkov   Options.MutateDepth = Flags.mutate_depth;
693ad05ee05SKostya Serebryany   Options.ReduceDepth = Flags.reduce_depth;
69410ab2aceSGeorge Karpenkov   Options.UseCounters = Flags.use_counters;
69510ab2aceSGeorge Karpenkov   Options.UseMemmem = Flags.use_memmem;
69610ab2aceSGeorge Karpenkov   Options.UseCmp = Flags.use_cmp;
69710ab2aceSGeorge Karpenkov   Options.UseValueProfile = Flags.use_value_profile;
69810ab2aceSGeorge Karpenkov   Options.Shrink = Flags.shrink;
69910ab2aceSGeorge Karpenkov   Options.ReduceInputs = Flags.reduce_inputs;
70010ab2aceSGeorge Karpenkov   Options.ShuffleAtStartUp = Flags.shuffle;
70110ab2aceSGeorge Karpenkov   Options.PreferSmall = Flags.prefer_small;
70210ab2aceSGeorge Karpenkov   Options.ReloadIntervalSec = Flags.reload;
70310ab2aceSGeorge Karpenkov   Options.OnlyASCII = Flags.only_ascii;
70410ab2aceSGeorge Karpenkov   Options.DetectLeaks = Flags.detect_leaks;
7056f1c26f2SAlex Shlyapnikov   Options.PurgeAllocatorIntervalSec = Flags.purge_allocator_interval;
70610ab2aceSGeorge Karpenkov   Options.TraceMalloc = Flags.trace_malloc;
70710ab2aceSGeorge Karpenkov   Options.RssLimitMb = Flags.rss_limit_mb;
708de9bafb1SKostya Serebryany   Options.MallocLimitMb = Flags.malloc_limit_mb;
709de9bafb1SKostya Serebryany   if (!Options.MallocLimitMb)
710de9bafb1SKostya Serebryany     Options.MallocLimitMb = Options.RssLimitMb;
71110ab2aceSGeorge Karpenkov   if (Flags.runs >= 0)
71210ab2aceSGeorge Karpenkov     Options.MaxNumberOfRuns = Flags.runs;
7132392ff09SMatt Morehouse   if (!Inputs->empty() && !Flags.minimize_crash_internal_step) {
7142392ff09SMatt Morehouse     // Ensure output corpus assumed to be the first arbitrary argument input
7152392ff09SMatt Morehouse     // is not a path to an existing file.
7162392ff09SMatt Morehouse     std::string OutputCorpusDir = (*Inputs)[0];
7172392ff09SMatt Morehouse     if (!IsFile(OutputCorpusDir)) {
7182392ff09SMatt Morehouse       Options.OutputCorpus = OutputCorpusDir;
719711b9806SMatt Morehouse       ValidateDirectoryExists(Options.OutputCorpus, Flags.create_missing_dirs);
7202392ff09SMatt Morehouse     }
7212392ff09SMatt Morehouse   }
72210ab2aceSGeorge Karpenkov   Options.ReportSlowUnits = Flags.report_slow_units;
7232392ff09SMatt Morehouse   if (Flags.artifact_prefix) {
72410ab2aceSGeorge Karpenkov     Options.ArtifactPrefix = Flags.artifact_prefix;
7252392ff09SMatt Morehouse 
7262392ff09SMatt Morehouse     // Since the prefix could be a full path to a file name prefix, assume
7272392ff09SMatt Morehouse     // that if the path ends with the platform's separator that a directory
7282392ff09SMatt Morehouse     // is desired
7292392ff09SMatt Morehouse     std::string ArtifactPathDir = Options.ArtifactPrefix;
7302392ff09SMatt Morehouse     if (!IsSeparator(ArtifactPathDir[ArtifactPathDir.length() - 1])) {
7312392ff09SMatt Morehouse       ArtifactPathDir = DirName(ArtifactPathDir);
7322392ff09SMatt Morehouse     }
733711b9806SMatt Morehouse     ValidateDirectoryExists(ArtifactPathDir, Flags.create_missing_dirs);
7342392ff09SMatt Morehouse   }
7352392ff09SMatt Morehouse   if (Flags.exact_artifact_path) {
73610ab2aceSGeorge Karpenkov     Options.ExactArtifactPath = Flags.exact_artifact_path;
737711b9806SMatt Morehouse     ValidateDirectoryExists(DirName(Options.ExactArtifactPath),
738711b9806SMatt Morehouse                             Flags.create_missing_dirs);
7392392ff09SMatt Morehouse   }
7407c921753SKostya Serebryany   std::vector<Unit> Dictionary;
74110ab2aceSGeorge Karpenkov   if (Flags.dict)
74210ab2aceSGeorge Karpenkov     if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary))
74310ab2aceSGeorge Karpenkov       return 1;
74410ab2aceSGeorge Karpenkov   if (Flags.verbosity > 0 && !Dictionary.empty())
74510ab2aceSGeorge Karpenkov     Printf("Dictionary: %zd entries\n", Dictionary.size());
7464c7353c5SKostya Serebryany   bool RunIndividualFiles = AllInputsAreFiles();
74710ab2aceSGeorge Karpenkov   Options.SaveArtifacts =
7484c7353c5SKostya Serebryany       !RunIndividualFiles || Flags.minimize_crash_internal_step;
74910ab2aceSGeorge Karpenkov   Options.PrintNewCovPcs = Flags.print_pcs;
7502eef816eSKostya Serebryany   Options.PrintNewCovFuncs = Flags.print_funcs;
75110ab2aceSGeorge Karpenkov   Options.PrintFinalStats = Flags.print_final_stats;
75210ab2aceSGeorge Karpenkov   Options.PrintCorpusStats = Flags.print_corpus_stats;
75310ab2aceSGeorge Karpenkov   Options.PrintCoverage = Flags.print_coverage;
754dc62d5ecSMax Moroz   Options.PrintFullCoverage = Flags.print_full_coverage;
75510ab2aceSGeorge Karpenkov   if (Flags.exit_on_src_pos)
75610ab2aceSGeorge Karpenkov     Options.ExitOnSrcPos = Flags.exit_on_src_pos;
75710ab2aceSGeorge Karpenkov   if (Flags.exit_on_item)
75810ab2aceSGeorge Karpenkov     Options.ExitOnItem = Flags.exit_on_item;
759e9c6f06cSKostya Serebryany   if (Flags.focus_function)
760e9c6f06cSKostya Serebryany     Options.FocusFunction = Flags.focus_function;
7611fd005f5SKostya Serebryany   if (Flags.data_flow_trace)
7621fd005f5SKostya Serebryany     Options.DataFlowTrace = Flags.data_flow_trace;
7632392ff09SMatt Morehouse   if (Flags.features_dir) {
7644614cc3dSKostya Serebryany     Options.FeaturesDir = Flags.features_dir;
765711b9806SMatt Morehouse     ValidateDirectoryExists(Options.FeaturesDir, Flags.create_missing_dirs);
7662392ff09SMatt Morehouse   }
7671bb1eac6SDokyung Song   if (Flags.mutation_graph_file)
7681bb1eac6SDokyung Song     Options.MutationGraphFile = Flags.mutation_graph_file;
769b7cc3d99SKostya Serebryany   if (Flags.collect_data_flow)
770b7cc3d99SKostya Serebryany     Options.CollectDataFlow = Flags.collect_data_flow;
771db88fc56SKostya Serebryany   if (Flags.stop_file)
772db88fc56SKostya Serebryany     Options.StopFile = Flags.stop_file;
773e2e38fcaSMatt Morehouse   Options.Entropic = Flags.entropic;
774e2e38fcaSMatt Morehouse   Options.EntropicFeatureFrequencyThreshold =
775e2e38fcaSMatt Morehouse       (size_t)Flags.entropic_feature_frequency_threshold;
776e2e38fcaSMatt Morehouse   Options.EntropicNumberOfRarestFeatures =
777e2e38fcaSMatt Morehouse       (size_t)Flags.entropic_number_of_rarest_features;
7785cda4dc7SDokyung Song   Options.EntropicScalePerExecTime = Flags.entropic_scale_per_exec_time;
779f3c2e0bcSMatt Morehouse   if (!Options.FocusFunction.empty())
780f3c2e0bcSMatt Morehouse     Options.Entropic = false; // FocusFunction overrides entropic scheduling.
781f3c2e0bcSMatt Morehouse   if (Options.Entropic)
782e2e38fcaSMatt Morehouse     Printf("INFO: Running with entropic power schedule (0x%X, %d).\n",
783e2e38fcaSMatt Morehouse            Options.EntropicFeatureFrequencyThreshold,
784e2e38fcaSMatt Morehouse            Options.EntropicNumberOfRarestFeatures);
785e2e38fcaSMatt Morehouse   struct EntropicOptions Entropic;
786e2e38fcaSMatt Morehouse   Entropic.Enabled = Options.Entropic;
787e2e38fcaSMatt Morehouse   Entropic.FeatureFrequencyThreshold =
788e2e38fcaSMatt Morehouse       Options.EntropicFeatureFrequencyThreshold;
789e2e38fcaSMatt Morehouse   Entropic.NumberOfRarestFeatures = Options.EntropicNumberOfRarestFeatures;
7905cda4dc7SDokyung Song   Entropic.ScalePerExecTime = Options.EntropicScalePerExecTime;
79110ab2aceSGeorge Karpenkov 
79210ab2aceSGeorge Karpenkov   unsigned Seed = Flags.seed;
79310ab2aceSGeorge Karpenkov   // Initialize Seed.
79410ab2aceSGeorge Karpenkov   if (Seed == 0)
7956708186cSAaron Green     Seed = static_cast<unsigned>(
7966708186cSAaron Green         std::chrono::system_clock::now().time_since_epoch().count() + GetPid());
79710ab2aceSGeorge Karpenkov   if (Flags.verbosity)
79810ab2aceSGeorge Karpenkov     Printf("INFO: Seed: %u\n", Seed);
79910ab2aceSGeorge Karpenkov 
800e6597dbaSaristotelis   if (Flags.collect_data_flow && !Flags.fork &&
801e6597dbaSaristotelis       !(Flags.merge || Flags.set_cover_merge)) {
8024c7353c5SKostya Serebryany     if (RunIndividualFiles)
803da96d921SKostya Serebryany       return CollectDataFlow(Flags.collect_data_flow, Flags.data_flow_trace,
8044c7353c5SKostya Serebryany                         ReadCorpora({}, *Inputs));
8054c7353c5SKostya Serebryany     else
8064c7353c5SKostya Serebryany       return CollectDataFlow(Flags.collect_data_flow, Flags.data_flow_trace,
8074c7353c5SKostya Serebryany                         ReadCorpora(*Inputs, {}));
8084c7353c5SKostya Serebryany   }
809da96d921SKostya Serebryany 
810c5d72517SMarco Vanotti   Random Rand(Seed);
811c5d72517SMarco Vanotti   auto *MD = new MutationDispatcher(Rand, Options);
812e2e38fcaSMatt Morehouse   auto *Corpus = new InputCorpus(Options.OutputCorpus, Entropic);
81310ab2aceSGeorge Karpenkov   auto *F = new Fuzzer(Callback, *Corpus, *MD, Options);
81410ab2aceSGeorge Karpenkov 
81510ab2aceSGeorge Karpenkov   for (auto &U: Dictionary)
81610ab2aceSGeorge Karpenkov     if (U.size() <= Word::GetMaxSize())
81710ab2aceSGeorge Karpenkov       MD->AddWordToManualDictionary(Word(U.data(), U.size()));
81810ab2aceSGeorge Karpenkov 
81923bee0b0SJonathan Metzman       // Threads are only supported by Chrome. Don't use them with emscripten
82023bee0b0SJonathan Metzman       // for now.
82123bee0b0SJonathan Metzman #if !LIBFUZZER_EMSCRIPTEN
82210ab2aceSGeorge Karpenkov   StartRssThread(F, Flags.rss_limit_mb);
82323bee0b0SJonathan Metzman #endif // LIBFUZZER_EMSCRIPTEN
82410ab2aceSGeorge Karpenkov 
82510ab2aceSGeorge Karpenkov   Options.HandleAbrt = Flags.handle_abrt;
8269df7ee34SIlya Leoshkevich   Options.HandleAlrm = !Flags.minimize_crash;
82710ab2aceSGeorge Karpenkov   Options.HandleBus = Flags.handle_bus;
82810ab2aceSGeorge Karpenkov   Options.HandleFpe = Flags.handle_fpe;
82910ab2aceSGeorge Karpenkov   Options.HandleIll = Flags.handle_ill;
83010ab2aceSGeorge Karpenkov   Options.HandleInt = Flags.handle_int;
83110ab2aceSGeorge Karpenkov   Options.HandleSegv = Flags.handle_segv;
83210ab2aceSGeorge Karpenkov   Options.HandleTerm = Flags.handle_term;
83310ab2aceSGeorge Karpenkov   Options.HandleXfsz = Flags.handle_xfsz;
834a2ca2dccSKostya Serebryany   Options.HandleUsr1 = Flags.handle_usr1;
835a2ca2dccSKostya Serebryany   Options.HandleUsr2 = Flags.handle_usr2;
836f897e82bSJoe Pletcher   Options.HandleWinExcept = Flags.handle_winexcept;
837f897e82bSJoe Pletcher 
83810ab2aceSGeorge Karpenkov   SetSignalHandler(Options);
83910ab2aceSGeorge Karpenkov 
84010ab2aceSGeorge Karpenkov   std::atexit(Fuzzer::StaticExitCallback);
84110ab2aceSGeorge Karpenkov 
84210ab2aceSGeorge Karpenkov   if (Flags.minimize_crash)
84310ab2aceSGeorge Karpenkov     return MinimizeCrashInput(Args, Options);
84410ab2aceSGeorge Karpenkov 
84510ab2aceSGeorge Karpenkov   if (Flags.minimize_crash_internal_step)
84610ab2aceSGeorge Karpenkov     return MinimizeCrashInputInternalStep(F, Corpus);
84710ab2aceSGeorge Karpenkov 
84810ab2aceSGeorge Karpenkov   if (Flags.cleanse_crash)
84910ab2aceSGeorge Karpenkov     return CleanseCrashInput(Args, Options);
85010ab2aceSGeorge Karpenkov 
8514c7353c5SKostya Serebryany   if (RunIndividualFiles) {
85210ab2aceSGeorge Karpenkov     Options.SaveArtifacts = false;
85310ab2aceSGeorge Karpenkov     int Runs = std::max(1, Flags.runs);
85410ab2aceSGeorge Karpenkov     Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName->c_str(),
85510ab2aceSGeorge Karpenkov            Inputs->size(), Runs);
85610ab2aceSGeorge Karpenkov     for (auto &Path : *Inputs) {
85710ab2aceSGeorge Karpenkov       auto StartTime = system_clock::now();
85810ab2aceSGeorge Karpenkov       Printf("Running: %s\n", Path.c_str());
85910ab2aceSGeorge Karpenkov       for (int Iter = 0; Iter < Runs; Iter++)
86010ab2aceSGeorge Karpenkov         RunOneTest(F, Path.c_str(), Options.MaxLen);
86110ab2aceSGeorge Karpenkov       auto StopTime = system_clock::now();
86210ab2aceSGeorge Karpenkov       auto MS = duration_cast<milliseconds>(StopTime - StartTime).count();
86310ab2aceSGeorge Karpenkov       Printf("Executed %s in %zd ms\n", Path.c_str(), (long)MS);
86410ab2aceSGeorge Karpenkov     }
86510ab2aceSGeorge Karpenkov     Printf("***\n"
86610ab2aceSGeorge Karpenkov            "*** NOTE: fuzzing was not performed, you have only\n"
86710ab2aceSGeorge Karpenkov            "***       executed the target code on a fixed set of inputs.\n"
86810ab2aceSGeorge Karpenkov            "***\n");
86910ab2aceSGeorge Karpenkov     F->PrintFinalStats();
87010ab2aceSGeorge Karpenkov     exit(0);
87110ab2aceSGeorge Karpenkov   }
87210ab2aceSGeorge Karpenkov 
873*a30dbbe9Sgtt1995   Options.ForkCorpusGroups = Flags.fork_corpus_groups;
874f762a115SKostya Serebryany   if (Flags.fork)
87560c5ded2SKostya Serebryany     FuzzWithFork(F->GetMD().GetRand(), Options, Args, *Inputs, Flags.fork);
876f762a115SKostya Serebryany 
877e6597dbaSaristotelis   if (Flags.merge || Flags.set_cover_merge)
878114cfafeSKostya Serebryany     Merge(F, Options, Args, *Inputs, Flags.merge_control_file);
87910ab2aceSGeorge Karpenkov 
88068fdef1fSKostya Serebryany   if (Flags.merge_inner) {
88168fdef1fSKostya Serebryany     const size_t kDefaultMaxMergeLen = 1 << 20;
88268fdef1fSKostya Serebryany     if (Options.MaxLen == 0)
88368fdef1fSKostya Serebryany       F->SetMaxInputLen(kDefaultMaxMergeLen);
88468fdef1fSKostya Serebryany     assert(Flags.merge_control_file);
885e6597dbaSaristotelis     F->CrashResistantMergeInternalStep(Flags.merge_control_file,
886e6597dbaSaristotelis                                        !strncmp(Flags.merge_inner, "2", 1));
88768fdef1fSKostya Serebryany     exit(0);
88868fdef1fSKostya Serebryany   }
88910ab2aceSGeorge Karpenkov 
8903a8e3c83SKostya Serebryany   if (Flags.analyze_dict) {
8913a8e3c83SKostya Serebryany     size_t MaxLen = INT_MAX;  // Large max length.
89210ab2aceSGeorge Karpenkov     UnitVector InitialCorpus;
89310ab2aceSGeorge Karpenkov     for (auto &Inp : *Inputs) {
89410ab2aceSGeorge Karpenkov       Printf("Loading corpus dir: %s\n", Inp.c_str());
89510ab2aceSGeorge Karpenkov       ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr,
8963a8e3c83SKostya Serebryany                              MaxLen, /*ExitOnError=*/false);
89710ab2aceSGeorge Karpenkov     }
89810ab2aceSGeorge Karpenkov 
89910ab2aceSGeorge Karpenkov     if (Dictionary.empty() || Inputs->empty()) {
90010ab2aceSGeorge Karpenkov       Printf("ERROR: can't analyze dict without dict and corpus provided\n");
90110ab2aceSGeorge Karpenkov       return 1;
90210ab2aceSGeorge Karpenkov     }
90310ab2aceSGeorge Karpenkov     if (AnalyzeDictionary(F, Dictionary, InitialCorpus)) {
90410ab2aceSGeorge Karpenkov       Printf("Dictionary analysis failed\n");
90510ab2aceSGeorge Karpenkov       exit(1);
90610ab2aceSGeorge Karpenkov     }
907d9a8b6a7SSylvestre Ledru     Printf("Dictionary analysis succeeded\n");
90810ab2aceSGeorge Karpenkov     exit(0);
90910ab2aceSGeorge Karpenkov   }
91010ab2aceSGeorge Karpenkov 
9114c7353c5SKostya Serebryany   auto CorporaFiles = ReadCorpora(*Inputs, ParseSeedInuts(Flags.seed_inputs));
9124c7353c5SKostya Serebryany   F->Loop(CorporaFiles);
91310ab2aceSGeorge Karpenkov 
91410ab2aceSGeorge Karpenkov   if (Flags.verbosity)
91510ab2aceSGeorge Karpenkov     Printf("Done %zd runs in %zd second(s)\n", F->getTotalNumberOfRuns(),
91610ab2aceSGeorge Karpenkov            F->secondsSinceProcessStartUp());
91710ab2aceSGeorge Karpenkov   F->PrintFinalStats();
91810ab2aceSGeorge Karpenkov 
91910ab2aceSGeorge Karpenkov   exit(0);  // Don't let F destroy itself.
92010ab2aceSGeorge Karpenkov }
92110ab2aceSGeorge Karpenkov 
92234ddf0b2SMatt Morehouse extern "C" ATTRIBUTE_INTERFACE int
LLVMFuzzerRunDriver(int * argc,char *** argv,int (* UserCb)(const uint8_t * Data,size_t Size))92334ddf0b2SMatt Morehouse LLVMFuzzerRunDriver(int *argc, char ***argv,
92434ddf0b2SMatt Morehouse                     int (*UserCb)(const uint8_t *Data, size_t Size)) {
92534ddf0b2SMatt Morehouse   return FuzzerDriver(argc, argv, UserCb);
92634ddf0b2SMatt Morehouse }
92734ddf0b2SMatt Morehouse 
92810ab2aceSGeorge Karpenkov // Storage for global ExternalFunctions object.
92910ab2aceSGeorge Karpenkov ExternalFunctions *EF = nullptr;
93010ab2aceSGeorge Karpenkov 
93110ab2aceSGeorge Karpenkov }  // namespace fuzzer
932