xref: /llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp (revision d9ce33a0eea701719651dafbf88deae0ece96976)
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) {
232*d9ce33a0SThurston Dang   ScopedDisableMsanInterceptorChecks S;
23310ab2aceSGeorge Karpenkov   while (true) {
23410ab2aceSGeorge Karpenkov     unsigned C = (*Counter)++;
23510ab2aceSGeorge Karpenkov     if (C >= NumJobs) break;
23610ab2aceSGeorge Karpenkov     std::string Log = "fuzz-" + std::to_string(C) + ".log";
23704304d12SMatt Morehouse     Command Cmd(BaseCmd);
23804304d12SMatt Morehouse     Cmd.setOutputFile(Log);
23904304d12SMatt Morehouse     Cmd.combineOutAndErr();
24004304d12SMatt Morehouse     if (Flags.verbosity) {
24104304d12SMatt Morehouse       std::string CommandLine = Cmd.toString();
2427ac58ee3SKostya Serebryany       Printf("%s\n", CommandLine.c_str());
24304304d12SMatt Morehouse     }
24404304d12SMatt Morehouse     int ExitCode = ExecuteCommand(Cmd);
24510ab2aceSGeorge Karpenkov     if (ExitCode != 0)
24610ab2aceSGeorge Karpenkov       *HasErrors = true;
24710ab2aceSGeorge Karpenkov     std::lock_guard<std::mutex> Lock(Mu);
24810ab2aceSGeorge Karpenkov     Printf("================== Job %u exited with exit code %d ============\n",
24910ab2aceSGeorge Karpenkov            C, ExitCode);
25010ab2aceSGeorge Karpenkov     fuzzer::CopyFileToErr(Log);
25110ab2aceSGeorge Karpenkov   }
25210ab2aceSGeorge Karpenkov }
25310ab2aceSGeorge Karpenkov 
ValidateDirectoryExists(const std::string & Path,bool CreateDirectory)254711b9806SMatt Morehouse static void ValidateDirectoryExists(const std::string &Path,
255711b9806SMatt Morehouse                                     bool CreateDirectory) {
256711b9806SMatt Morehouse   if (Path.empty()) {
257711b9806SMatt Morehouse     Printf("ERROR: Provided directory path is an empty string\n");
258cb891279SMatt Morehouse     exit(1);
2592392ff09SMatt Morehouse   }
260711b9806SMatt Morehouse 
261711b9806SMatt Morehouse   if (IsDirectory(Path))
262711b9806SMatt Morehouse     return;
263711b9806SMatt Morehouse 
264711b9806SMatt Morehouse   if (CreateDirectory) {
265711b9806SMatt Morehouse     if (!MkDirRecursive(Path)) {
266711b9806SMatt Morehouse       Printf("ERROR: Failed to create directory \"%s\"\n", Path.c_str());
267711b9806SMatt Morehouse       exit(1);
268711b9806SMatt Morehouse     }
269711b9806SMatt Morehouse     return;
270711b9806SMatt Morehouse   }
271711b9806SMatt Morehouse 
272711b9806SMatt Morehouse   Printf("ERROR: The required directory \"%s\" does not exist\n", Path.c_str());
273711b9806SMatt Morehouse   exit(1);
27410670bdfSMatt Morehouse }
2752392ff09SMatt Morehouse 
CloneArgsWithoutX(const std::vector<std::string> & Args,const char * X1,const char * X2)2767c921753SKostya Serebryany std::string CloneArgsWithoutX(const std::vector<std::string> &Args,
27710ab2aceSGeorge Karpenkov                               const char *X1, const char *X2) {
27810ab2aceSGeorge Karpenkov   std::string Cmd;
27910ab2aceSGeorge Karpenkov   for (auto &S : Args) {
28010ab2aceSGeorge Karpenkov     if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2))
28110ab2aceSGeorge Karpenkov       continue;
28210ab2aceSGeorge Karpenkov     Cmd += S + " ";
28310ab2aceSGeorge Karpenkov   }
28410ab2aceSGeorge Karpenkov   return Cmd;
28510ab2aceSGeorge Karpenkov }
28610ab2aceSGeorge Karpenkov 
RunInMultipleProcesses(const std::vector<std::string> & Args,unsigned NumWorkers,unsigned NumJobs)2877c921753SKostya Serebryany static int RunInMultipleProcesses(const std::vector<std::string> &Args,
28810ab2aceSGeorge Karpenkov                                   unsigned NumWorkers, unsigned NumJobs) {
28910ab2aceSGeorge Karpenkov   std::atomic<unsigned> Counter(0);
29010ab2aceSGeorge Karpenkov   std::atomic<bool> HasErrors(false);
29104304d12SMatt Morehouse   Command Cmd(Args);
29204304d12SMatt Morehouse   Cmd.removeFlag("jobs");
29304304d12SMatt Morehouse   Cmd.removeFlag("workers");
2947c921753SKostya Serebryany   std::vector<std::thread> V;
29510ab2aceSGeorge Karpenkov   std::thread Pulse(PulseThread);
29610ab2aceSGeorge Karpenkov   Pulse.detach();
297b2a25385SDavid CARLIER   V.resize(NumWorkers);
298b2a25385SDavid CARLIER   for (unsigned i = 0; i < NumWorkers; i++) {
299b2a25385SDavid CARLIER     V[i] = std::thread(WorkerThread, std::ref(Cmd), &Counter, NumJobs,
300b2a25385SDavid CARLIER                             &HasErrors);
301b2a25385SDavid CARLIER     SetThreadName(V[i], "FuzzerWorker");
302b2a25385SDavid CARLIER   }
30310ab2aceSGeorge Karpenkov   for (auto &T : V)
30410ab2aceSGeorge Karpenkov     T.join();
30510ab2aceSGeorge Karpenkov   return HasErrors ? 1 : 0;
30610ab2aceSGeorge Karpenkov }
30710ab2aceSGeorge Karpenkov 
RssThread(Fuzzer * F,size_t RssLimitMb)30810ab2aceSGeorge Karpenkov static void RssThread(Fuzzer *F, size_t RssLimitMb) {
30910ab2aceSGeorge Karpenkov   while (true) {
31010ab2aceSGeorge Karpenkov     SleepSeconds(1);
31110ab2aceSGeorge Karpenkov     size_t Peak = GetPeakRSSMb();
31210ab2aceSGeorge Karpenkov     if (Peak > RssLimitMb)
31310ab2aceSGeorge Karpenkov       F->RssLimitCallback();
31410ab2aceSGeorge Karpenkov   }
31510ab2aceSGeorge Karpenkov }
31610ab2aceSGeorge Karpenkov 
StartRssThread(Fuzzer * F,size_t RssLimitMb)31710ab2aceSGeorge Karpenkov static void StartRssThread(Fuzzer *F, size_t RssLimitMb) {
31823bee0b0SJonathan Metzman   if (!RssLimitMb)
31923bee0b0SJonathan Metzman     return;
32010ab2aceSGeorge Karpenkov   std::thread T(RssThread, F, RssLimitMb);
32110ab2aceSGeorge Karpenkov   T.detach();
32210ab2aceSGeorge Karpenkov }
32310ab2aceSGeorge Karpenkov 
RunOneTest(Fuzzer * F,const char * InputFilePath,size_t MaxLen)32410ab2aceSGeorge Karpenkov int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) {
32510ab2aceSGeorge Karpenkov   Unit U = FileToVector(InputFilePath);
32610ab2aceSGeorge Karpenkov   if (MaxLen && MaxLen < U.size())
32710ab2aceSGeorge Karpenkov     U.resize(MaxLen);
32810ab2aceSGeorge Karpenkov   F->ExecuteCallback(U.data(), U.size());
329dc62d5ecSMax Moroz   if (Flags.print_full_coverage) {
330dc62d5ecSMax Moroz     // Leak detection is not needed when collecting full coverage data.
331dc62d5ecSMax Moroz     F->TPCUpdateObservedPCs();
332dc62d5ecSMax Moroz   } else {
33310ab2aceSGeorge Karpenkov     F->TryDetectingAMemoryLeak(U.data(), U.size(), true);
334dc62d5ecSMax Moroz   }
33510ab2aceSGeorge Karpenkov   return 0;
33610ab2aceSGeorge Karpenkov }
33710ab2aceSGeorge Karpenkov 
AllInputsAreFiles()33810ab2aceSGeorge Karpenkov static bool AllInputsAreFiles() {
33910ab2aceSGeorge Karpenkov   if (Inputs->empty()) return false;
34010ab2aceSGeorge Karpenkov   for (auto &Path : *Inputs)
34110ab2aceSGeorge Karpenkov     if (!IsFile(Path))
34210ab2aceSGeorge Karpenkov       return false;
34310ab2aceSGeorge Karpenkov   return true;
34410ab2aceSGeorge Karpenkov }
34510ab2aceSGeorge Karpenkov 
GetDedupTokenFromCmdOutput(const std::string & S)34685515c7fSYuanfang Chen static std::string GetDedupTokenFromCmdOutput(const std::string &S) {
34710ab2aceSGeorge Karpenkov   auto Beg = S.find("DEDUP_TOKEN:");
34810ab2aceSGeorge Karpenkov   if (Beg == std::string::npos)
34910ab2aceSGeorge Karpenkov     return "";
35010ab2aceSGeorge Karpenkov   auto End = S.find('\n', Beg);
35110ab2aceSGeorge Karpenkov   if (End == std::string::npos)
35210ab2aceSGeorge Karpenkov     return "";
35310ab2aceSGeorge Karpenkov   return S.substr(Beg, End - Beg);
35410ab2aceSGeorge Karpenkov }
35510ab2aceSGeorge Karpenkov 
CleanseCrashInput(const std::vector<std::string> & Args,const FuzzingOptions & Options)3567c921753SKostya Serebryany int CleanseCrashInput(const std::vector<std::string> &Args,
35710ab2aceSGeorge Karpenkov                       const FuzzingOptions &Options) {
35810ab2aceSGeorge Karpenkov   if (Inputs->size() != 1 || !Flags.exact_artifact_path) {
35910ab2aceSGeorge Karpenkov     Printf("ERROR: -cleanse_crash should be given one input file and"
36010ab2aceSGeorge Karpenkov           " -exact_artifact_path\n");
36110ab2aceSGeorge Karpenkov     exit(1);
36210ab2aceSGeorge Karpenkov   }
36310ab2aceSGeorge Karpenkov   std::string InputFilePath = Inputs->at(0);
36410ab2aceSGeorge Karpenkov   std::string OutputFilePath = Flags.exact_artifact_path;
36504304d12SMatt Morehouse   Command Cmd(Args);
36604304d12SMatt Morehouse   Cmd.removeFlag("cleanse_crash");
36710ab2aceSGeorge Karpenkov 
36804304d12SMatt Morehouse   assert(Cmd.hasArgument(InputFilePath));
36904304d12SMatt Morehouse   Cmd.removeArgument(InputFilePath);
37010ab2aceSGeorge Karpenkov 
3714f3c3bbbSYuanfang Chen   auto TmpFilePath = TempPath("CleanseCrashInput", ".repro");
37204304d12SMatt Morehouse   Cmd.addArgument(TmpFilePath);
37385515c7fSYuanfang Chen   Cmd.setOutputFile(getDevNull());
37404304d12SMatt Morehouse   Cmd.combineOutAndErr();
37510ab2aceSGeorge Karpenkov 
37610ab2aceSGeorge Karpenkov   std::string CurrentFilePath = InputFilePath;
37710ab2aceSGeorge Karpenkov   auto U = FileToVector(CurrentFilePath);
37810ab2aceSGeorge Karpenkov   size_t Size = U.size();
37910ab2aceSGeorge Karpenkov 
3807c921753SKostya Serebryany   const std::vector<uint8_t> ReplacementBytes = {' ', 0xff};
38110ab2aceSGeorge Karpenkov   for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) {
38210ab2aceSGeorge Karpenkov     bool Changed = false;
38310ab2aceSGeorge Karpenkov     for (size_t Idx = 0; Idx < Size; Idx++) {
38410ab2aceSGeorge Karpenkov       Printf("CLEANSE[%d]: Trying to replace byte %zd of %zd\n", NumAttempts,
38510ab2aceSGeorge Karpenkov              Idx, Size);
38610ab2aceSGeorge Karpenkov       uint8_t OriginalByte = U[Idx];
38710ab2aceSGeorge Karpenkov       if (ReplacementBytes.end() != std::find(ReplacementBytes.begin(),
38810ab2aceSGeorge Karpenkov                                               ReplacementBytes.end(),
38910ab2aceSGeorge Karpenkov                                               OriginalByte))
39010ab2aceSGeorge Karpenkov         continue;
39110ab2aceSGeorge Karpenkov       for (auto NewByte : ReplacementBytes) {
39210ab2aceSGeorge Karpenkov         U[Idx] = NewByte;
39310ab2aceSGeorge Karpenkov         WriteToFile(U, TmpFilePath);
39410ab2aceSGeorge Karpenkov         auto ExitCode = ExecuteCommand(Cmd);
39510ab2aceSGeorge Karpenkov         RemoveFile(TmpFilePath);
39610ab2aceSGeorge Karpenkov         if (!ExitCode) {
39710ab2aceSGeorge Karpenkov           U[Idx] = OriginalByte;
39810ab2aceSGeorge Karpenkov         } else {
39910ab2aceSGeorge Karpenkov           Changed = true;
40010ab2aceSGeorge Karpenkov           Printf("CLEANSE: Replaced byte %zd with 0x%x\n", Idx, NewByte);
40110ab2aceSGeorge Karpenkov           WriteToFile(U, OutputFilePath);
40210ab2aceSGeorge Karpenkov           break;
40310ab2aceSGeorge Karpenkov         }
40410ab2aceSGeorge Karpenkov       }
40510ab2aceSGeorge Karpenkov     }
40610ab2aceSGeorge Karpenkov     if (!Changed) break;
40710ab2aceSGeorge Karpenkov   }
40810ab2aceSGeorge Karpenkov   return 0;
40910ab2aceSGeorge Karpenkov }
41010ab2aceSGeorge Karpenkov 
MinimizeCrashInput(const std::vector<std::string> & Args,const FuzzingOptions & Options)4117c921753SKostya Serebryany int MinimizeCrashInput(const std::vector<std::string> &Args,
41210ab2aceSGeorge Karpenkov                        const FuzzingOptions &Options) {
41310ab2aceSGeorge Karpenkov   if (Inputs->size() != 1) {
41410ab2aceSGeorge Karpenkov     Printf("ERROR: -minimize_crash should be given one input file\n");
41510ab2aceSGeorge Karpenkov     exit(1);
41610ab2aceSGeorge Karpenkov   }
41710ab2aceSGeorge Karpenkov   std::string InputFilePath = Inputs->at(0);
41804304d12SMatt Morehouse   Command BaseCmd(Args);
41904304d12SMatt Morehouse   BaseCmd.removeFlag("minimize_crash");
42004304d12SMatt Morehouse   BaseCmd.removeFlag("exact_artifact_path");
42104304d12SMatt Morehouse   assert(BaseCmd.hasArgument(InputFilePath));
42204304d12SMatt Morehouse   BaseCmd.removeArgument(InputFilePath);
42310ab2aceSGeorge Karpenkov   if (Flags.runs <= 0 && Flags.max_total_time == 0) {
42410ab2aceSGeorge Karpenkov     Printf("INFO: you need to specify -runs=N or "
42510ab2aceSGeorge Karpenkov            "-max_total_time=N with -minimize_crash=1\n"
42610ab2aceSGeorge Karpenkov            "INFO: defaulting to -max_total_time=600\n");
42704304d12SMatt Morehouse     BaseCmd.addFlag("max_total_time", "600");
42810ab2aceSGeorge Karpenkov   }
42910ab2aceSGeorge Karpenkov 
43004304d12SMatt Morehouse   BaseCmd.combineOutAndErr();
43110ab2aceSGeorge Karpenkov 
43210ab2aceSGeorge Karpenkov   std::string CurrentFilePath = InputFilePath;
43310ab2aceSGeorge Karpenkov   while (true) {
43410ab2aceSGeorge Karpenkov     Unit U = FileToVector(CurrentFilePath);
43510ab2aceSGeorge Karpenkov     Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n",
43610ab2aceSGeorge Karpenkov            CurrentFilePath.c_str(), U.size());
43710ab2aceSGeorge Karpenkov 
43804304d12SMatt Morehouse     Command Cmd(BaseCmd);
43904304d12SMatt Morehouse     Cmd.addArgument(CurrentFilePath);
44010ab2aceSGeorge Karpenkov 
44185515c7fSYuanfang Chen     Printf("CRASH_MIN: executing: %s\n", Cmd.toString().c_str());
44285515c7fSYuanfang Chen     std::string CmdOutput;
4434caeb62eSYuanfang Chen     bool Success = ExecuteCommand(Cmd, &CmdOutput);
44485515c7fSYuanfang Chen     if (Success) {
44510ab2aceSGeorge Karpenkov       Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str());
44610ab2aceSGeorge Karpenkov       exit(1);
44710ab2aceSGeorge Karpenkov     }
44810ab2aceSGeorge Karpenkov     Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize "
44910ab2aceSGeorge Karpenkov            "it further\n",
45010ab2aceSGeorge Karpenkov            CurrentFilePath.c_str(), U.size());
45185515c7fSYuanfang Chen     auto DedupToken1 = GetDedupTokenFromCmdOutput(CmdOutput);
45210ab2aceSGeorge Karpenkov     if (!DedupToken1.empty())
45310ab2aceSGeorge Karpenkov       Printf("CRASH_MIN: DedupToken1: %s\n", DedupToken1.c_str());
45410ab2aceSGeorge Karpenkov 
45510ab2aceSGeorge Karpenkov     std::string ArtifactPath =
45610ab2aceSGeorge Karpenkov         Flags.exact_artifact_path
45710ab2aceSGeorge Karpenkov             ? Flags.exact_artifact_path
45810ab2aceSGeorge Karpenkov             : Options.ArtifactPrefix + "minimized-from-" + Hash(U);
45904304d12SMatt Morehouse     Cmd.addFlag("minimize_crash_internal_step", "1");
46004304d12SMatt Morehouse     Cmd.addFlag("exact_artifact_path", ArtifactPath);
46185515c7fSYuanfang Chen     Printf("CRASH_MIN: executing: %s\n", Cmd.toString().c_str());
46285515c7fSYuanfang Chen     CmdOutput.clear();
4634caeb62eSYuanfang Chen     Success = ExecuteCommand(Cmd, &CmdOutput);
46485515c7fSYuanfang Chen     Printf("%s", CmdOutput.c_str());
46585515c7fSYuanfang Chen     if (Success) {
46610ab2aceSGeorge Karpenkov       if (Flags.exact_artifact_path) {
46710ab2aceSGeorge Karpenkov         CurrentFilePath = Flags.exact_artifact_path;
46810ab2aceSGeorge Karpenkov         WriteToFile(U, CurrentFilePath);
46910ab2aceSGeorge Karpenkov       }
47091985c2eSWu, Yingcong       Printf("CRASH_MIN: failed to minimize beyond %s (%zu bytes), exiting\n",
47110ab2aceSGeorge Karpenkov              CurrentFilePath.c_str(), U.size());
47210ab2aceSGeorge Karpenkov       break;
47310ab2aceSGeorge Karpenkov     }
47485515c7fSYuanfang Chen     auto DedupToken2 = GetDedupTokenFromCmdOutput(CmdOutput);
47510ab2aceSGeorge Karpenkov     if (!DedupToken2.empty())
47610ab2aceSGeorge Karpenkov       Printf("CRASH_MIN: DedupToken2: %s\n", DedupToken2.c_str());
47710ab2aceSGeorge Karpenkov 
47810ab2aceSGeorge Karpenkov     if (DedupToken1 != DedupToken2) {
47910ab2aceSGeorge Karpenkov       if (Flags.exact_artifact_path) {
48010ab2aceSGeorge Karpenkov         CurrentFilePath = Flags.exact_artifact_path;
48110ab2aceSGeorge Karpenkov         WriteToFile(U, CurrentFilePath);
48210ab2aceSGeorge Karpenkov       }
48310ab2aceSGeorge Karpenkov       Printf("CRASH_MIN: mismatch in dedup tokens"
48410ab2aceSGeorge Karpenkov              " (looks like a different bug). Won't minimize further\n");
48510ab2aceSGeorge Karpenkov       break;
48610ab2aceSGeorge Karpenkov     }
48710ab2aceSGeorge Karpenkov 
48810ab2aceSGeorge Karpenkov     CurrentFilePath = ArtifactPath;
48910ab2aceSGeorge Karpenkov     Printf("*********************************\n");
49010ab2aceSGeorge Karpenkov   }
49110ab2aceSGeorge Karpenkov   return 0;
49210ab2aceSGeorge Karpenkov }
49310ab2aceSGeorge Karpenkov 
MinimizeCrashInputInternalStep(Fuzzer * F,InputCorpus * Corpus)49410ab2aceSGeorge Karpenkov int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) {
49510ab2aceSGeorge Karpenkov   assert(Inputs->size() == 1);
49610ab2aceSGeorge Karpenkov   std::string InputFilePath = Inputs->at(0);
49710ab2aceSGeorge Karpenkov   Unit U = FileToVector(InputFilePath);
49810ab2aceSGeorge Karpenkov   Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size());
49910ab2aceSGeorge Karpenkov   if (U.size() < 2) {
50010ab2aceSGeorge Karpenkov     Printf("INFO: The input is small enough, exiting\n");
50110ab2aceSGeorge Karpenkov     exit(0);
50210ab2aceSGeorge Karpenkov   }
50310ab2aceSGeorge Karpenkov   F->SetMaxInputLen(U.size());
50410ab2aceSGeorge Karpenkov   F->SetMaxMutationLen(U.size() - 1);
50510ab2aceSGeorge Karpenkov   F->MinimizeCrashLoop(U);
50610ab2aceSGeorge Karpenkov   Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n");
50710ab2aceSGeorge Karpenkov   exit(0);
50810ab2aceSGeorge Karpenkov }
50910ab2aceSGeorge Karpenkov 
Merge(Fuzzer * F,FuzzingOptions & Options,const std::vector<std::string> & Args,const std::vector<std::string> & Corpora,const char * CFPathOrNull)5107c921753SKostya Serebryany void Merge(Fuzzer *F, FuzzingOptions &Options,
5117c921753SKostya Serebryany            const std::vector<std::string> &Args,
5127c921753SKostya Serebryany            const std::vector<std::string> &Corpora, const char *CFPathOrNull) {
513114cfafeSKostya Serebryany   if (Corpora.size() < 2) {
514114cfafeSKostya Serebryany     Printf("INFO: Merge requires two or more corpus dirs\n");
515114cfafeSKostya Serebryany     exit(0);
516114cfafeSKostya Serebryany   }
517114cfafeSKostya Serebryany 
5187c921753SKostya Serebryany   std::vector<SizedFile> OldCorpus, NewCorpus;
519114cfafeSKostya Serebryany   GetSizedFilesFromDir(Corpora[0], &OldCorpus);
520114cfafeSKostya Serebryany   for (size_t i = 1; i < Corpora.size(); i++)
521114cfafeSKostya Serebryany     GetSizedFilesFromDir(Corpora[i], &NewCorpus);
522114cfafeSKostya Serebryany   std::sort(OldCorpus.begin(), OldCorpus.end());
523114cfafeSKostya Serebryany   std::sort(NewCorpus.begin(), NewCorpus.end());
524114cfafeSKostya Serebryany 
5254f3c3bbbSYuanfang Chen   std::string CFPath = CFPathOrNull ? CFPathOrNull : TempPath("Merge", ".txt");
5267c921753SKostya Serebryany   std::vector<std::string> NewFiles;
5277c921753SKostya Serebryany   std::set<uint32_t> NewFeatures, NewCov;
5280fda9dcbSKostya Serebryany   CrashResistantMerge(Args, OldCorpus, NewCorpus, &NewFiles, {}, &NewFeatures,
529e6597dbaSaristotelis                       {}, &NewCov, CFPath, true, Flags.set_cover_merge);
5300fda9dcbSKostya Serebryany   for (auto &Path : NewFiles)
531114cfafeSKostya Serebryany     F->WriteToOutputCorpus(FileToVector(Path, Options.MaxLen));
532114cfafeSKostya Serebryany   // We are done, delete the control file if it was a temporary one.
533114cfafeSKostya Serebryany   if (!Flags.merge_control_file)
534114cfafeSKostya Serebryany     RemoveFile(CFPath);
535114cfafeSKostya Serebryany 
536114cfafeSKostya Serebryany   exit(0);
537114cfafeSKostya Serebryany }
538114cfafeSKostya Serebryany 
AnalyzeDictionary(Fuzzer * F,const std::vector<Unit> & Dict,UnitVector & Corpus)5397c921753SKostya Serebryany int AnalyzeDictionary(Fuzzer *F, const std::vector<Unit> &Dict,
54010ab2aceSGeorge Karpenkov                       UnitVector &Corpus) {
54191985c2eSWu, Yingcong   Printf("Started dictionary minimization (up to %zu tests)\n",
54210ab2aceSGeorge Karpenkov          Dict.size() * Corpus.size() * 2);
54310ab2aceSGeorge Karpenkov 
54410ab2aceSGeorge Karpenkov   // Scores and usage count for each dictionary unit.
5457c921753SKostya Serebryany   std::vector<int> Scores(Dict.size());
5467c921753SKostya Serebryany   std::vector<int> Usages(Dict.size());
54710ab2aceSGeorge Karpenkov 
5487c921753SKostya Serebryany   std::vector<size_t> InitialFeatures;
5497c921753SKostya Serebryany   std::vector<size_t> ModifiedFeatures;
55010ab2aceSGeorge Karpenkov   for (auto &C : Corpus) {
55110ab2aceSGeorge Karpenkov     // Get coverage for the testcase without modifications.
55210ab2aceSGeorge Karpenkov     F->ExecuteCallback(C.data(), C.size());
55310ab2aceSGeorge Karpenkov     InitialFeatures.clear();
554bcd78491SKostya Serebryany     TPC.CollectFeatures([&](size_t Feature) {
55510ab2aceSGeorge Karpenkov       InitialFeatures.push_back(Feature);
55610ab2aceSGeorge Karpenkov     });
55710ab2aceSGeorge Karpenkov 
55810ab2aceSGeorge Karpenkov     for (size_t i = 0; i < Dict.size(); ++i) {
5597c921753SKostya Serebryany       std::vector<uint8_t> Data = C;
56010ab2aceSGeorge Karpenkov       auto StartPos = std::search(Data.begin(), Data.end(),
56110ab2aceSGeorge Karpenkov                                   Dict[i].begin(), Dict[i].end());
56210ab2aceSGeorge Karpenkov       // Skip dictionary unit, if the testcase does not contain it.
56310ab2aceSGeorge Karpenkov       if (StartPos == Data.end())
56410ab2aceSGeorge Karpenkov         continue;
56510ab2aceSGeorge Karpenkov 
56610ab2aceSGeorge Karpenkov       ++Usages[i];
56710ab2aceSGeorge Karpenkov       while (StartPos != Data.end()) {
56810ab2aceSGeorge Karpenkov         // Replace all occurrences of dictionary unit in the testcase.
56910ab2aceSGeorge Karpenkov         auto EndPos = StartPos + Dict[i].size();
57010ab2aceSGeorge Karpenkov         for (auto It = StartPos; It != EndPos; ++It)
57110ab2aceSGeorge Karpenkov           *It ^= 0xFF;
57210ab2aceSGeorge Karpenkov 
57310ab2aceSGeorge Karpenkov         StartPos = std::search(EndPos, Data.end(),
57410ab2aceSGeorge Karpenkov                                Dict[i].begin(), Dict[i].end());
57510ab2aceSGeorge Karpenkov       }
57610ab2aceSGeorge Karpenkov 
57710ab2aceSGeorge Karpenkov       // Get coverage for testcase with masked occurrences of dictionary unit.
57810ab2aceSGeorge Karpenkov       F->ExecuteCallback(Data.data(), Data.size());
57910ab2aceSGeorge Karpenkov       ModifiedFeatures.clear();
580bcd78491SKostya Serebryany       TPC.CollectFeatures([&](size_t Feature) {
58110ab2aceSGeorge Karpenkov         ModifiedFeatures.push_back(Feature);
58210ab2aceSGeorge Karpenkov       });
58310ab2aceSGeorge Karpenkov 
58410ab2aceSGeorge Karpenkov       if (InitialFeatures == ModifiedFeatures)
58510ab2aceSGeorge Karpenkov         --Scores[i];
58610ab2aceSGeorge Karpenkov       else
58710ab2aceSGeorge Karpenkov         Scores[i] += 2;
58810ab2aceSGeorge Karpenkov     }
58910ab2aceSGeorge Karpenkov   }
59010ab2aceSGeorge Karpenkov 
59110ab2aceSGeorge Karpenkov   Printf("###### Useless dictionary elements. ######\n");
59210ab2aceSGeorge Karpenkov   for (size_t i = 0; i < Dict.size(); ++i) {
59310ab2aceSGeorge Karpenkov     // Dictionary units with positive score are treated as useful ones.
59410ab2aceSGeorge Karpenkov     if (Scores[i] > 0)
59510ab2aceSGeorge Karpenkov        continue;
59610ab2aceSGeorge Karpenkov 
59710ab2aceSGeorge Karpenkov     Printf("\"");
59810ab2aceSGeorge Karpenkov     PrintASCII(Dict[i].data(), Dict[i].size(), "\"");
59910ab2aceSGeorge Karpenkov     Printf(" # Score: %d, Used: %d\n", Scores[i], Usages[i]);
60010ab2aceSGeorge Karpenkov   }
60110ab2aceSGeorge Karpenkov   Printf("###### End of useless dictionary elements. ######\n");
60210ab2aceSGeorge Karpenkov   return 0;
60310ab2aceSGeorge Karpenkov }
60410ab2aceSGeorge Karpenkov 
ParseSeedInuts(const char * seed_inputs)6057c921753SKostya Serebryany std::vector<std::string> ParseSeedInuts(const char *seed_inputs) {
606da96d921SKostya Serebryany   // Parse -seed_inputs=file1,file2,... or -seed_inputs=@seed_inputs_file
6077c921753SKostya Serebryany   std::vector<std::string> Files;
608da96d921SKostya Serebryany   if (!seed_inputs) return Files;
609da96d921SKostya Serebryany   std::string SeedInputs;
610da96d921SKostya Serebryany   if (Flags.seed_inputs[0] == '@')
611da96d921SKostya Serebryany     SeedInputs = FileToString(Flags.seed_inputs + 1); // File contains list.
612da96d921SKostya Serebryany   else
613da96d921SKostya Serebryany     SeedInputs = Flags.seed_inputs; // seed_inputs contains the list.
614da96d921SKostya Serebryany   if (SeedInputs.empty()) {
615da96d921SKostya Serebryany     Printf("seed_inputs is empty or @file does not exist.\n");
616da96d921SKostya Serebryany     exit(1);
617da96d921SKostya Serebryany   }
618da96d921SKostya Serebryany   // Parse SeedInputs.
619da96d921SKostya Serebryany   size_t comma_pos = 0;
620da96d921SKostya Serebryany   while ((comma_pos = SeedInputs.find_last_of(',')) != std::string::npos) {
621da96d921SKostya Serebryany     Files.push_back(SeedInputs.substr(comma_pos + 1));
622da96d921SKostya Serebryany     SeedInputs = SeedInputs.substr(0, comma_pos);
623da96d921SKostya Serebryany   }
624da96d921SKostya Serebryany   Files.push_back(SeedInputs);
625da96d921SKostya Serebryany   return Files;
626da96d921SKostya Serebryany }
627da96d921SKostya Serebryany 
6287c921753SKostya Serebryany static std::vector<SizedFile>
ReadCorpora(const std::vector<std::string> & CorpusDirs,const std::vector<std::string> & ExtraSeedFiles)6297c921753SKostya Serebryany ReadCorpora(const std::vector<std::string> &CorpusDirs,
6307c921753SKostya Serebryany             const std::vector<std::string> &ExtraSeedFiles) {
6317c921753SKostya Serebryany   std::vector<SizedFile> SizedFiles;
6324c7353c5SKostya Serebryany   size_t LastNumFiles = 0;
6334c7353c5SKostya Serebryany   for (auto &Dir : CorpusDirs) {
6344c7353c5SKostya Serebryany     GetSizedFilesFromDir(Dir, &SizedFiles);
6354c7353c5SKostya Serebryany     Printf("INFO: % 8zd files found in %s\n", SizedFiles.size() - LastNumFiles,
6364c7353c5SKostya Serebryany            Dir.c_str());
6374c7353c5SKostya Serebryany     LastNumFiles = SizedFiles.size();
6384c7353c5SKostya Serebryany   }
6394c7353c5SKostya Serebryany   for (auto &File : ExtraSeedFiles)
6404c7353c5SKostya Serebryany     if (auto Size = FileSize(File))
6414c7353c5SKostya Serebryany       SizedFiles.push_back({File, Size});
6424c7353c5SKostya Serebryany   return SizedFiles;
6434c7353c5SKostya Serebryany }
6444c7353c5SKostya Serebryany 
FuzzerDriver(int * argc,char *** argv,UserCallback Callback)64510ab2aceSGeorge Karpenkov int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
64610ab2aceSGeorge Karpenkov   using namespace fuzzer;
64710ab2aceSGeorge Karpenkov   assert(argc && argv && "Argument pointers cannot be nullptr");
64810ab2aceSGeorge Karpenkov   std::string Argv0((*argv)[0]);
64910ab2aceSGeorge Karpenkov   EF = new ExternalFunctions();
65010ab2aceSGeorge Karpenkov   if (EF->LLVMFuzzerInitialize)
65110ab2aceSGeorge Karpenkov     EF->LLVMFuzzerInitialize(argc, argv);
652a34c65e8SMatt Morehouse   if (EF->__msan_scoped_disable_interceptor_checks)
653a34c65e8SMatt Morehouse     EF->__msan_scoped_disable_interceptor_checks();
6547c921753SKostya Serebryany   const std::vector<std::string> Args(*argv, *argv + *argc);
65510ab2aceSGeorge Karpenkov   assert(!Args.empty());
65610ab2aceSGeorge Karpenkov   ProgName = new std::string(Args[0]);
65710ab2aceSGeorge Karpenkov   if (Argv0 != *ProgName) {
65810ab2aceSGeorge Karpenkov     Printf("ERROR: argv[0] has been modified in LLVMFuzzerInitialize\n");
65910ab2aceSGeorge Karpenkov     exit(1);
66010ab2aceSGeorge Karpenkov   }
6610784e01aSMax Moroz   ParseFlags(Args, EF);
66210ab2aceSGeorge Karpenkov   if (Flags.help) {
66310ab2aceSGeorge Karpenkov     PrintHelp();
66410ab2aceSGeorge Karpenkov     return 0;
66510ab2aceSGeorge Karpenkov   }
66610ab2aceSGeorge Karpenkov 
66710ab2aceSGeorge Karpenkov   if (Flags.close_fd_mask & 2)
66810ab2aceSGeorge Karpenkov     DupAndCloseStderr();
66910ab2aceSGeorge Karpenkov   if (Flags.close_fd_mask & 1)
67010ab2aceSGeorge Karpenkov     CloseStdout();
67110ab2aceSGeorge Karpenkov 
67210ab2aceSGeorge Karpenkov   if (Flags.jobs > 0 && Flags.workers == 0) {
67310ab2aceSGeorge Karpenkov     Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs);
67410ab2aceSGeorge Karpenkov     if (Flags.workers > 1)
67510ab2aceSGeorge Karpenkov       Printf("Running %u workers\n", Flags.workers);
67610ab2aceSGeorge Karpenkov   }
67710ab2aceSGeorge Karpenkov 
67810ab2aceSGeorge Karpenkov   if (Flags.workers > 0 && Flags.jobs > 0)
67910ab2aceSGeorge Karpenkov     return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs);
68010ab2aceSGeorge Karpenkov 
68110ab2aceSGeorge Karpenkov   FuzzingOptions Options;
68210ab2aceSGeorge Karpenkov   Options.Verbosity = Flags.verbosity;
68310ab2aceSGeorge Karpenkov   Options.MaxLen = Flags.max_len;
68436c89b3cSMatt Morehouse   Options.LenControl = Flags.len_control;
68562673c43SDokyung Song   Options.KeepSeed = Flags.keep_seed;
68610ab2aceSGeorge Karpenkov   Options.UnitTimeoutSec = Flags.timeout;
68710ab2aceSGeorge Karpenkov   Options.ErrorExitCode = Flags.error_exitcode;
68810ab2aceSGeorge Karpenkov   Options.TimeoutExitCode = Flags.timeout_exitcode;
689cdbb9dc9SKostya Serebryany   Options.IgnoreTimeouts = Flags.ignore_timeouts;
690cdbb9dc9SKostya Serebryany   Options.IgnoreOOMs = Flags.ignore_ooms;
6919982ee54SKostya Serebryany   Options.IgnoreCrashes = Flags.ignore_crashes;
69210ab2aceSGeorge Karpenkov   Options.MaxTotalTimeSec = Flags.max_total_time;
69310ab2aceSGeorge Karpenkov   Options.DoCrossOver = Flags.cross_over;
694b53243e1SDokyung Song   Options.CrossOverUniformDist = Flags.cross_over_uniform_dist;
69510ab2aceSGeorge Karpenkov   Options.MutateDepth = Flags.mutate_depth;
696ad05ee05SKostya Serebryany   Options.ReduceDepth = Flags.reduce_depth;
69710ab2aceSGeorge Karpenkov   Options.UseCounters = Flags.use_counters;
69810ab2aceSGeorge Karpenkov   Options.UseMemmem = Flags.use_memmem;
69910ab2aceSGeorge Karpenkov   Options.UseCmp = Flags.use_cmp;
70010ab2aceSGeorge Karpenkov   Options.UseValueProfile = Flags.use_value_profile;
70110ab2aceSGeorge Karpenkov   Options.Shrink = Flags.shrink;
70210ab2aceSGeorge Karpenkov   Options.ReduceInputs = Flags.reduce_inputs;
70310ab2aceSGeorge Karpenkov   Options.ShuffleAtStartUp = Flags.shuffle;
70410ab2aceSGeorge Karpenkov   Options.PreferSmall = Flags.prefer_small;
70510ab2aceSGeorge Karpenkov   Options.ReloadIntervalSec = Flags.reload;
70610ab2aceSGeorge Karpenkov   Options.OnlyASCII = Flags.only_ascii;
70710ab2aceSGeorge Karpenkov   Options.DetectLeaks = Flags.detect_leaks;
7086f1c26f2SAlex Shlyapnikov   Options.PurgeAllocatorIntervalSec = Flags.purge_allocator_interval;
70910ab2aceSGeorge Karpenkov   Options.TraceMalloc = Flags.trace_malloc;
71010ab2aceSGeorge Karpenkov   Options.RssLimitMb = Flags.rss_limit_mb;
711de9bafb1SKostya Serebryany   Options.MallocLimitMb = Flags.malloc_limit_mb;
712de9bafb1SKostya Serebryany   if (!Options.MallocLimitMb)
713de9bafb1SKostya Serebryany     Options.MallocLimitMb = Options.RssLimitMb;
71410ab2aceSGeorge Karpenkov   if (Flags.runs >= 0)
71510ab2aceSGeorge Karpenkov     Options.MaxNumberOfRuns = Flags.runs;
7162392ff09SMatt Morehouse   if (!Inputs->empty() && !Flags.minimize_crash_internal_step) {
7172392ff09SMatt Morehouse     // Ensure output corpus assumed to be the first arbitrary argument input
7182392ff09SMatt Morehouse     // is not a path to an existing file.
7192392ff09SMatt Morehouse     std::string OutputCorpusDir = (*Inputs)[0];
7202392ff09SMatt Morehouse     if (!IsFile(OutputCorpusDir)) {
7212392ff09SMatt Morehouse       Options.OutputCorpus = OutputCorpusDir;
722711b9806SMatt Morehouse       ValidateDirectoryExists(Options.OutputCorpus, Flags.create_missing_dirs);
7232392ff09SMatt Morehouse     }
7242392ff09SMatt Morehouse   }
72510ab2aceSGeorge Karpenkov   Options.ReportSlowUnits = Flags.report_slow_units;
7262392ff09SMatt Morehouse   if (Flags.artifact_prefix) {
72710ab2aceSGeorge Karpenkov     Options.ArtifactPrefix = Flags.artifact_prefix;
7282392ff09SMatt Morehouse 
7292392ff09SMatt Morehouse     // Since the prefix could be a full path to a file name prefix, assume
7302392ff09SMatt Morehouse     // that if the path ends with the platform's separator that a directory
7312392ff09SMatt Morehouse     // is desired
7322392ff09SMatt Morehouse     std::string ArtifactPathDir = Options.ArtifactPrefix;
7332392ff09SMatt Morehouse     if (!IsSeparator(ArtifactPathDir[ArtifactPathDir.length() - 1])) {
7342392ff09SMatt Morehouse       ArtifactPathDir = DirName(ArtifactPathDir);
7352392ff09SMatt Morehouse     }
736711b9806SMatt Morehouse     ValidateDirectoryExists(ArtifactPathDir, Flags.create_missing_dirs);
7372392ff09SMatt Morehouse   }
7382392ff09SMatt Morehouse   if (Flags.exact_artifact_path) {
73910ab2aceSGeorge Karpenkov     Options.ExactArtifactPath = Flags.exact_artifact_path;
740711b9806SMatt Morehouse     ValidateDirectoryExists(DirName(Options.ExactArtifactPath),
741711b9806SMatt Morehouse                             Flags.create_missing_dirs);
7422392ff09SMatt Morehouse   }
7437c921753SKostya Serebryany   std::vector<Unit> Dictionary;
74410ab2aceSGeorge Karpenkov   if (Flags.dict)
74510ab2aceSGeorge Karpenkov     if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary))
74610ab2aceSGeorge Karpenkov       return 1;
74710ab2aceSGeorge Karpenkov   if (Flags.verbosity > 0 && !Dictionary.empty())
74810ab2aceSGeorge Karpenkov     Printf("Dictionary: %zd entries\n", Dictionary.size());
7494c7353c5SKostya Serebryany   bool RunIndividualFiles = AllInputsAreFiles();
75010ab2aceSGeorge Karpenkov   Options.SaveArtifacts =
7514c7353c5SKostya Serebryany       !RunIndividualFiles || Flags.minimize_crash_internal_step;
75210ab2aceSGeorge Karpenkov   Options.PrintNewCovPcs = Flags.print_pcs;
7532eef816eSKostya Serebryany   Options.PrintNewCovFuncs = Flags.print_funcs;
75410ab2aceSGeorge Karpenkov   Options.PrintFinalStats = Flags.print_final_stats;
75510ab2aceSGeorge Karpenkov   Options.PrintCorpusStats = Flags.print_corpus_stats;
75610ab2aceSGeorge Karpenkov   Options.PrintCoverage = Flags.print_coverage;
757dc62d5ecSMax Moroz   Options.PrintFullCoverage = Flags.print_full_coverage;
75810ab2aceSGeorge Karpenkov   if (Flags.exit_on_src_pos)
75910ab2aceSGeorge Karpenkov     Options.ExitOnSrcPos = Flags.exit_on_src_pos;
76010ab2aceSGeorge Karpenkov   if (Flags.exit_on_item)
76110ab2aceSGeorge Karpenkov     Options.ExitOnItem = Flags.exit_on_item;
762e9c6f06cSKostya Serebryany   if (Flags.focus_function)
763e9c6f06cSKostya Serebryany     Options.FocusFunction = Flags.focus_function;
7641fd005f5SKostya Serebryany   if (Flags.data_flow_trace)
7651fd005f5SKostya Serebryany     Options.DataFlowTrace = Flags.data_flow_trace;
7662392ff09SMatt Morehouse   if (Flags.features_dir) {
7674614cc3dSKostya Serebryany     Options.FeaturesDir = Flags.features_dir;
768711b9806SMatt Morehouse     ValidateDirectoryExists(Options.FeaturesDir, Flags.create_missing_dirs);
7692392ff09SMatt Morehouse   }
7701bb1eac6SDokyung Song   if (Flags.mutation_graph_file)
7711bb1eac6SDokyung Song     Options.MutationGraphFile = Flags.mutation_graph_file;
772b7cc3d99SKostya Serebryany   if (Flags.collect_data_flow)
773b7cc3d99SKostya Serebryany     Options.CollectDataFlow = Flags.collect_data_flow;
774db88fc56SKostya Serebryany   if (Flags.stop_file)
775db88fc56SKostya Serebryany     Options.StopFile = Flags.stop_file;
776e2e38fcaSMatt Morehouse   Options.Entropic = Flags.entropic;
777e2e38fcaSMatt Morehouse   Options.EntropicFeatureFrequencyThreshold =
778e2e38fcaSMatt Morehouse       (size_t)Flags.entropic_feature_frequency_threshold;
779e2e38fcaSMatt Morehouse   Options.EntropicNumberOfRarestFeatures =
780e2e38fcaSMatt Morehouse       (size_t)Flags.entropic_number_of_rarest_features;
7815cda4dc7SDokyung Song   Options.EntropicScalePerExecTime = Flags.entropic_scale_per_exec_time;
782f3c2e0bcSMatt Morehouse   if (!Options.FocusFunction.empty())
783f3c2e0bcSMatt Morehouse     Options.Entropic = false; // FocusFunction overrides entropic scheduling.
784f3c2e0bcSMatt Morehouse   if (Options.Entropic)
78591985c2eSWu, Yingcong     Printf("INFO: Running with entropic power schedule (0x%zX, %zu).\n",
786e2e38fcaSMatt Morehouse            Options.EntropicFeatureFrequencyThreshold,
787e2e38fcaSMatt Morehouse            Options.EntropicNumberOfRarestFeatures);
788e2e38fcaSMatt Morehouse   struct EntropicOptions Entropic;
789e2e38fcaSMatt Morehouse   Entropic.Enabled = Options.Entropic;
790e2e38fcaSMatt Morehouse   Entropic.FeatureFrequencyThreshold =
791e2e38fcaSMatt Morehouse       Options.EntropicFeatureFrequencyThreshold;
792e2e38fcaSMatt Morehouse   Entropic.NumberOfRarestFeatures = Options.EntropicNumberOfRarestFeatures;
7935cda4dc7SDokyung Song   Entropic.ScalePerExecTime = Options.EntropicScalePerExecTime;
79410ab2aceSGeorge Karpenkov 
79510ab2aceSGeorge Karpenkov   unsigned Seed = Flags.seed;
79610ab2aceSGeorge Karpenkov   // Initialize Seed.
79710ab2aceSGeorge Karpenkov   if (Seed == 0)
7986708186cSAaron Green     Seed = static_cast<unsigned>(
7996708186cSAaron Green         std::chrono::system_clock::now().time_since_epoch().count() + GetPid());
80010ab2aceSGeorge Karpenkov   if (Flags.verbosity)
80110ab2aceSGeorge Karpenkov     Printf("INFO: Seed: %u\n", Seed);
80210ab2aceSGeorge Karpenkov 
80367f5b05cSWu, Yingcong   if (Flags.collect_data_flow && Flags.data_flow_trace && !Flags.fork &&
804e6597dbaSaristotelis       !(Flags.merge || Flags.set_cover_merge)) {
8054c7353c5SKostya Serebryany     if (RunIndividualFiles)
806da96d921SKostya Serebryany       return CollectDataFlow(Flags.collect_data_flow, Flags.data_flow_trace,
8074c7353c5SKostya Serebryany                         ReadCorpora({}, *Inputs));
8084c7353c5SKostya Serebryany     else
8094c7353c5SKostya Serebryany       return CollectDataFlow(Flags.collect_data_flow, Flags.data_flow_trace,
8104c7353c5SKostya Serebryany                         ReadCorpora(*Inputs, {}));
8114c7353c5SKostya Serebryany   }
812da96d921SKostya Serebryany 
813c5d72517SMarco Vanotti   Random Rand(Seed);
814c5d72517SMarco Vanotti   auto *MD = new MutationDispatcher(Rand, Options);
815e2e38fcaSMatt Morehouse   auto *Corpus = new InputCorpus(Options.OutputCorpus, Entropic);
81610ab2aceSGeorge Karpenkov   auto *F = new Fuzzer(Callback, *Corpus, *MD, Options);
81710ab2aceSGeorge Karpenkov 
81810ab2aceSGeorge Karpenkov   for (auto &U: Dictionary)
81910ab2aceSGeorge Karpenkov     if (U.size() <= Word::GetMaxSize())
82010ab2aceSGeorge Karpenkov       MD->AddWordToManualDictionary(Word(U.data(), U.size()));
82110ab2aceSGeorge Karpenkov 
82223bee0b0SJonathan Metzman       // Threads are only supported by Chrome. Don't use them with emscripten
82323bee0b0SJonathan Metzman       // for now.
82423bee0b0SJonathan Metzman #if !LIBFUZZER_EMSCRIPTEN
82510ab2aceSGeorge Karpenkov   StartRssThread(F, Flags.rss_limit_mb);
82623bee0b0SJonathan Metzman #endif // LIBFUZZER_EMSCRIPTEN
82710ab2aceSGeorge Karpenkov 
82810ab2aceSGeorge Karpenkov   Options.HandleAbrt = Flags.handle_abrt;
8299df7ee34SIlya Leoshkevich   Options.HandleAlrm = !Flags.minimize_crash;
83010ab2aceSGeorge Karpenkov   Options.HandleBus = Flags.handle_bus;
83110ab2aceSGeorge Karpenkov   Options.HandleFpe = Flags.handle_fpe;
83210ab2aceSGeorge Karpenkov   Options.HandleIll = Flags.handle_ill;
83310ab2aceSGeorge Karpenkov   Options.HandleInt = Flags.handle_int;
83410ab2aceSGeorge Karpenkov   Options.HandleSegv = Flags.handle_segv;
83510ab2aceSGeorge Karpenkov   Options.HandleTerm = Flags.handle_term;
83610ab2aceSGeorge Karpenkov   Options.HandleXfsz = Flags.handle_xfsz;
837a2ca2dccSKostya Serebryany   Options.HandleUsr1 = Flags.handle_usr1;
838a2ca2dccSKostya Serebryany   Options.HandleUsr2 = Flags.handle_usr2;
839f897e82bSJoe Pletcher   Options.HandleWinExcept = Flags.handle_winexcept;
840f897e82bSJoe Pletcher 
84110ab2aceSGeorge Karpenkov   SetSignalHandler(Options);
84210ab2aceSGeorge Karpenkov 
84310ab2aceSGeorge Karpenkov   std::atexit(Fuzzer::StaticExitCallback);
84410ab2aceSGeorge Karpenkov 
84510ab2aceSGeorge Karpenkov   if (Flags.minimize_crash)
84610ab2aceSGeorge Karpenkov     return MinimizeCrashInput(Args, Options);
84710ab2aceSGeorge Karpenkov 
84810ab2aceSGeorge Karpenkov   if (Flags.minimize_crash_internal_step)
84910ab2aceSGeorge Karpenkov     return MinimizeCrashInputInternalStep(F, Corpus);
85010ab2aceSGeorge Karpenkov 
85110ab2aceSGeorge Karpenkov   if (Flags.cleanse_crash)
85210ab2aceSGeorge Karpenkov     return CleanseCrashInput(Args, Options);
85310ab2aceSGeorge Karpenkov 
8544c7353c5SKostya Serebryany   if (RunIndividualFiles) {
85510ab2aceSGeorge Karpenkov     Options.SaveArtifacts = false;
85610ab2aceSGeorge Karpenkov     int Runs = std::max(1, Flags.runs);
85710ab2aceSGeorge Karpenkov     Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName->c_str(),
85810ab2aceSGeorge Karpenkov            Inputs->size(), Runs);
85910ab2aceSGeorge Karpenkov     for (auto &Path : *Inputs) {
86010ab2aceSGeorge Karpenkov       auto StartTime = system_clock::now();
86110ab2aceSGeorge Karpenkov       Printf("Running: %s\n", Path.c_str());
86210ab2aceSGeorge Karpenkov       for (int Iter = 0; Iter < Runs; Iter++)
86310ab2aceSGeorge Karpenkov         RunOneTest(F, Path.c_str(), Options.MaxLen);
86410ab2aceSGeorge Karpenkov       auto StopTime = system_clock::now();
86510ab2aceSGeorge Karpenkov       auto MS = duration_cast<milliseconds>(StopTime - StartTime).count();
86691985c2eSWu, Yingcong       Printf("Executed %s in %ld ms\n", Path.c_str(), (long)MS);
86710ab2aceSGeorge Karpenkov     }
86810ab2aceSGeorge Karpenkov     Printf("***\n"
86910ab2aceSGeorge Karpenkov            "*** NOTE: fuzzing was not performed, you have only\n"
87010ab2aceSGeorge Karpenkov            "***       executed the target code on a fixed set of inputs.\n"
87110ab2aceSGeorge Karpenkov            "***\n");
87210ab2aceSGeorge Karpenkov     F->PrintFinalStats();
87310ab2aceSGeorge Karpenkov     exit(0);
87410ab2aceSGeorge Karpenkov   }
87510ab2aceSGeorge Karpenkov 
876a30dbbe9Sgtt1995   Options.ForkCorpusGroups = Flags.fork_corpus_groups;
877f762a115SKostya Serebryany   if (Flags.fork)
87860c5ded2SKostya Serebryany     FuzzWithFork(F->GetMD().GetRand(), Options, Args, *Inputs, Flags.fork);
879f762a115SKostya Serebryany 
880e6597dbaSaristotelis   if (Flags.merge || Flags.set_cover_merge)
881114cfafeSKostya Serebryany     Merge(F, Options, Args, *Inputs, Flags.merge_control_file);
88210ab2aceSGeorge Karpenkov 
88368fdef1fSKostya Serebryany   if (Flags.merge_inner) {
88468fdef1fSKostya Serebryany     const size_t kDefaultMaxMergeLen = 1 << 20;
88568fdef1fSKostya Serebryany     if (Options.MaxLen == 0)
88668fdef1fSKostya Serebryany       F->SetMaxInputLen(kDefaultMaxMergeLen);
88768fdef1fSKostya Serebryany     assert(Flags.merge_control_file);
888e6597dbaSaristotelis     F->CrashResistantMergeInternalStep(Flags.merge_control_file,
889e6597dbaSaristotelis                                        !strncmp(Flags.merge_inner, "2", 1));
89068fdef1fSKostya Serebryany     exit(0);
89168fdef1fSKostya Serebryany   }
89210ab2aceSGeorge Karpenkov 
8933a8e3c83SKostya Serebryany   if (Flags.analyze_dict) {
8943a8e3c83SKostya Serebryany     size_t MaxLen = INT_MAX;  // Large max length.
89510ab2aceSGeorge Karpenkov     UnitVector InitialCorpus;
89610ab2aceSGeorge Karpenkov     for (auto &Inp : *Inputs) {
89710ab2aceSGeorge Karpenkov       Printf("Loading corpus dir: %s\n", Inp.c_str());
89810ab2aceSGeorge Karpenkov       ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr,
8993a8e3c83SKostya Serebryany                              MaxLen, /*ExitOnError=*/false);
90010ab2aceSGeorge Karpenkov     }
90110ab2aceSGeorge Karpenkov 
90210ab2aceSGeorge Karpenkov     if (Dictionary.empty() || Inputs->empty()) {
90310ab2aceSGeorge Karpenkov       Printf("ERROR: can't analyze dict without dict and corpus provided\n");
90410ab2aceSGeorge Karpenkov       return 1;
90510ab2aceSGeorge Karpenkov     }
90610ab2aceSGeorge Karpenkov     if (AnalyzeDictionary(F, Dictionary, InitialCorpus)) {
90710ab2aceSGeorge Karpenkov       Printf("Dictionary analysis failed\n");
90810ab2aceSGeorge Karpenkov       exit(1);
90910ab2aceSGeorge Karpenkov     }
910d9a8b6a7SSylvestre Ledru     Printf("Dictionary analysis succeeded\n");
91110ab2aceSGeorge Karpenkov     exit(0);
91210ab2aceSGeorge Karpenkov   }
91310ab2aceSGeorge Karpenkov 
9144c7353c5SKostya Serebryany   auto CorporaFiles = ReadCorpora(*Inputs, ParseSeedInuts(Flags.seed_inputs));
9154c7353c5SKostya Serebryany   F->Loop(CorporaFiles);
91610ab2aceSGeorge Karpenkov 
91710ab2aceSGeorge Karpenkov   if (Flags.verbosity)
91810ab2aceSGeorge Karpenkov     Printf("Done %zd runs in %zd second(s)\n", F->getTotalNumberOfRuns(),
91910ab2aceSGeorge Karpenkov            F->secondsSinceProcessStartUp());
92010ab2aceSGeorge Karpenkov   F->PrintFinalStats();
92110ab2aceSGeorge Karpenkov 
92210ab2aceSGeorge Karpenkov   exit(0);  // Don't let F destroy itself.
92310ab2aceSGeorge Karpenkov }
92410ab2aceSGeorge Karpenkov 
92534ddf0b2SMatt Morehouse extern "C" ATTRIBUTE_INTERFACE int
LLVMFuzzerRunDriver(int * argc,char *** argv,int (* UserCb)(const uint8_t * Data,size_t Size))92634ddf0b2SMatt Morehouse LLVMFuzzerRunDriver(int *argc, char ***argv,
92734ddf0b2SMatt Morehouse                     int (*UserCb)(const uint8_t *Data, size_t Size)) {
92834ddf0b2SMatt Morehouse   return FuzzerDriver(argc, argv, UserCb);
92934ddf0b2SMatt Morehouse }
93034ddf0b2SMatt Morehouse 
93110ab2aceSGeorge Karpenkov // Storage for global ExternalFunctions object.
93210ab2aceSGeorge Karpenkov ExternalFunctions *EF = nullptr;
93310ab2aceSGeorge Karpenkov 
93410ab2aceSGeorge Karpenkov }  // namespace fuzzer
935