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.
32extern "C" __attribute__((used)) void __libfuzzer_is_present() {}
33
34namespace fuzzer {
35
36// Program arguments.
37struct 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
46struct {
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
58static 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
75static const size_t kNumFlags =
76    sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]);
77
78static Vector<std::string> *Inputs;
79static std::string *ProgName;
80
81static 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
108static 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.
117static 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
133static 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.
179static 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
200static std::mutex Mu;
201
202static void PulseThread() {
203  while (true) {
204    SleepSeconds(600);
205    std::lock_guard<std::mutex> Lock(Mu);
206    Printf("pulse...\n");
207  }
208}
209
210static 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
233std::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
244static 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
261static 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
270static void StartRssThread(Fuzzer *F, size_t RssLimitMb) {
271  if (!RssLimitMb) return;
272  std::thread T(RssThread, F, RssLimitMb);
273  T.detach();
274}
275
276int 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
285static 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
293static 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
304int 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
363int 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
450int 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
467int 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
533int 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.
775ExternalFunctions *EF = nullptr;
776
777}  // namespace fuzzer
778