[fuzzer] make multi-process execution more verbose; fix mutation to actually respect mutation depth and to never produce empty units

llvm-svn: 228170
diff --git a/llvm/lib/Fuzzer/FuzzerFlags.def b/llvm/lib/Fuzzer/FuzzerFlags.def
index cbaa81e..0895fa7 100644
--- a/llvm/lib/Fuzzer/FuzzerFlags.def
+++ b/llvm/lib/Fuzzer/FuzzerFlags.def
@@ -16,7 +16,7 @@
             "Number of iterations of the fuzzer (-1 for infinite runs).")
 FUZZER_FLAG(int, max_len, 64, "Maximal length of the test input.")
 FUZZER_FLAG(int, cross_over, 1, "If 1, cross over inputs.")
-FUZZER_FLAG(int, mutate_depth, 10,
+FUZZER_FLAG(int, mutate_depth, 5,
             "Apply this number of consecutive mutations to each input.")
 FUZZER_FLAG(int, exit_on_first, 0,
             "If 1, exit after the first new interesting input is found.")
diff --git a/llvm/lib/Fuzzer/FuzzerIO.cpp b/llvm/lib/Fuzzer/FuzzerIO.cpp
index 4e0ac81..224808c 100644
--- a/llvm/lib/Fuzzer/FuzzerIO.cpp
+++ b/llvm/lib/Fuzzer/FuzzerIO.cpp
@@ -9,6 +9,8 @@
 // IO functions.
 //===----------------------------------------------------------------------===//
 #include "FuzzerInternal.h"
+#include <iostream>
+#include <iterator>
 #include <fstream>
 #include <dirent.h>
 namespace fuzzer {
@@ -31,6 +33,12 @@
               std::istreambuf_iterator<char>());
 }
 
+void CopyFileToErr(const std::string &Path) {
+  std::ifstream T(Path);
+  std::copy(std::istreambuf_iterator<char>(T), std::istreambuf_iterator<char>(),
+            std::ostream_iterator<char>(std::cerr, ""));
+}
+
 void WriteToFile(const Unit &U, const std::string &Path) {
   std::ofstream OF(Path);
   OF.write((const char*)U.data(), U.size());
diff --git a/llvm/lib/Fuzzer/FuzzerInternal.h b/llvm/lib/Fuzzer/FuzzerInternal.h
index 4537971..fbf2630 100644
--- a/llvm/lib/Fuzzer/FuzzerInternal.h
+++ b/llvm/lib/Fuzzer/FuzzerInternal.h
@@ -23,6 +23,7 @@
 Unit ReadFile(const char *Path);
 void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V);
 void WriteToFile(const Unit &U, const std::string &Path);
+void CopyFileToErr(const std::string &Path);
 // Returns "Dir/FileName" or equivalent for the current OS.
 std::string DirPlusFile(const std::string &DirPath,
                         const std::string &FileName);
@@ -42,7 +43,7 @@
     int Verbosity = 1;
     int MaxLen = 0;
     bool DoCrossOver = true;
-    bool MutateDepth = 10;
+    int  MutateDepth = 5;
     bool ExitOnFirst = false;
     bool UseFullCoverageSet  = false;
     std::string OutputCorpus;
diff --git a/llvm/lib/Fuzzer/FuzzerLoop.cpp b/llvm/lib/Fuzzer/FuzzerLoop.cpp
index 88ae6ca..0428589 100644
--- a/llvm/lib/Fuzzer/FuzzerLoop.cpp
+++ b/llvm/lib/Fuzzer/FuzzerLoop.cpp
@@ -146,9 +146,8 @@
 
 size_t Fuzzer::MutateAndTestOne(Unit *U) {
   size_t NewUnits = 0;
-  for (size_t i = 0; i < Options.MutateDepth; i++) {
+  for (int i = 0; i < Options.MutateDepth; i++) {
     Mutate(U, Options.MaxLen);
-    if (U->empty()) continue;
     size_t NewCoverage = RunOne(*U);
     if (NewCoverage) {
       Corpus.push_back(*U);
@@ -158,6 +157,7 @@
                   << "\tNEW: " << NewCoverage
                   << " L: " << U->size()
                   << " S: " << Corpus.size()
+                  << " I: " << i
                   << "\t";
         if (U->size() < 30) {
           PrintASCII(*U);
diff --git a/llvm/lib/Fuzzer/FuzzerMain.cpp b/llvm/lib/Fuzzer/FuzzerMain.cpp
index 3370a80..0a852ed 100644
--- a/llvm/lib/Fuzzer/FuzzerMain.cpp
+++ b/llvm/lib/Fuzzer/FuzzerMain.cpp
@@ -17,6 +17,7 @@
 #include <iostream>
 #include <thread>
 #include <atomic>
+#include <mutex>
 
 // ASAN options:
 //   * don't dump the coverage to disk.
@@ -105,20 +106,30 @@
 }
 
 static void WorkerThread(const std::string &Cmd, std::atomic<int> *Counter,
-                         int NumJobs) {
+                        int NumJobs, std::atomic<bool> *HasErrors) {
+  static std::mutex CerrMutex;
   while (true) {
     int C = (*Counter)++;
-    if (C >= NumJobs) return;
-    std::string ToRun = Cmd + " > fuzz-" + std::to_string(C) + ".log 2>&1\n";
+    if (C >= NumJobs) break;
+    std::string Log = "fuzz-" + std::to_string(C) + ".log";
+    std::string ToRun = Cmd + " > " + Log + " 2>&1\n";
     if (Flags.verbosity)
       std::cerr << ToRun;
-    system(ToRun.c_str());
+    int ExitCode = system(ToRun.c_str());
+    if (ExitCode != 0)
+      *HasErrors = true;
+    std::lock_guard<std::mutex> Lock(CerrMutex);
+    std::cerr << "================== Job " << C
+              << " exited with exit code " << ExitCode
+              << " =================\n";
+    fuzzer::CopyFileToErr(Log);
   }
 }
 
 static int RunInMultipleProcesses(int argc, char **argv, int NumWorkers,
                                   int NumJobs) {
   std::atomic<int> Counter(0);
+  std::atomic<bool> HasErrors(false);
   std::string Cmd;
   for (int i = 0; i < argc; i++) {
     if (FlagValue(argv[i], "jobs") || FlagValue(argv[i], "workers")) continue;
@@ -127,10 +138,10 @@
   }
   std::vector<std::thread> V;
   for (int i = 0; i < NumWorkers; i++)
-    V.push_back(std::thread(WorkerThread, Cmd, &Counter, NumJobs));
+    V.push_back(std::thread(WorkerThread, Cmd, &Counter, NumJobs, &HasErrors));
   for (auto &T : V)
     T.join();
-  return 0;
+  return HasErrors ? 1 : 0;
 }
 
 int main(int argc, char **argv) {
diff --git a/llvm/lib/Fuzzer/FuzzerMutate.cpp b/llvm/lib/Fuzzer/FuzzerMutate.cpp
index 2db8fac..60d5623 100644
--- a/llvm/lib/Fuzzer/FuzzerMutate.cpp
+++ b/llvm/lib/Fuzzer/FuzzerMutate.cpp
@@ -31,18 +31,25 @@
   return Special[rand() % (sizeof(Special) - 1)];
 }
 
+// Mutate U in place.
 void Mutate(Unit *U, size_t MaxLen) {
   assert(MaxLen > 0);
   assert(U->size() <= MaxLen);
+  if (U->empty()) {
+    for (size_t i = 0; i < MaxLen; i++)
+      U->push_back(RandCh());
+    return;
+  }
+  assert(!U->empty());
   switch (rand() % 3) {
   case 0:
-    if (U->size())
+    if (U->size() > 1) {
       U->erase(U->begin() + rand() % U->size());
-    break;
+      break;
+    }
+    // Fallthrough
   case 1:
-    if (U->empty()) {
-      U->push_back(RandCh());
-    } else if (U->size() < MaxLen) {
+    if (U->size() < MaxLen) {
       U->insert(U->begin() + rand() % U->size(), RandCh());
     } else { // At MaxLen.
       uint8_t Ch = RandCh();
@@ -51,12 +58,13 @@
     }
     break;
   default:
-    if (!U->empty()) {
-      size_t idx = rand() % U->size();
-      (*U)[idx] = FlipRandomBit((*U)[idx]);
+    {
+      size_t Idx = rand() % U->size();
+      (*U)[Idx] = FlipRandomBit((*U)[Idx]);
     }
     break;
   }
+  assert(!U->empty());
 }
 
 }  // namespace fuzzer