[llvm] r280332 - [libFuzzer] add -minimize_crash flag (to minimize crashers). also add two tests that I failed to commit last time

Kostya Serebryany via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 31 18:22:28 PDT 2016


Author: kcc
Date: Wed Aug 31 20:22:27 2016
New Revision: 280332

URL: http://llvm.org/viewvc/llvm-project?rev=280332&view=rev
Log:
[libFuzzer] add -minimize_crash flag (to minimize crashers). also add two tests that I failed to commit last time

Added:
    llvm/trunk/lib/Fuzzer/test/minimize_crash.test
    llvm/trunk/lib/Fuzzer/test/value-profile-div.test
    llvm/trunk/lib/Fuzzer/test/value-profile-load.test
Modified:
    llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp
    llvm/trunk/lib/Fuzzer/FuzzerFlags.def

Modified: llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp?rev=280332&r1=280331&r2=280332&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp Wed Aug 31 20:22:27 2016
@@ -215,16 +215,27 @@ static void WorkerThread(const std::stri
   }
 }
 
-static int RunInMultipleProcesses(const std::vector<std::string> &Args,
-                                  int NumWorkers, int NumJobs) {
-  std::atomic<int> Counter(0);
-  std::atomic<bool> HasErrors(false);
+static std::string CloneArgsWithoutX(const std::vector<std::string> &Args,
+                                     const char *X1, const char *X2) {
   std::string Cmd;
   for (auto &S : Args) {
-    if (FlagValue(S.c_str(), "jobs") || FlagValue(S.c_str(), "workers"))
+    if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2))
       continue;
     Cmd += S + " ";
   }
+  return Cmd;
+}
+
+static std::string CloneArgsWithoutX(const std::vector<std::string> &Args,
+                                     const char *X) {
+  return CloneArgsWithoutX(Args, X, X);
+}
+
+static int RunInMultipleProcesses(const std::vector<std::string> &Args,
+                                  int NumWorkers, int NumJobs) {
+  std::atomic<int> Counter(0);
+  std::atomic<bool> HasErrors(false);
+  std::string Cmd = CloneArgsWithoutX(Args, "jobs", "workers");
   std::vector<std::thread> V;
   std::thread Pulse(PulseThread);
   Pulse.detach();
@@ -266,6 +277,80 @@ static bool AllInputsAreFiles() {
   return true;
 }
 
+int MinimizeCrashInput(const std::vector<std::string> &Args) {
+  if (Inputs->size() != 1) {
+    Printf("ERROR: -minimize_crash should be given one input file\n");
+    exit(1);
+  }
+  if (Flags.runs <= 0 && Flags.max_total_time == 0) {
+    Printf("ERROR: you need to use -runs=N or "
+           "-max_total_time=N with -minimize_crash=1\n" );
+    exit(1);
+  }
+  std::string InputFilePath = Inputs->at(0);
+  std::string BaseCmd = CloneArgsWithoutX(Args, "minimize_crash");
+  auto InputPos = BaseCmd.find(" " + InputFilePath + " ");
+  assert(InputPos != std::string::npos);
+  BaseCmd.erase(InputPos, InputFilePath.size() + 1);
+  // BaseCmd += " >  /dev/null 2>&1 ";
+
+  std::string CurrentFilePath = InputFilePath;
+  while (true) {
+    Unit U = FileToVector(CurrentFilePath);
+    if (U.size() < 2) {
+      Printf("CRASH_MIN: '%s' is small enough\n", CurrentFilePath.c_str());
+      return 0;
+    }
+    Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n",
+           CurrentFilePath.c_str(), U.size());
+
+    auto Cmd = BaseCmd + " " + CurrentFilePath;
+
+    Printf("CRASH_MIN: executing: %s\n", Cmd.c_str());
+    int ExitCode = ExecuteCommand(Cmd);
+    if (ExitCode == 0) {
+      Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str());
+      exit(1);
+    }
+    Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize "
+           "it further\n",
+           CurrentFilePath.c_str(), U.size());
+
+    std::string ArtifactPath = "minimized-from-" + Hash(U);
+    Cmd += " -minimize_crash_internal_step=1 -exact_artifact_path=" +
+        ArtifactPath;
+    Printf("CRASH_MIN: executing: %s\n", Cmd.c_str());
+    ExitCode = ExecuteCommand(Cmd);
+    if (ExitCode == 0) {
+      Printf("CRASH_MIN: failed to minimize beyond %s (%d bytes), exiting\n",
+             CurrentFilePath.c_str(), U.size());
+      return 0;
+    }
+    CurrentFilePath = ArtifactPath;
+    Printf("\n\n\n\n\n\n*********************************\n");
+  }
+  return 0;
+}
+
+int MinimizeCrashInputInternalStep(Fuzzer *F) {
+  assert(Inputs->size() == 1);
+  std::string InputFilePath = Inputs->at(0);
+  Unit U = FileToVector(InputFilePath);
+  assert(U.size() > 2);
+  Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size());
+  Unit X(U.size() - 1);
+  for (size_t I = 0; I < U.size(); I++) {
+    std::copy(U.begin(), U.begin() + I, X.begin());
+    std::copy(U.begin() + I + 1, U.end(), X.begin() + I);
+    F->AddToCorpus(X);
+  }
+  F->SetMaxLen(U.size() - 1);
+  F->Loop();
+  Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n");
+  exit(0);
+  return 0;
+}
+
 int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
   using namespace fuzzer;
   assert(argc && argv && "Argument pointers cannot be nullptr");
@@ -281,6 +366,9 @@ int FuzzerDriver(int *argc, char ***argv
     return 0;
   }
 
+  if (Flags.minimize_crash)
+    return MinimizeCrashInput(Args);
+
   if (Flags.close_fd_mask & 2)
     DupAndCloseStderr();
   if (Flags.close_fd_mask & 1)
@@ -319,7 +407,7 @@ int FuzzerDriver(int *argc, char ***argv
   Options.RssLimitMb = Flags.rss_limit_mb;
   if (Flags.runs >= 0)
     Options.MaxNumberOfRuns = Flags.runs;
-  if (!Inputs->empty())
+  if (!Inputs->empty() && !Flags.minimize_crash_internal_step)
     Options.OutputCorpus = (*Inputs)[0];
   Options.ReportSlowUnits = Flags.report_slow_units;
   if (Flags.artifact_prefix)
@@ -333,7 +421,8 @@ int FuzzerDriver(int *argc, char ***argv
   if (Flags.verbosity > 0 && !Dictionary.empty())
     Printf("Dictionary: %zd entries\n", Dictionary.size());
   bool DoPlainRun = AllInputsAreFiles();
-  Options.SaveArtifacts = !DoPlainRun;
+  Options.SaveArtifacts =
+      !DoPlainRun || Flags.minimize_crash_internal_step;
   Options.PrintNewCovPcs = Flags.print_pcs;
   Options.PrintFinalStats = Flags.print_final_stats;
   Options.TruncateUnits = Flags.truncate_units;
@@ -371,6 +460,9 @@ int FuzzerDriver(int *argc, char ***argv
   if (Flags.handle_int) SetSigIntHandler();
   if (Flags.handle_term) SetSigTermHandler();
 
+  if (Flags.minimize_crash_internal_step)
+    return MinimizeCrashInputInternalStep(&F);
+
   if (DoPlainRun) {
     Options.SaveArtifacts = false;
     int Runs = std::max(1, Flags.runs);
@@ -393,7 +485,6 @@ int FuzzerDriver(int *argc, char ***argv
     exit(0);
   }
 
-
   if (Flags.merge) {
     if (Options.MaxLen == 0)
       F.SetMaxLen(kMaxSaneLen);

Modified: llvm/trunk/lib/Fuzzer/FuzzerFlags.def
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerFlags.def?rev=280332&r1=280331&r2=280332&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerFlags.def (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerFlags.def Wed Aug 31 20:22:27 2016
@@ -37,6 +37,10 @@ FUZZER_FLAG_INT(help, 0, "Print help.")
 FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be "
   "merged into the 1-st corpus. Only interesting units will be taken. "
   "This flag can be used to minimize a corpus.")
+FUZZER_FLAG_INT(minimize_crash, 0, "If 1, minimizes the provided"
+  " crash input. Use with -runs=N or -max_total_time=N to limit "
+  "the number attempts")
+FUZZER_FLAG_INT(minimize_crash_internal_step, 0, "internal flag")
 FUZZER_FLAG_INT(use_counters, 1, "Use coverage counters")
 FUZZER_FLAG_INT(use_indir_calls, 1, "Use indirect caller-callee counters")
 FUZZER_FLAG_INT(use_traces, 0, "Experimental: use instruction traces")

Added: llvm/trunk/lib/Fuzzer/test/minimize_crash.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/minimize_crash.test?rev=280332&view=auto
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/minimize_crash.test (added)
+++ llvm/trunk/lib/Fuzzer/test/minimize_crash.test Wed Aug 31 20:22:27 2016
@@ -0,0 +1,6 @@
+CHECK: CRASH_MIN: failed to minimize beyond minimized-from-{{.*}} (3 bytes), exiting
+RUN: echo 'Hi!rv349f34t3gg' > not_minimal_crash
+RUN: LLVMFuzzer-NullDerefTest -minimize_crash=1 not_minimal_crash -max_total_time=2 2>&1 | FileCheck %s
+RUN: rm not_minimal_crash minimized-from-*
+
+

Added: llvm/trunk/lib/Fuzzer/test/value-profile-div.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/value-profile-div.test?rev=280332&view=auto
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/value-profile-div.test (added)
+++ llvm/trunk/lib/Fuzzer/test/value-profile-div.test Wed Aug 31 20:22:27 2016
@@ -0,0 +1,3 @@
+CHECK: AddressSanitizer: FPE
+RUN: not LLVMFuzzer-DivTest -seed=1 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s
+

Added: llvm/trunk/lib/Fuzzer/test/value-profile-load.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/value-profile-load.test?rev=280332&view=auto
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/value-profile-load.test (added)
+++ llvm/trunk/lib/Fuzzer/test/value-profile-load.test Wed Aug 31 20:22:27 2016
@@ -0,0 +1,3 @@
+CHECK: AddressSanitizer: global-buffer-overflow
+RUN: not LLVMFuzzer-LoadTest -seed=1 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s
+




More information about the llvm-commits mailing list