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