Bug 1450047 - part 2 - updated in-tree copy of libFuzzer; r?decoder draft
authorAlex Gaynor <agaynor@mozilla.com>
Thu, 29 Mar 2018 14:18:36 -0400
changeset 774915 8732fa42e675357100ba5704cce338275802bd1b
parent 774872 09526140c91d36f2bf514fbafe0b9fabf1a287a5
push id104553
push userbmo:agaynor@mozilla.com
push dateThu, 29 Mar 2018 19:02:06 +0000
reviewersdecoder
bugs1450047
milestone61.0a1
Bug 1450047 - part 2 - updated in-tree copy of libFuzzer; r?decoder MozReview-Commit-ID: I1LZ8N82kr7
tools/fuzzing/libfuzzer/FuzzerClangCounters.cpp
tools/fuzzing/libfuzzer/FuzzerCommand.h
tools/fuzzing/libfuzzer/FuzzerCorpus.h
tools/fuzzing/libfuzzer/FuzzerDefs.h
tools/fuzzing/libfuzzer/FuzzerDictionary.h
tools/fuzzing/libfuzzer/FuzzerDriver.cpp
tools/fuzzing/libfuzzer/FuzzerExtFunctions.def
tools/fuzzing/libfuzzer/FuzzerExtFunctionsDlsymWin.cpp
tools/fuzzing/libfuzzer/FuzzerExtFunctionsWeak.cpp
tools/fuzzing/libfuzzer/FuzzerExtraCounters.cpp
tools/fuzzing/libfuzzer/FuzzerFlags.def
tools/fuzzing/libfuzzer/FuzzerFnAdapter.h
tools/fuzzing/libfuzzer/FuzzerIO.cpp
tools/fuzzing/libfuzzer/FuzzerIO.h
tools/fuzzing/libfuzzer/FuzzerIOPosix.cpp
tools/fuzzing/libfuzzer/FuzzerIOWindows.cpp
tools/fuzzing/libfuzzer/FuzzerInterface.h
tools/fuzzing/libfuzzer/FuzzerInternal.h
tools/fuzzing/libfuzzer/FuzzerLoop.cpp
tools/fuzzing/libfuzzer/FuzzerMain.cpp
tools/fuzzing/libfuzzer/FuzzerMerge.cpp
tools/fuzzing/libfuzzer/FuzzerMerge.h
tools/fuzzing/libfuzzer/FuzzerMutate.cpp
tools/fuzzing/libfuzzer/FuzzerMutate.h
tools/fuzzing/libfuzzer/FuzzerOptions.h
tools/fuzzing/libfuzzer/FuzzerShmemFuchsia.cpp
tools/fuzzing/libfuzzer/FuzzerShmemPosix.cpp
tools/fuzzing/libfuzzer/FuzzerShmemWindows.cpp
tools/fuzzing/libfuzzer/FuzzerTracePC.cpp
tools/fuzzing/libfuzzer/FuzzerTracePC.h
tools/fuzzing/libfuzzer/FuzzerTraceState.cpp
tools/fuzzing/libfuzzer/FuzzerUtil.cpp
tools/fuzzing/libfuzzer/FuzzerUtil.h
tools/fuzzing/libfuzzer/FuzzerUtilDarwin.cpp
tools/fuzzing/libfuzzer/FuzzerUtilFuchsia.cpp
tools/fuzzing/libfuzzer/FuzzerUtilLinux.cpp
tools/fuzzing/libfuzzer/FuzzerUtilPosix.cpp
tools/fuzzing/libfuzzer/FuzzerUtilWindows.cpp
tools/fuzzing/libfuzzer/FuzzerValueBitMap.h
tools/fuzzing/libfuzzer/moz.build
new file mode 100644
--- /dev/null
+++ b/tools/fuzzing/libfuzzer/FuzzerClangCounters.cpp
@@ -0,0 +1,49 @@
+//===- FuzzerExtraCounters.cpp - Extra coverage counters ------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Coverage counters from Clang's SourceBasedCodeCoverage.
+//===----------------------------------------------------------------------===//
+
+// Support for SourceBasedCodeCoverage is experimental:
+// * Works only for the main binary, not DSOs yet.
+// * Works only on Linux.
+// * Does not implement print_pcs/print_coverage yet.
+// * Is not fully evaluated for performance and sensitivity.
+//   We expect large performance drop due to 64-bit counters,
+//   and *maybe* better sensitivity due to more fine-grained counters.
+//   Preliminary comparison on a single benchmark (RE2) shows
+//   a bit worse sensitivity though.
+
+#include "FuzzerDefs.h"
+
+#if LIBFUZZER_LINUX
+__attribute__((weak)) extern uint64_t __start___llvm_prf_cnts;
+__attribute__((weak)) extern uint64_t __stop___llvm_prf_cnts;
+namespace fuzzer {
+uint64_t *ClangCountersBegin() { return &__start___llvm_prf_cnts; }
+uint64_t *ClangCountersEnd() { return &__stop___llvm_prf_cnts; }
+}  // namespace fuzzer
+#else
+// TODO: Implement on Mac (if the data shows it's worth it).
+//__attribute__((visibility("hidden")))
+//extern uint64_t CountersStart __asm("section$start$__DATA$__llvm_prf_cnts");
+//__attribute__((visibility("hidden")))
+//extern uint64_t CountersEnd __asm("section$end$__DATA$__llvm_prf_cnts");
+namespace fuzzer {
+uint64_t *ClangCountersBegin() { return nullptr; }
+uint64_t *ClangCountersEnd() { return  nullptr; }
+}  // namespace fuzzer
+#endif
+
+namespace fuzzer {
+ATTRIBUTE_NO_SANITIZE_ALL
+void ClearClangCounters() {  // hand-written memset, don't asan-ify.
+  for (auto P = ClangCountersBegin(); P < ClangCountersEnd(); P++)
+    *P = 0;
+}
+}
new file mode 100644
--- /dev/null
+++ b/tools/fuzzing/libfuzzer/FuzzerCommand.h
@@ -0,0 +1,180 @@
+//===- FuzzerCommand.h - Interface representing a process -------*- C++ -* ===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// FuzzerCommand represents a command to run in a subprocess.  It allows callers
+// to manage command line arguments and output and error streams.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_COMMAND_H
+#define LLVM_FUZZER_COMMAND_H
+
+#include "FuzzerDefs.h"
+#include "FuzzerIO.h"
+
+#include <algorithm>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace fuzzer {
+
+class Command final {
+public:
+  // This command line flag is used to indicate that the remaining command line
+  // is immutable, meaning this flag effectively marks the end of the mutable
+  // argument list.
+  static inline const char *ignoreRemainingArgs() {
+    static const char *kIgnoreRemaining = "-ignore_remaining_args=1";
+    return kIgnoreRemaining;
+  }
+
+  Command() : CombinedOutAndErr(false) {}
+
+  explicit Command(const Vector<std::string> &ArgsToAdd)
+      : Args(ArgsToAdd), CombinedOutAndErr(false) {}
+
+  explicit Command(const Command &Other)
+      : Args(Other.Args), CombinedOutAndErr(Other.CombinedOutAndErr),
+        OutputFile(Other.OutputFile) {}
+
+  Command &operator=(const Command &Other) {
+    Args = Other.Args;
+    CombinedOutAndErr = Other.CombinedOutAndErr;
+    OutputFile = Other.OutputFile;
+    return *this;
+  }
+
+  ~Command() {}
+
+  // Returns true if the given Arg is present in Args.  Only checks up to
+  // "-ignore_remaining_args=1".
+  bool hasArgument(const std::string &Arg) const {
+    auto i = endMutableArgs();
+    return std::find(Args.begin(), i, Arg) != i;
+  }
+
+  // Gets all of the current command line arguments, **including** those after
+  // "-ignore-remaining-args=1".
+  const Vector<std::string> &getArguments() const { return Args; }
+
+  // Adds the given argument before "-ignore_remaining_args=1", or at the end
+  // if that flag isn't present.
+  void addArgument(const std::string &Arg) {
+    Args.insert(endMutableArgs(), Arg);
+  }
+
+  // Adds all given arguments before "-ignore_remaining_args=1", or at the end
+  // if that flag isn't present.
+  void addArguments(const Vector<std::string> &ArgsToAdd) {
+    Args.insert(endMutableArgs(), ArgsToAdd.begin(), ArgsToAdd.end());
+  }
+
+  // Removes the given argument from the command argument list.  Ignores any
+  // occurrences after "-ignore_remaining_args=1", if present.
+  void removeArgument(const std::string &Arg) {
+    auto i = endMutableArgs();
+    Args.erase(std::remove(Args.begin(), i, Arg), i);
+  }
+
+  // Like hasArgument, but checks for "-[Flag]=...".
+  bool hasFlag(const std::string &Flag) {
+    std::string Arg("-" + Flag + "=");
+    auto IsMatch = [&](const std::string &Other) {
+      return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
+    };
+    return std::any_of(Args.begin(), endMutableArgs(), IsMatch);
+  }
+
+  // Returns the value of the first instance of a given flag, or an empty string
+  // if the flag isn't present.  Ignores any occurrences after
+  // "-ignore_remaining_args=1", if present.
+  std::string getFlagValue(const std::string &Flag) {
+    std::string Arg("-" + Flag + "=");
+    auto IsMatch = [&](const std::string &Other) {
+      return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
+    };
+    auto i = endMutableArgs();
+    auto j = std::find_if(Args.begin(), i, IsMatch);
+    std::string result;
+    if (j != i) {
+      result = j->substr(Arg.length());
+    }
+    return result;
+  }
+
+  // Like AddArgument, but adds "-[Flag]=[Value]".
+  void addFlag(const std::string &Flag, const std::string &Value) {
+    addArgument("-" + Flag + "=" + Value);
+  }
+
+  // Like RemoveArgument, but removes "-[Flag]=...".
+  void removeFlag(const std::string &Flag) {
+    std::string Arg("-" + Flag + "=");
+    auto IsMatch = [&](const std::string &Other) {
+      return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
+    };
+    auto i = endMutableArgs();
+    Args.erase(std::remove_if(Args.begin(), i, IsMatch), i);
+  }
+
+  // Returns whether the command's stdout is being written to an output file.
+  bool hasOutputFile() const { return !OutputFile.empty(); }
+
+  // Returns the currently set output file.
+  const std::string &getOutputFile() const { return OutputFile; }
+
+  // Configures the command to redirect its output to the name file.
+  void setOutputFile(const std::string &FileName) { OutputFile = FileName; }
+
+  // Returns whether the command's stderr is redirected to stdout.
+  bool isOutAndErrCombined() const { return CombinedOutAndErr; }
+
+  // Sets whether to redirect the command's stderr to its stdout.
+  void combineOutAndErr(bool combine = true) { CombinedOutAndErr = combine; }
+
+  // Returns a string representation of the command.  On many systems this will
+  // be the equivalent command line.
+  std::string toString() const {
+    std::stringstream SS;
+    for (auto arg : getArguments())
+      SS << arg << " ";
+    if (hasOutputFile())
+      SS << ">" << getOutputFile() << " ";
+    if (isOutAndErrCombined())
+      SS << "2>&1 ";
+    std::string result = SS.str();
+    if (!result.empty())
+      result = result.substr(0, result.length() - 1);
+    return result;
+  }
+
+private:
+  Command(Command &&Other) = delete;
+  Command &operator=(Command &&Other) = delete;
+
+  Vector<std::string>::iterator endMutableArgs() {
+    return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
+  }
+
+  Vector<std::string>::const_iterator endMutableArgs() const {
+    return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
+  }
+
+  // The command arguments.  Args[0] is the command name.
+  Vector<std::string> Args;
+
+  // True indicates stderr is redirected to stdout.
+  bool CombinedOutAndErr;
+
+  // If not empty, stdout is redirected to the named file.
+  std::string OutputFile;
+};
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_COMMAND_H
--- a/tools/fuzzing/libfuzzer/FuzzerCorpus.h
+++ b/tools/fuzzing/libfuzzer/FuzzerCorpus.h
@@ -29,24 +29,28 @@ struct InputInfo {
   uint8_t Sha1[kSHA1NumBytes];  // Checksum.
   // Number of features that this input has and no smaller input has.
   size_t NumFeatures = 0;
   size_t Tmp = 0; // Used by ValidateFeatureSet.
   // Stats.
   size_t NumExecutedMutations = 0;
   size_t NumSuccessfullMutations = 0;
   bool MayDeleteFile = false;
+  bool Reduced = false;
+  Vector<uint32_t> UniqFeatureSet;
+  float FeatureFrequencyScore = 1.0;
 };
 
 class InputCorpus {
   static const size_t kFeatureSetSize = 1 << 21;
  public:
   InputCorpus(const std::string &OutputCorpus) : OutputCorpus(OutputCorpus) {
     memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature));
     memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature));
+    memset(FeatureFrequency, 0, sizeof(FeatureFrequency));
   }
   ~InputCorpus() {
     for (auto II : Inputs)
       delete II;
   }
   size_t size() const { return Inputs.size(); }
   size_t SizeInBytes() const {
     size_t Res = 0;
@@ -63,45 +67,92 @@ class InputCorpus {
   size_t MaxInputSize() const {
     size_t Res = 0;
     for (auto II : Inputs)
         Res = std::max(Res, II->U.size());
     return Res;
   }
   bool empty() const { return Inputs.empty(); }
   const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; }
-  void AddToCorpus(const Unit &U, size_t NumFeatures,
-                   bool MayDeleteFile = false) {
+  void AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile,
+                   const Vector<uint32_t> &FeatureSet) {
     assert(!U.empty());
-    uint8_t Hash[kSHA1NumBytes];
     if (FeatureDebug)
       Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures);
-    ComputeSHA1(U.data(), U.size(), Hash);
-    Hashes.insert(Sha1ToString(Hash));
     Inputs.push_back(new InputInfo());
     InputInfo &II = *Inputs.back();
     II.U = U;
     II.NumFeatures = NumFeatures;
     II.MayDeleteFile = MayDeleteFile;
-    memcpy(II.Sha1, Hash, kSHA1NumBytes);
+    II.UniqFeatureSet = FeatureSet;
+    std::sort(II.UniqFeatureSet.begin(), II.UniqFeatureSet.end());
+    ComputeSHA1(U.data(), U.size(), II.Sha1);
+    Hashes.insert(Sha1ToString(II.Sha1));
     UpdateCorpusDistribution();
+    PrintCorpus();
     // ValidateFeatureSet();
   }
 
+  // Debug-only
+  void PrintUnit(const Unit &U) {
+    if (!FeatureDebug) return;
+    for (uint8_t C : U) {
+      if (C != 'F' && C != 'U' && C != 'Z')
+        C = '.';
+      Printf("%c", C);
+    }
+  }
+
+  // Debug-only
+  void PrintFeatureSet(const Vector<uint32_t> &FeatureSet) {
+    if (!FeatureDebug) return;
+    Printf("{");
+    for (uint32_t Feature: FeatureSet)
+      Printf("%u,", Feature);
+    Printf("}");
+  }
+
+  // Debug-only
+  void PrintCorpus() {
+    if (!FeatureDebug) return;
+    Printf("======= CORPUS:\n");
+    int i = 0;
+    for (auto II : Inputs) {
+      if (std::find(II->U.begin(), II->U.end(), 'F') != II->U.end()) {
+        Printf("[%2d] ", i);
+        Printf("%s sz=%zd ", Sha1ToString(II->Sha1).c_str(), II->U.size());
+        PrintUnit(II->U);
+        Printf(" ");
+        PrintFeatureSet(II->UniqFeatureSet);
+        Printf("\n");
+      }
+      i++;
+    }
+  }
+
+  void Replace(InputInfo *II, const Unit &U) {
+    assert(II->U.size() > U.size());
+    Hashes.erase(Sha1ToString(II->Sha1));
+    DeleteFile(*II);
+    ComputeSHA1(U.data(), U.size(), II->Sha1);
+    Hashes.insert(Sha1ToString(II->Sha1));
+    II->U = U;
+    II->Reduced = true;
+    UpdateCorpusDistribution();
+  }
+
   bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); }
   bool HasUnit(const std::string &H) { return Hashes.count(H); }
   InputInfo &ChooseUnitToMutate(Random &Rand) {
     InputInfo &II = *Inputs[ChooseUnitIdxToMutate(Rand)];
     assert(!II.U.empty());
     return II;
   };
 
   // Returns an index of random unit from the corpus to mutate.
-  // Hypothesis: units added to the corpus last are more likely to be
-  // interesting. This function gives more weight to the more recent units.
   size_t ChooseUnitIdxToMutate(Random &Rand) {
     size_t Idx = static_cast<size_t>(CorpusDistribution(Rand));
     assert(Idx < Inputs.size());
     return Idx;
   }
 
   void PrintStats() {
     for (size_t i = 0; i < Inputs.size(); i++) {
@@ -119,26 +170,30 @@ class InputCorpus {
     }
     Printf("\n\t");
     for (size_t i = 0; i < Inputs.size(); i++)
       if (size_t N = Inputs[i]->NumFeatures)
         Printf(" %zd=>%zd ", i, N);
     Printf("\n");
   }
 
+  void DeleteFile(const InputInfo &II) {
+    if (!OutputCorpus.empty() && II.MayDeleteFile)
+      RemoveFile(DirPlusFile(OutputCorpus, Sha1ToString(II.Sha1)));
+  }
+
   void DeleteInput(size_t Idx) {
     InputInfo &II = *Inputs[Idx];
-    if (!OutputCorpus.empty() && II.MayDeleteFile)
-      RemoveFile(DirPlusFile(OutputCorpus, Sha1ToString(II.Sha1)));
+    DeleteFile(II);
     Unit().swap(II.U);
     if (FeatureDebug)
       Printf("EVICTED %zd\n", Idx);
   }
 
-  void AddFeature(size_t Idx, uint32_t NewSize, bool Shrink) {
+  bool AddFeature(size_t Idx, uint32_t NewSize, bool Shrink) {
     assert(NewSize);
     Idx = Idx % kFeatureSetSize;
     uint32_t OldSize = GetFeature(Idx);
     if (OldSize == 0 || (Shrink && OldSize > NewSize)) {
       if (OldSize > 0) {
         size_t OldIdx = SmallestElementPerFeature[Idx];
         InputInfo &II = *Inputs[OldIdx];
         assert(II.NumFeatures > 0);
@@ -148,77 +203,100 @@ class InputCorpus {
       } else {
         NumAddedFeatures++;
       }
       NumUpdatedFeatures++;
       if (FeatureDebug)
         Printf("ADD FEATURE %zd sz %d\n", Idx, NewSize);
       SmallestElementPerFeature[Idx] = Inputs.size();
       InputSizesPerFeature[Idx] = NewSize;
-      CountingFeatures = true;
+      return true;
     }
+    return false;
+  }
+
+  void UpdateFeatureFrequency(size_t Idx) {
+    FeatureFrequency[Idx % kFeatureSetSize]++;
+  }
+  float GetFeatureFrequency(size_t Idx) const {
+    return FeatureFrequency[Idx % kFeatureSetSize];
+  }
+  void UpdateFeatureFrequencyScore(InputInfo *II) {
+    const float kMin = 0.01, kMax = 100.;
+    II->FeatureFrequencyScore = kMin;
+    for (auto Idx : II->UniqFeatureSet)
+      II->FeatureFrequencyScore += 1. / (GetFeatureFrequency(Idx) + 1.);
+    II->FeatureFrequencyScore = Min(II->FeatureFrequencyScore, kMax);
   }
 
   size_t NumFeatures() const { return NumAddedFeatures; }
   size_t NumFeatureUpdates() const { return NumUpdatedFeatures; }
 
-  void ResetFeatureSet() {
-    assert(Inputs.empty());
-    memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature));
-    memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature));
-  }
-
 private:
 
   static const bool FeatureDebug = false;
 
   size_t GetFeature(size_t Idx) const { return InputSizesPerFeature[Idx]; }
 
   void ValidateFeatureSet() {
-    if (!CountingFeatures) return;
     if (FeatureDebug)
       PrintFeatureSet();
     for (size_t Idx = 0; Idx < kFeatureSetSize; Idx++)
       if (GetFeature(Idx))
         Inputs[SmallestElementPerFeature[Idx]]->Tmp++;
     for (auto II: Inputs) {
       if (II->Tmp != II->NumFeatures)
         Printf("ZZZ %zd %zd\n", II->Tmp, II->NumFeatures);
       assert(II->Tmp == II->NumFeatures);
       II->Tmp = 0;
     }
   }
 
   // Updates the probability distribution for the units in the corpus.
   // Must be called whenever the corpus or unit weights are changed.
+  //
+  // Hypothesis: units added to the corpus last are more interesting.
+  //
+  // Hypothesis: inputs with infrequent features are more interesting.
   void UpdateCorpusDistribution() {
     size_t N = Inputs.size();
+    assert(N);
     Intervals.resize(N + 1);
     Weights.resize(N);
     std::iota(Intervals.begin(), Intervals.end(), 0);
-    if (CountingFeatures)
+    for (size_t i = 0; i < N; i++)
+      Weights[i] = Inputs[i]->NumFeatures
+                       ? (i + 1) * Inputs[i]->FeatureFrequencyScore
+                       : 0.;
+    if (FeatureDebug) {
       for (size_t i = 0; i < N; i++)
-        Weights[i] = Inputs[i]->NumFeatures * (i + 1);
-    else
-      std::iota(Weights.begin(), Weights.end(), 1);
+        Printf("%zd ", Inputs[i]->NumFeatures);
+      Printf("NUM\n");
+      for (size_t i = 0; i < N; i++)
+        Printf("%f ", Inputs[i]->FeatureFrequencyScore);
+      Printf("SCORE\n");
+      for (size_t i = 0; i < N; i++)
+        Printf("%f ", Weights[i]);
+      Printf("Weights\n");
+    }
     CorpusDistribution = std::piecewise_constant_distribution<double>(
         Intervals.begin(), Intervals.end(), Weights.begin());
   }
   std::piecewise_constant_distribution<double> CorpusDistribution;
 
-  std::vector<double> Intervals;
-  std::vector<double> Weights;
+  Vector<double> Intervals;
+  Vector<double> Weights;
 
   std::unordered_set<std::string> Hashes;
-  std::vector<InputInfo*> Inputs;
+  Vector<InputInfo*> Inputs;
 
-  bool CountingFeatures = false;
   size_t NumAddedFeatures = 0;
   size_t NumUpdatedFeatures = 0;
   uint32_t InputSizesPerFeature[kFeatureSetSize];
   uint32_t SmallestElementPerFeature[kFeatureSetSize];
+  float FeatureFrequency[kFeatureSetSize];
 
   std::string OutputCorpus;
 };
 
 }  // namespace fuzzer
 
 #endif  // LLVM_FUZZER_CORPUS
--- a/tools/fuzzing/libfuzzer/FuzzerDefs.h
+++ b/tools/fuzzing/libfuzzer/FuzzerDefs.h
@@ -13,39 +13,71 @@
 #define LLVM_FUZZER_DEFS_H
 
 #include <cassert>
 #include <cstddef>
 #include <cstdint>
 #include <cstring>
 #include <string>
 #include <vector>
+#include <set>
+#include <memory>
 
 // Platform detection.
 #ifdef __linux__
 #define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 0
 #define LIBFUZZER_LINUX 1
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 0
 #define LIBFUZZER_WINDOWS 0
 #elif __APPLE__
 #define LIBFUZZER_APPLE 1
+#define LIBFUZZER_FUCHSIA 0
 #define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 0
+#define LIBFUZZER_WINDOWS 0
+#elif __NetBSD__
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 0
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 1
+#define LIBFUZZER_FREEBSD 0
+#define LIBFUZZER_WINDOWS 0
+#elif __FreeBSD__
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 0
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 1
 #define LIBFUZZER_WINDOWS 0
 #elif _WIN32
 #define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 0
 #define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 0
 #define LIBFUZZER_WINDOWS 1
+#elif __Fuchsia__
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 1
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 0
+#define LIBFUZZER_WINDOWS 0
 #else
 #error "Support for your platform has not been implemented"
 #endif
 
 #ifndef __has_attribute
 #  define __has_attribute(x) 0
 #endif
 
-#define LIBFUZZER_POSIX LIBFUZZER_APPLE || LIBFUZZER_LINUX
+#define LIBFUZZER_POSIX (LIBFUZZER_APPLE || LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD)
 
 #ifdef __x86_64
 #  if __has_attribute(target)
 #    define ATTRIBUTE_TARGET_POPCNT __attribute__((target("popcnt")))
 #  else
 #    define ATTRIBUTE_TARGET_POPCNT
 #  endif
 #else
@@ -97,18 +129,33 @@ class MutationDispatcher;
 struct FuzzingOptions;
 class InputCorpus;
 struct InputInfo;
 struct ExternalFunctions;
 
 // Global interface to functions that may or may not be available.
 extern ExternalFunctions *EF;
 
-typedef std::vector<uint8_t> Unit;
-typedef std::vector<Unit> UnitVector;
+// We are using a custom allocator to give a different symbol name to STL
+// containers in order to avoid ODR violations.
+template<typename T>
+  class fuzzer_allocator: public std::allocator<T> {
+    public:
+      template<class Other>
+      struct rebind { typedef fuzzer_allocator<Other> other;  };
+  };
+
+template<typename T>
+using Vector = std::vector<T, fuzzer_allocator<T>>;
+
+template<typename T>
+using Set = std::set<T, std::less<T>, fuzzer_allocator<T>>;
+
+typedef Vector<uint8_t> Unit;
+typedef Vector<Unit> UnitVector;
 typedef int (*UserCallback)(const uint8_t *Data, size_t Size);
 
 int FuzzerDriver(int *argc, char ***argv, UserCallback Callback);
 
 struct ScopedDoingMyOwnMemOrStr {
   ScopedDoingMyOwnMemOrStr() { DoingMyOwnMemOrStr++; }
   ~ScopedDoingMyOwnMemOrStr() { DoingMyOwnMemOrStr--; }
   static int DoingMyOwnMemOrStr;
@@ -118,11 +165,15 @@ inline uint8_t  Bswap(uint8_t x)  { retu
 inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); }
 inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); }
 inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); }
 
 uint8_t *ExtraCountersBegin();
 uint8_t *ExtraCountersEnd();
 void ClearExtraCounters();
 
+uint64_t *ClangCountersBegin();
+uint64_t *ClangCountersEnd();
+void ClearClangCounters();
+
 }  // namespace fuzzer
 
 #endif  // LLVM_FUZZER_DEFS_H
--- a/tools/fuzzing/libfuzzer/FuzzerDictionary.h
+++ b/tools/fuzzing/libfuzzer/FuzzerDictionary.h
@@ -110,18 +110,18 @@ class Dictionary {
   size_t size() const { return Size; }
 
 private:
   DictionaryEntry DE[kMaxDictSize];
   size_t Size = 0;
 };
 
 // Parses one dictionary entry.
-// If successfull, write the enty to Unit and returns true,
+// If successful, write the enty to Unit and returns true,
 // otherwise returns false.
 bool ParseOneDictionaryEntry(const std::string &Str, Unit *U);
 // Parses the dictionary file, fills Units, returns true iff all lines
-// were parsed succesfully.
-bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units);
+// were parsed successfully.
+bool ParseDictionaryFile(const std::string &Text, Vector<Unit> *Units);
 
 }  // namespace fuzzer
 
 #endif  // LLVM_FUZZER_DICTIONARY_H
--- a/tools/fuzzing/libfuzzer/FuzzerDriver.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerDriver.cpp
@@ -4,27 +4,29 @@
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 // FuzzerDriver and flag parsing.
 //===----------------------------------------------------------------------===//
 
+#include "FuzzerCommand.h"
 #include "FuzzerCorpus.h"
+#include "FuzzerIO.h"
 #include "FuzzerInterface.h"
 #include "FuzzerInternal.h"
-#include "FuzzerIO.h"
 #include "FuzzerMutate.h"
 #include "FuzzerRandom.h"
 #include "FuzzerShmem.h"
 #include "FuzzerTracePC.h"
 #include <algorithm>
 #include <atomic>
 #include <chrono>
+#include <cstdlib>
 #include <cstring>
 #include <mutex>
 #include <string>
 #include <thread>
 
 // This function should be present in the libFuzzer so that the client
 // binary can test for its existence.
 extern "C" __attribute__((used)) void __libfuzzer_is_present() {}
@@ -68,17 +70,17 @@ static const FlagDescription FlagDescrip
 #undef FUZZER_FLAG_INT
 #undef FUZZER_FLAG_UNSIGNED
 #undef FUZZER_FLAG_STRING
 };
 
 static const size_t kNumFlags =
     sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]);
 
-static std::vector<std::string> *Inputs;
+static Vector<std::string> *Inputs;
 static std::string *ProgName;
 
 static void PrintHelp() {
   Printf("Usage:\n");
   auto Prog = ProgName->c_str();
   Printf("\nTo run fuzzing pass 0 or more directories.\n");
   Printf("%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog);
 
@@ -144,17 +146,17 @@ static bool ParseOneFlag(const char *Par
   for (size_t F = 0; F < kNumFlags; F++) {
     const char *Name = FlagDescriptions[F].Name;
     const char *Str = FlagValue(Param, Name);
     if (Str)  {
       if (FlagDescriptions[F].IntFlag) {
         int Val = MyStol(Str);
         *FlagDescriptions[F].IntFlag = Val;
         if (Flags.verbosity >= 2)
-          Printf("Flag: %s %d\n", Name, Val);;
+          Printf("Flag: %s %d\n", Name, Val);
         return true;
       } else if (FlagDescriptions[F].UIntFlag) {
         unsigned int Val = std::stoul(Str);
         *FlagDescriptions[F].UIntFlag = Val;
         if (Flags.verbosity >= 2)
           Printf("Flag: %s %u\n", Name, Val);
         return true;
       } else if (FlagDescriptions[F].StrFlag) {
@@ -169,83 +171,93 @@ static bool ParseOneFlag(const char *Par
     }
   }
   Printf("\n\nWARNING: unrecognized flag '%s'; "
          "use -help=1 to list all flags\n\n", Param);
   return true;
 }
 
 // We don't use any library to minimize dependencies.
-static void ParseFlags(const std::vector<std::string> &Args) {
+static void ParseFlags(const Vector<std::string> &Args) {
   for (size_t F = 0; F < kNumFlags; F++) {
     if (FlagDescriptions[F].IntFlag)
       *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default;
     if (FlagDescriptions[F].UIntFlag)
       *FlagDescriptions[F].UIntFlag =
           static_cast<unsigned int>(FlagDescriptions[F].Default);
     if (FlagDescriptions[F].StrFlag)
       *FlagDescriptions[F].StrFlag = nullptr;
   }
-  Inputs = new std::vector<std::string>;
+  Inputs = new Vector<std::string>;
   for (size_t A = 1; A < Args.size(); A++) {
-    if (ParseOneFlag(Args[A].c_str())) continue;
+    if (ParseOneFlag(Args[A].c_str())) {
+      if (Flags.ignore_remaining_args)
+        break;
+      continue;
+    }
     Inputs->push_back(Args[A]);
   }
 }
 
 static std::mutex Mu;
 
 static void PulseThread() {
   while (true) {
     SleepSeconds(600);
     std::lock_guard<std::mutex> Lock(Mu);
     Printf("pulse...\n");
   }
 }
 
-static void WorkerThread(const std::string &Cmd, std::atomic<unsigned> *Counter,
+static void WorkerThread(const Command &BaseCmd, std::atomic<unsigned> *Counter,
                          unsigned NumJobs, std::atomic<bool> *HasErrors) {
   while (true) {
     unsigned C = (*Counter)++;
     if (C >= NumJobs) break;
     std::string Log = "fuzz-" + std::to_string(C) + ".log";
-    std::string ToRun = Cmd + " > " + Log + " 2>&1\n";
-    if (Flags.verbosity)
-      Printf("%s", ToRun.c_str());
-    int ExitCode = ExecuteCommand(ToRun);
+    Command Cmd(BaseCmd);
+    Cmd.setOutputFile(Log);
+    Cmd.combineOutAndErr();
+    if (Flags.verbosity) {
+      std::string CommandLine = Cmd.toString();
+      Printf("%s\n", CommandLine.c_str());
+    }
+    int ExitCode = ExecuteCommand(Cmd);
     if (ExitCode != 0)
       *HasErrors = true;
     std::lock_guard<std::mutex> Lock(Mu);
     Printf("================== Job %u exited with exit code %d ============\n",
            C, ExitCode);
     fuzzer::CopyFileToErr(Log);
   }
 }
 
-std::string CloneArgsWithoutX(const std::vector<std::string> &Args,
+std::string CloneArgsWithoutX(const Vector<std::string> &Args,
                               const char *X1, const char *X2) {
   std::string Cmd;
   for (auto &S : Args) {
     if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2))
       continue;
     Cmd += S + " ";
   }
   return Cmd;
 }
 
-static int RunInMultipleProcesses(const std::vector<std::string> &Args,
+static int RunInMultipleProcesses(const Vector<std::string> &Args,
                                   unsigned NumWorkers, unsigned NumJobs) {
   std::atomic<unsigned> Counter(0);
   std::atomic<bool> HasErrors(false);
-  std::string Cmd = CloneArgsWithoutX(Args, "jobs", "workers");
-  std::vector<std::thread> V;
+  Command Cmd(Args);
+  Cmd.removeFlag("jobs");
+  Cmd.removeFlag("workers");
+  Vector<std::thread> V;
   std::thread Pulse(PulseThread);
   Pulse.detach();
   for (unsigned i = 0; i < NumWorkers; i++)
-    V.push_back(std::thread(WorkerThread, Cmd, &Counter, NumJobs, &HasErrors));
+    V.push_back(std::thread(WorkerThread, std::ref(Cmd), &Counter, NumJobs, &HasErrors));
   for (auto &T : V)
     T.join();
   return HasErrors ? 1 : 0;
 }
 
 static void RssThread(Fuzzer *F, size_t RssLimitMb) {
   while (true) {
     SleepSeconds(1);
@@ -260,17 +272,17 @@ static void StartRssThread(Fuzzer *F, si
   std::thread T(RssThread, F, RssLimitMb);
   T.detach();
 }
 
 int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) {
   Unit U = FileToVector(InputFilePath);
   if (MaxLen && MaxLen < U.size())
     U.resize(MaxLen);
-  F->RunOne(U.data(), U.size());
+  F->ExecuteCallback(U.data(), U.size());
   F->TryDetectingAMemoryLeak(U.data(), U.size(), true);
   return 0;
 }
 
 static bool AllInputsAreFiles() {
   if (Inputs->empty()) return false;
   for (auto &Path : *Inputs)
     if (!IsFile(Path))
@@ -284,45 +296,44 @@ static std::string GetDedupTokenFromFile
   if (Beg == std::string::npos)
     return "";
   auto End = S.find('\n', Beg);
   if (End == std::string::npos)
     return "";
   return S.substr(Beg, End - Beg);
 }
 
-int CleanseCrashInput(const std::vector<std::string> &Args,
+int CleanseCrashInput(const Vector<std::string> &Args,
                        const FuzzingOptions &Options) {
   if (Inputs->size() != 1 || !Flags.exact_artifact_path) {
     Printf("ERROR: -cleanse_crash should be given one input file and"
           " -exact_artifact_path\n");
     exit(1);
   }
   std::string InputFilePath = Inputs->at(0);
   std::string OutputFilePath = Flags.exact_artifact_path;
-  std::string BaseCmd =
-      CloneArgsWithoutX(Args, "cleanse_crash", "cleanse_crash");
+  Command Cmd(Args);
+  Cmd.removeFlag("cleanse_crash");
 
-  auto InputPos = BaseCmd.find(" " + InputFilePath + " ");
-  assert(InputPos != std::string::npos);
-  BaseCmd.erase(InputPos, InputFilePath.size() + 1);
+  assert(Cmd.hasArgument(InputFilePath));
+  Cmd.removeArgument(InputFilePath);
 
   auto LogFilePath = DirPlusFile(
       TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt");
   auto TmpFilePath = DirPlusFile(
       TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".repro");
-  auto LogFileRedirect = " > " + LogFilePath + " 2>&1 ";
-
-  auto Cmd = BaseCmd + " " + TmpFilePath + LogFileRedirect;
+  Cmd.addArgument(TmpFilePath);
+  Cmd.setOutputFile(LogFilePath);
+  Cmd.combineOutAndErr();
 
   std::string CurrentFilePath = InputFilePath;
   auto U = FileToVector(CurrentFilePath);
   size_t Size = U.size();
 
-  const std::vector<uint8_t> ReplacementBytes = {' ', 0xff};
+  const Vector<uint8_t> ReplacementBytes = {' ', 0xff};
   for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) {
     bool Changed = false;
     for (size_t Idx = 0; Idx < Size; Idx++) {
       Printf("CLEANSE[%d]: Trying to replace byte %zd of %zd\n", NumAttempts,
              Idx, Size);
       uint8_t OriginalByte = U[Idx];
       if (ReplacementBytes.end() != std::find(ReplacementBytes.begin(),
                                               ReplacementBytes.end(),
@@ -344,67 +355,71 @@ int CleanseCrashInput(const std::vector<
       }
     }
     if (!Changed) break;
   }
   RemoveFile(LogFilePath);
   return 0;
 }
 
-int MinimizeCrashInput(const std::vector<std::string> &Args,
+int MinimizeCrashInput(const Vector<std::string> &Args,
                        const FuzzingOptions &Options) {
   if (Inputs->size() != 1) {
     Printf("ERROR: -minimize_crash should be given one input file\n");
     exit(1);
   }
   std::string InputFilePath = Inputs->at(0);
-  std::string BaseCmd =
-      CloneArgsWithoutX(Args, "minimize_crash", "exact_artifact_path");
-  auto InputPos = BaseCmd.find(" " + InputFilePath + " ");
-  assert(InputPos != std::string::npos);
-  BaseCmd.erase(InputPos, InputFilePath.size() + 1);
+  Command BaseCmd(Args);
+  BaseCmd.removeFlag("minimize_crash");
+  BaseCmd.removeFlag("exact_artifact_path");
+  assert(BaseCmd.hasArgument(InputFilePath));
+  BaseCmd.removeArgument(InputFilePath);
   if (Flags.runs <= 0 && Flags.max_total_time == 0) {
     Printf("INFO: you need to specify -runs=N or "
            "-max_total_time=N with -minimize_crash=1\n"
            "INFO: defaulting to -max_total_time=600\n");
-    BaseCmd += " -max_total_time=600";
+    BaseCmd.addFlag("max_total_time", "600");
   }
 
   auto LogFilePath = DirPlusFile(
       TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt");
-  auto LogFileRedirect = " > " + LogFilePath + " 2>&1 ";
+  BaseCmd.setOutputFile(LogFilePath);
+  BaseCmd.combineOutAndErr();
 
   std::string CurrentFilePath = InputFilePath;
   while (true) {
     Unit U = FileToVector(CurrentFilePath);
     Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n",
            CurrentFilePath.c_str(), U.size());
 
-    auto Cmd = BaseCmd + " " + CurrentFilePath + LogFileRedirect;
+    Command Cmd(BaseCmd);
+    Cmd.addArgument(CurrentFilePath);
 
-    Printf("CRASH_MIN: executing: %s\n", Cmd.c_str());
+    std::string CommandLine = Cmd.toString();
+    Printf("CRASH_MIN: executing: %s\n", CommandLine.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());
     auto DedupToken1 = GetDedupTokenFromFile(LogFilePath);
     if (!DedupToken1.empty())
       Printf("CRASH_MIN: DedupToken1: %s\n", DedupToken1.c_str());
 
     std::string ArtifactPath =
         Flags.exact_artifact_path
             ? Flags.exact_artifact_path
             : Options.ArtifactPrefix + "minimized-from-" + Hash(U);
-    Cmd += " -minimize_crash_internal_step=1 -exact_artifact_path=" +
-        ArtifactPath;
-    Printf("CRASH_MIN: executing: %s\n", Cmd.c_str());
+    Cmd.addFlag("minimize_crash_internal_step", "1");
+    Cmd.addFlag("exact_artifact_path", ArtifactPath);
+    CommandLine = Cmd.toString();
+    Printf("CRASH_MIN: executing: %s\n", CommandLine.c_str());
     ExitCode = ExecuteCommand(Cmd);
     CopyFileToErr(LogFilePath);
     if (ExitCode == 0) {
       if (Flags.exact_artifact_path) {
         CurrentFilePath = Flags.exact_artifact_path;
         WriteToFile(U, CurrentFilePath);
       }
       Printf("CRASH_MIN: failed to minimize beyond %s (%d bytes), exiting\n",
@@ -436,47 +451,45 @@ int MinimizeCrashInputInternalStep(Fuzze
   assert(Inputs->size() == 1);
   std::string InputFilePath = Inputs->at(0);
   Unit U = FileToVector(InputFilePath);
   Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size());
   if (U.size() < 2) {
     Printf("INFO: The input is small enough, exiting\n");
     exit(0);
   }
-  Corpus->AddToCorpus(U, 0);
   F->SetMaxInputLen(U.size());
   F->SetMaxMutationLen(U.size() - 1);
   F->MinimizeCrashLoop(U);
   Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n");
   exit(0);
   return 0;
 }
 
-int AnalyzeDictionary(Fuzzer *F, const std::vector<Unit>& Dict,
+int AnalyzeDictionary(Fuzzer *F, const Vector<Unit>& Dict,
                       UnitVector& Corpus) {
   Printf("Started dictionary minimization (up to %d tests)\n",
          Dict.size() * Corpus.size() * 2);
 
   // Scores and usage count for each dictionary unit.
-  std::vector<int> Scores(Dict.size());
-  std::vector<int> Usages(Dict.size());
+  Vector<int> Scores(Dict.size());
+  Vector<int> Usages(Dict.size());
 
-  std::vector<size_t> InitialFeatures;
-  std::vector<size_t> ModifiedFeatures;
+  Vector<size_t> InitialFeatures;
+  Vector<size_t> ModifiedFeatures;
   for (auto &C : Corpus) {
     // Get coverage for the testcase without modifications.
     F->ExecuteCallback(C.data(), C.size());
     InitialFeatures.clear();
-    TPC.CollectFeatures([&](size_t Feature) -> bool {
+    TPC.CollectFeatures([&](size_t Feature) {
       InitialFeatures.push_back(Feature);
-      return true;
     });
 
     for (size_t i = 0; i < Dict.size(); ++i) {
-      auto Data = C;
+      Vector<uint8_t> Data = C;
       auto StartPos = std::search(Data.begin(), Data.end(),
                                   Dict[i].begin(), Dict[i].end());
       // Skip dictionary unit, if the testcase does not contain it.
       if (StartPos == Data.end())
         continue;
 
       ++Usages[i];
       while (StartPos != Data.end()) {
@@ -487,19 +500,18 @@ int AnalyzeDictionary(Fuzzer *F, const s
 
         StartPos = std::search(EndPos, Data.end(),
                                Dict[i].begin(), Dict[i].end());
       }
 
       // Get coverage for testcase with masked occurrences of dictionary unit.
       F->ExecuteCallback(Data.data(), Data.size());
       ModifiedFeatures.clear();
-      TPC.CollectFeatures([&](size_t Feature) -> bool {
+      TPC.CollectFeatures([&](size_t Feature) {
         ModifiedFeatures.push_back(Feature);
-        return true;
       });
 
       if (InitialFeatures == ModifiedFeatures)
         --Scores[i];
       else
         Scores[i] += 2;
     }
   }
@@ -520,17 +532,17 @@ int AnalyzeDictionary(Fuzzer *F, const s
 
 int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
   using namespace fuzzer;
   assert(argc && argv && "Argument pointers cannot be nullptr");
   std::string Argv0((*argv)[0]);
   EF = new ExternalFunctions();
   if (EF->LLVMFuzzerInitialize)
     EF->LLVMFuzzerInitialize(argc, argv);
-  const std::vector<std::string> Args(*argv, *argv + *argc);
+  const Vector<std::string> Args(*argv, *argv + *argc);
   assert(!Args.empty());
   ProgName = new std::string(Args[0]);
   if (Argv0 != *ProgName) {
     Printf("ERROR: argv[0] has been modified in LLVMFuzzerInitialize\n");
     exit(1);
   }
   ParseFlags(Args);
   if (Flags.help) {
@@ -547,66 +559,70 @@ int FuzzerDriver(int *argc, char ***argv
     Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs);
     if (Flags.workers > 1)
       Printf("Running %u workers\n", Flags.workers);
   }
 
   if (Flags.workers > 0 && Flags.jobs > 0)
     return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs);
 
-  const size_t kMaxSaneLen = 1 << 20;
-  const size_t kMinDefaultLen = 64;
   FuzzingOptions Options;
   Options.Verbosity = Flags.verbosity;
   Options.MaxLen = Flags.max_len;
-  Options.ExperimentalLenControl = Flags.experimental_len_control;
-  if (Flags.experimental_len_control && Flags.max_len == 64)
-    Options.MaxLen = 1 << 20;
+  Options.LenControl = Flags.len_control;
   Options.UnitTimeoutSec = Flags.timeout;
   Options.ErrorExitCode = Flags.error_exitcode;
   Options.TimeoutExitCode = Flags.timeout_exitcode;
   Options.MaxTotalTimeSec = Flags.max_total_time;
   Options.DoCrossOver = Flags.cross_over;
   Options.MutateDepth = Flags.mutate_depth;
+  Options.ReduceDepth = Flags.reduce_depth;
   Options.UseCounters = Flags.use_counters;
-  Options.UseIndirCalls = Flags.use_indir_calls;
   Options.UseMemmem = Flags.use_memmem;
   Options.UseCmp = Flags.use_cmp;
   Options.UseValueProfile = Flags.use_value_profile;
   Options.Shrink = Flags.shrink;
+  Options.ReduceInputs = Flags.reduce_inputs;
   Options.ShuffleAtStartUp = Flags.shuffle;
   Options.PreferSmall = Flags.prefer_small;
   Options.ReloadIntervalSec = Flags.reload;
   Options.OnlyASCII = Flags.only_ascii;
   Options.DetectLeaks = Flags.detect_leaks;
+  Options.PurgeAllocatorIntervalSec = Flags.purge_allocator_interval;
   Options.TraceMalloc = Flags.trace_malloc;
   Options.RssLimitMb = Flags.rss_limit_mb;
+  Options.MallocLimitMb = Flags.malloc_limit_mb;
+  if (!Options.MallocLimitMb)
+    Options.MallocLimitMb = Options.RssLimitMb;
   if (Flags.runs >= 0)
     Options.MaxNumberOfRuns = Flags.runs;
   if (!Inputs->empty() && !Flags.minimize_crash_internal_step)
     Options.OutputCorpus = (*Inputs)[0];
   Options.ReportSlowUnits = Flags.report_slow_units;
   if (Flags.artifact_prefix)
     Options.ArtifactPrefix = Flags.artifact_prefix;
   if (Flags.exact_artifact_path)
     Options.ExactArtifactPath = Flags.exact_artifact_path;
-  std::vector<Unit> Dictionary;
+  Vector<Unit> Dictionary;
   if (Flags.dict)
     if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary))
       return 1;
   if (Flags.verbosity > 0 && !Dictionary.empty())
     Printf("Dictionary: %zd entries\n", Dictionary.size());
   bool DoPlainRun = AllInputsAreFiles();
   Options.SaveArtifacts =
       !DoPlainRun || Flags.minimize_crash_internal_step;
   Options.PrintNewCovPcs = Flags.print_pcs;
+  Options.PrintNewCovFuncs = Flags.print_funcs;
   Options.PrintFinalStats = Flags.print_final_stats;
   Options.PrintCorpusStats = Flags.print_corpus_stats;
   Options.PrintCoverage = Flags.print_coverage;
   Options.DumpCoverage = Flags.dump_coverage;
+  Options.UseClangCoverage = Flags.use_clang_coverage;
+  Options.UseFeatureFrequency = Flags.use_feature_frequency;
   if (Flags.exit_on_src_pos)
     Options.ExitOnSrcPos = Flags.exit_on_src_pos;
   if (Flags.exit_on_item)
     Options.ExitOnItem = Flags.exit_on_item;
 
   unsigned Seed = Flags.seed;
   // Initialize Seed.
   if (Seed == 0)
@@ -629,18 +645,22 @@ int FuzzerDriver(int *argc, char ***argv
   Options.HandleAbrt = Flags.handle_abrt;
   Options.HandleBus = Flags.handle_bus;
   Options.HandleFpe = Flags.handle_fpe;
   Options.HandleIll = Flags.handle_ill;
   Options.HandleInt = Flags.handle_int;
   Options.HandleSegv = Flags.handle_segv;
   Options.HandleTerm = Flags.handle_term;
   Options.HandleXfsz = Flags.handle_xfsz;
+  Options.HandleUsr1 = Flags.handle_usr1;
+  Options.HandleUsr2 = Flags.handle_usr2;
   SetSignalHandler(Options);
 
+  std::atexit(Fuzzer::StaticExitCallback);
+
   if (Flags.minimize_crash)
     return MinimizeCrashInput(Args, Options);
 
   if (Flags.minimize_crash_internal_step)
     return MinimizeCrashInputInternalStep(F, Corpus);
 
   if (Flags.cleanse_crash)
     return CleanseCrashInput(Args, Options);
@@ -652,17 +672,17 @@ int FuzzerDriver(int *argc, char ***argv
       return 1;
     }
     Printf("INFO: EQUIVALENCE SERVER UP\n");
     while (true) {
       SMR.WaitClient();
       size_t Size = SMR.ReadByteArraySize();
       SMR.WriteByteArray(nullptr, 0);
       const Unit tmp(SMR.GetByteArray(), SMR.GetByteArray() + Size);
-      F->RunOne(tmp.data(), tmp.size());
+      F->ExecuteCallback(tmp.data(), tmp.size());
       SMR.PostServer();
     }
     return 0;
   }
 
   if (auto Name = Flags.use_equivalence_server) {
     if (!SMR.Open(Name)) {
       Printf("ERROR: can't open shared memory region\n");
@@ -689,64 +709,54 @@ int FuzzerDriver(int *argc, char ***argv
            "*** NOTE: fuzzing was not performed, you have only\n"
            "***       executed the target code on a fixed set of inputs.\n"
            "***\n");
     F->PrintFinalStats();
     exit(0);
   }
 
   if (Flags.merge) {
-    if (Options.MaxLen == 0)
-      F->SetMaxInputLen(kMaxSaneLen);
-    if (Flags.merge_control_file)
-      F->CrashResistantMergeInternalStep(Flags.merge_control_file);
-    else
-      F->CrashResistantMerge(Args, *Inputs,
-                             Flags.load_coverage_summary,
-                             Flags.save_coverage_summary);
+    F->CrashResistantMerge(Args, *Inputs,
+                           Flags.load_coverage_summary,
+                           Flags.save_coverage_summary,
+                           Flags.merge_control_file);
     exit(0);
   }
 
-  size_t TemporaryMaxLen = Options.MaxLen ? Options.MaxLen : kMaxSaneLen;
-
-  UnitVector InitialCorpus;
-  for (auto &Inp : *Inputs) {
-    Printf("Loading corpus dir: %s\n", Inp.c_str());
-    ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr,
-                           TemporaryMaxLen, /*ExitOnError=*/false);
+  if (Flags.merge_inner) {
+    const size_t kDefaultMaxMergeLen = 1 << 20;
+    if (Options.MaxLen == 0)
+      F->SetMaxInputLen(kDefaultMaxMergeLen);
+    assert(Flags.merge_control_file);
+    F->CrashResistantMergeInternalStep(Flags.merge_control_file);
+    exit(0);
   }
 
   if (Flags.analyze_dict) {
+    size_t MaxLen = INT_MAX;  // Large max length.
+    UnitVector InitialCorpus;
+    for (auto &Inp : *Inputs) {
+      Printf("Loading corpus dir: %s\n", Inp.c_str());
+      ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr,
+                             MaxLen, /*ExitOnError=*/false);
+    }
+
     if (Dictionary.empty() || Inputs->empty()) {
       Printf("ERROR: can't analyze dict without dict and corpus provided\n");
       return 1;
     }
     if (AnalyzeDictionary(F, Dictionary, InitialCorpus)) {
       Printf("Dictionary analysis failed\n");
       exit(1);
     }
-    Printf("Dictionary analysis suceeded\n");
+    Printf("Dictionary analysis succeeded\n");
     exit(0);
   }
 
-  if (Options.MaxLen == 0) {
-    size_t MaxLen = 0;
-    for (auto &U : InitialCorpus)
-      MaxLen = std::max(U.size(), MaxLen);
-    F->SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxLen), kMaxSaneLen));
-  }
-
-  if (InitialCorpus.empty()) {
-    InitialCorpus.push_back(Unit({'\n'}));  // Valid ASCII input.
-    if (Options.Verbosity)
-      Printf("INFO: A corpus is not provided, starting from an empty corpus\n");
-  }
-  F->ShuffleAndMinimize(&InitialCorpus);
-  InitialCorpus.clear();  // Don't need this memory any more.
-  F->Loop();
+  F->Loop(*Inputs);
 
   if (Flags.verbosity)
     Printf("Done %zd runs in %zd second(s)\n", F->getTotalNumberOfRuns(),
            F->secondsSinceProcessStartUp());
   F->PrintFinalStats();
 
   exit(0);  // Don't let F destroy itself.
 }
--- a/tools/fuzzing/libfuzzer/FuzzerExtFunctions.def
+++ b/tools/fuzzing/libfuzzer/FuzzerExtFunctions.def
@@ -28,16 +28,17 @@ EXT_FUNC(LLVMFuzzerCustomCrossOver, size
 // Sanitizer functions
 EXT_FUNC(__lsan_enable, void, (), false);
 EXT_FUNC(__lsan_disable, void, (), false);
 EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false);
 EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int,
          (void (*malloc_hook)(const volatile void *, size_t),
           void (*free_hook)(const volatile void *)),
          false);
+EXT_FUNC(__sanitizer_purge_allocator, void, (), false);
 EXT_FUNC(__sanitizer_print_memory_profile, int, (size_t, size_t), false);
 EXT_FUNC(__sanitizer_print_stack_trace, void, (), true);
 EXT_FUNC(__sanitizer_symbolize_pc, void,
          (void *, const char *fmt, char *out_buf, size_t out_buf_size), false);
 EXT_FUNC(__sanitizer_get_module_and_offset_for_pc, int,
          (void *pc, char *module_path,
          size_t module_path_len,void **pc_offset), false);
 EXT_FUNC(__sanitizer_set_death_callback, void, (void (*)(void)), true);
--- a/tools/fuzzing/libfuzzer/FuzzerExtFunctionsDlsymWin.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerExtFunctionsDlsymWin.cpp
@@ -9,16 +9,18 @@
 // Implementation using dynamic loading for Windows.
 //===----------------------------------------------------------------------===//
 #include "FuzzerDefs.h"
 #if LIBFUZZER_WINDOWS
 
 #include "FuzzerExtFunctions.h"
 #include "FuzzerIO.h"
 #include "Windows.h"
+
+// This must be included after Windows.h.
 #include "Psapi.h"
 
 namespace fuzzer {
 
 ExternalFunctions::ExternalFunctions() {
   HMODULE Modules[1024];
   DWORD BytesNeeded;
   HANDLE CurrentProcess = GetCurrentProcess();
--- a/tools/fuzzing/libfuzzer/FuzzerExtFunctionsWeak.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerExtFunctionsWeak.cpp
@@ -8,17 +8,17 @@
 //===----------------------------------------------------------------------===//
 // Implementation for Linux. This relies on the linker's support for weak
 // symbols. We don't use this approach on Apple platforms because it requires
 // clients of LibFuzzer to pass ``-U _<symbol_name>`` to the linker to allow
 // weak symbols to be undefined. That is a complication we don't want to expose
 // to clients right now.
 //===----------------------------------------------------------------------===//
 #include "FuzzerDefs.h"
-#if LIBFUZZER_LINUX
+#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FUCHSIA || LIBFUZZER_FREEBSD
 
 #include "FuzzerExtFunctions.h"
 #include "FuzzerIO.h"
 
 extern "C" {
 // Declare these symbols as weak to allow them to be optionally defined.
 #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN)                            \
   __attribute__((weak)) RETURN_TYPE NAME FUNC_SIG
@@ -36,18 +36,19 @@ static void CheckFnPtr(void *FnPtr, cons
   }
 }
 
 namespace fuzzer {
 
 ExternalFunctions::ExternalFunctions() {
 #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN)                            \
   this->NAME = ::NAME;                                                         \
-  CheckFnPtr((void *)::NAME, #NAME, WARN);
+  CheckFnPtr(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(::NAME)),    \
+             #NAME, WARN);
 
 #include "FuzzerExtFunctions.def"
 
 #undef EXT_FUNC
 }
 
 } // namespace fuzzer
 
-#endif // LIBFUZZER_LINUX
+#endif // LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FUSCHIA || LIBFUZZER_FREEBSD
--- a/tools/fuzzing/libfuzzer/FuzzerExtraCounters.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerExtraCounters.cpp
@@ -6,17 +6,17 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 // Extra coverage counters defined by user code.
 //===----------------------------------------------------------------------===//
 
 #include "FuzzerDefs.h"
 
-#if LIBFUZZER_LINUX
+#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD
 __attribute__((weak)) extern uint8_t __start___libfuzzer_extra_counters;
 __attribute__((weak)) extern uint8_t __stop___libfuzzer_extra_counters;
 
 namespace fuzzer {
 uint8_t *ExtraCountersBegin() { return &__start___libfuzzer_extra_counters; }
 uint8_t *ExtraCountersEnd() { return &__stop___libfuzzer_extra_counters; }
 ATTRIBUTE_NO_SANITIZE_ALL
 void ClearExtraCounters() {  // hand-written memset, don't asan-ify.
--- a/tools/fuzzing/libfuzzer/FuzzerFlags.def
+++ b/tools/fuzzing/libfuzzer/FuzzerFlags.def
@@ -12,20 +12,25 @@
 //===----------------------------------------------------------------------===//
 FUZZER_FLAG_INT(verbosity, 1, "Verbosity level.")
 FUZZER_FLAG_UNSIGNED(seed, 0, "Random seed. If 0, seed is generated.")
 FUZZER_FLAG_INT(runs, -1,
             "Number of individual test runs (-1 for infinite runs).")
 FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. "
     "If 0, libFuzzer tries to guess a good value based on the corpus "
     "and reports it. ")
-FUZZER_FLAG_INT(experimental_len_control, 0, "experimental flag")
+FUZZER_FLAG_INT(len_control, 1000, "Try generating small inputs first, "
+  "then try larger inputs over time.  Specifies the rate at which the length "
+  "limit is increased (smaller == faster).  If 0, immediately try inputs with "
+  "size up to max_len.")
 FUZZER_FLAG_INT(cross_over, 1, "If 1, cross over inputs.")
 FUZZER_FLAG_INT(mutate_depth, 5,
             "Apply this number of consecutive mutations to each input.")
+FUZZER_FLAG_INT(reduce_depth, 0, "Experimental/internal. "
+                "Reduce depth if mutations lose unique features")
 FUZZER_FLAG_INT(shuffle, 1, "Shuffle inputs at startup")
 FUZZER_FLAG_INT(prefer_small, 1,
     "If 1, always prefer smaller inputs during the corpus shuffle.")
 FUZZER_FLAG_INT(
     timeout, 1200,
     "Timeout in seconds (if positive). "
     "If one unit runs more than this number of seconds the process will abort.")
 FUZZER_FLAG_INT(error_exitcode, 77, "When libFuzzer itself reports a bug "
@@ -33,17 +38,22 @@ FUZZER_FLAG_INT(error_exitcode, 77, "Whe
 FUZZER_FLAG_INT(timeout_exitcode, 77, "When libFuzzer reports a timeout "
   "this exit code will be used.")
 FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total "
                                    "time in seconds to run the fuzzer.")
 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_STRING(merge_control_file, "internal flag")
+FUZZER_FLAG_STRING(merge_inner, "internal flag")
+FUZZER_FLAG_STRING(merge_control_file,
+                   "Specify a control file used for the merge process. "
+                   "If a merge process gets killed it tries to leave this file "
+                   "in a state suitable for resuming the merge. "
+                   "By default a temporary file will be used.")
 FUZZER_FLAG_STRING(save_coverage_summary, "Experimental:"
                    " save coverage summary to a given file."
                    " Used with -merge=1")
 FUZZER_FLAG_STRING(load_coverage_summary, "Experimental:"
                    " load coverage summary from a given file."
                    " Treat this coverage as belonging to the first corpus. "
                    " Used with -merge=1")
 FUZZER_FLAG_INT(minimize_crash, 0, "If 1, minimizes the provided"
@@ -54,23 +64,24 @@ FUZZER_FLAG_INT(minimize_crash, 0, "If 1
   " the minimized input triggers the same crash."
   )
 FUZZER_FLAG_INT(cleanse_crash, 0, "If 1, tries to cleanse the provided"
   " crash input to make it contain fewer original bytes."
   " Use with -exact_artifact_path to specify the output."
   )
 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_memmem, 1,
                 "Use hints from intercepting memmem, strstr, etc")
 FUZZER_FLAG_INT(use_value_profile, 0,
                 "Experimental. Use value profile to guide fuzzing.")
 FUZZER_FLAG_INT(use_cmp, 1, "Use CMP traces to guide mutations")
-FUZZER_FLAG_INT(shrink, 0, "Experimental. Try to shrink corpus elements.")
+FUZZER_FLAG_INT(shrink, 0, "Experimental. Try to shrink corpus inputs.")
+FUZZER_FLAG_INT(reduce_inputs, 1,
+  "Try to reduce the size of inputs while preserving their full feature sets")
 FUZZER_FLAG_UNSIGNED(jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn"
                           " this number of jobs in separate worker processes"
                           " with stdout/stderr redirected to fuzz-JOB.log.")
 FUZZER_FLAG_UNSIGNED(workers, 0,
             "Number of simultaneous worker processes to run the jobs."
             " If zero, \"min(jobs,NumberOfCpuCores()/2)\" is used.")
 FUZZER_FLAG_INT(reload, 1,
                 "Reload the main corpus every <N> seconds to get new units"
@@ -84,51 +95,59 @@ FUZZER_FLAG_STRING(artifact_prefix, "Wri
                                     "timeout, or slow inputs) as "
                                     "$(artifact_prefix)file")
 FUZZER_FLAG_STRING(exact_artifact_path,
                    "Write the single artifact on failure (crash, timeout) "
                    "as $(exact_artifact_path). This overrides -artifact_prefix "
                    "and will not use checksum in the file name. Do not "
                    "use the same path for several parallel processes.")
 FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.")
+FUZZER_FLAG_INT(print_funcs, 2, "If >=1, print out at most this number of "
+                                "newly covered functions.")
 FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.")
 FUZZER_FLAG_INT(print_corpus_stats, 0,
   "If 1, print statistics on corpus elements at exit.")
 FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text"
                                    " at exit.")
-FUZZER_FLAG_INT(dump_coverage, 0, "If 1, dump coverage information as a"
+FUZZER_FLAG_INT(dump_coverage, 0, "Deprecated."
+                                  " If 1, dump coverage information as a"
                                   " .sancov file at exit.")
 FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.")
 FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGBUS.")
 FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.")
 FUZZER_FLAG_INT(handle_ill, 1, "If 1, try to intercept SIGILL.")
 FUZZER_FLAG_INT(handle_fpe, 1, "If 1, try to intercept SIGFPE.")
 FUZZER_FLAG_INT(handle_int, 1, "If 1, try to intercept SIGINT.")
 FUZZER_FLAG_INT(handle_term, 1, "If 1, try to intercept SIGTERM.")
 FUZZER_FLAG_INT(handle_xfsz, 1, "If 1, try to intercept SIGXFSZ.")
+FUZZER_FLAG_INT(handle_usr1, 1, "If 1, try to intercept SIGUSR1.")
+FUZZER_FLAG_INT(handle_usr2, 1, "If 1, try to intercept SIGUSR2.")
 FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; "
     "if 2, close stderr; if 3, close both. "
-    "Be careful, this will also close e.g. asan's stderr/stdout.")
+    "Be careful, this will also close e.g. stderr of asan.")
 FUZZER_FLAG_INT(detect_leaks, 1, "If 1, and if LeakSanitizer is enabled "
     "try to detect memory leaks during fuzzing (i.e. not only at shut down).")
+FUZZER_FLAG_INT(purge_allocator_interval, 1, "Purge allocator caches and "
+    "quarantines every <N> seconds. When rss_limit_mb is specified (>0), "
+    "purging starts when RSS exceeds 50% of rss_limit_mb. Pass "
+    "purge_allocator_interval=-1 to disable this functionality.")
 FUZZER_FLAG_INT(trace_malloc, 0, "If >= 1 will print all mallocs/frees. "
     "If >= 2 will also print stack traces.")
 FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon"
     "reaching this limit of RSS memory usage.")
+FUZZER_FLAG_INT(malloc_limit_mb, 0, "If non-zero, the fuzzer will exit "
+    "if the target tries to allocate this number of Mb with one malloc call. "
+    "If zero (default) same limit as rss_limit_mb is applied.")
 FUZZER_FLAG_STRING(exit_on_src_pos, "Exit if a newly found PC originates"
     " from the given source location. Example: -exit_on_src_pos=foo.cc:123. "
     "Used primarily for testing libFuzzer itself.")
 FUZZER_FLAG_STRING(exit_on_item, "Exit if an item with a given sha1 sum"
     " was added to the corpus. "
     "Used primarily for testing libFuzzer itself.")
+FUZZER_FLAG_INT(ignore_remaining_args, 0, "If 1, ignore all arguments passed "
+                "after this one. Useful for fuzzers that need to do their own "
+                "argument parsing.")
 
 FUZZER_FLAG_STRING(run_equivalence_server, "Experimental")
 FUZZER_FLAG_STRING(use_equivalence_server, "Experimental")
 FUZZER_FLAG_INT(analyze_dict, 0, "Experimental")
-
-FUZZER_DEPRECATED_FLAG(exit_on_first)
-FUZZER_DEPRECATED_FLAG(save_minimized_corpus)
-FUZZER_DEPRECATED_FLAG(sync_command)
-FUZZER_DEPRECATED_FLAG(sync_timeout)
-FUZZER_DEPRECATED_FLAG(test_single_input)
-FUZZER_DEPRECATED_FLAG(drill)
-FUZZER_DEPRECATED_FLAG(truncate_units)
-FUZZER_DEPRECATED_FLAG(output_csv)
+FUZZER_FLAG_INT(use_clang_coverage, 0, "Experimental")
+FUZZER_FLAG_INT(use_feature_frequency, 0, "Experimental/internal")
deleted file mode 100644
--- a/tools/fuzzing/libfuzzer/FuzzerFnAdapter.h
+++ /dev/null
@@ -1,187 +0,0 @@
-//===- FuzzerAdapter.h - Arbitrary function Fuzzer adapter -------*- C++ -*===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// W A R N I N G :  E X P E R I M E N T A L.
-//
-// Defines an adapter to fuzz functions with (almost) arbitrary signatures.
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_FUZZER_ADAPTER_H
-#define LLVM_FUZZER_ADAPTER_H
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <string>
-#include <tuple>
-#include <vector>
-
-namespace fuzzer {
-
-/// Unpacks bytes from \p Data according to \p F argument types
-/// and calls the function.
-/// Use to automatically adapt LLVMFuzzerTestOneInput interface to
-/// a specific function.
-/// Supported argument types: primitive types, std::vector<uint8_t>.
-template <typename Fn> bool Adapt(Fn F, const uint8_t *Data, size_t Size);
-
-// The implementation performs several steps:
-// - function argument types are obtained (Args...)
-// - data is unpacked into std::tuple<Args...> one by one
-// - function is called with std::tuple<Args...> containing arguments.
-namespace impl {
-
-// Single argument unpacking.
-
-template <typename T>
-size_t UnpackPrimitive(const uint8_t *Data, size_t Size, T *Value) {
-  if (Size < sizeof(T))
-    return Size;
-  *Value = *reinterpret_cast<const T *>(Data);
-  return Size - sizeof(T);
-}
-
-/// Unpacks into a given Value and returns the Size - num_consumed_bytes.
-/// Return value equal to Size signals inability to unpack the data (typically
-/// because there are not enough bytes).
-template <typename T>
-size_t UnpackSingle(const uint8_t *Data, size_t Size, T *Value);
-
-#define UNPACK_SINGLE_PRIMITIVE(Type)                                          \
-  template <>                                                                  \
-  size_t UnpackSingle<Type>(const uint8_t *Data, size_t Size, Type *Value) {   \
-    return UnpackPrimitive(Data, Size, Value);                                 \
-  }
-
-UNPACK_SINGLE_PRIMITIVE(char)
-UNPACK_SINGLE_PRIMITIVE(signed char)
-UNPACK_SINGLE_PRIMITIVE(unsigned char)
-
-UNPACK_SINGLE_PRIMITIVE(short int)
-UNPACK_SINGLE_PRIMITIVE(unsigned short int)
-
-UNPACK_SINGLE_PRIMITIVE(int)
-UNPACK_SINGLE_PRIMITIVE(unsigned int)
-
-UNPACK_SINGLE_PRIMITIVE(long int)
-UNPACK_SINGLE_PRIMITIVE(unsigned long int)
-
-UNPACK_SINGLE_PRIMITIVE(bool)
-UNPACK_SINGLE_PRIMITIVE(wchar_t)
-
-UNPACK_SINGLE_PRIMITIVE(float)
-UNPACK_SINGLE_PRIMITIVE(double)
-UNPACK_SINGLE_PRIMITIVE(long double)
-
-#undef UNPACK_SINGLE_PRIMITIVE
-
-template <>
-size_t UnpackSingle<std::vector<uint8_t>>(const uint8_t *Data, size_t Size,
-                                          std::vector<uint8_t> *Value) {
-  if (Size < 1)
-    return Size;
-  size_t Len = std::min(static_cast<size_t>(*Data), Size - 1);
-  std::vector<uint8_t> V(Data + 1, Data + 1 + Len);
-  Value->swap(V);
-  return Size - Len - 1;
-}
-
-template <>
-size_t UnpackSingle<std::string>(const uint8_t *Data, size_t Size,
-    std::string *Value) {
-  if (Size < 1)
-    return Size;
-  size_t Len = std::min(static_cast<size_t>(*Data), Size - 1);
-  std::string S(Data + 1, Data + 1 + Len);
-  Value->swap(S);
-  return Size - Len - 1;
-}
-
-// Unpacking into arbitrary tuple.
-
-// Recursion guard.
-template <int N, typename TupleT>
-typename std::enable_if<N == std::tuple_size<TupleT>::value, bool>::type
-UnpackImpl(const uint8_t *Data, size_t Size, TupleT *Tuple) {
-  return true;
-}
-
-// Unpack tuple elements starting from Nth.
-template <int N, typename TupleT>
-typename std::enable_if<N < std::tuple_size<TupleT>::value, bool>::type
-UnpackImpl(const uint8_t *Data, size_t Size, TupleT *Tuple) {
-  size_t NewSize = UnpackSingle(Data, Size, &std::get<N>(*Tuple));
-  if (NewSize == Size) {
-    return false;
-  }
-
-  return UnpackImpl<N + 1, TupleT>(Data + (Size - NewSize), NewSize, Tuple);
-}
-
-// Unpacks into arbitrary tuple and returns true if successful.
-template <typename... Args>
-bool Unpack(const uint8_t *Data, size_t Size, std::tuple<Args...> *Tuple) {
-  return UnpackImpl<0, std::tuple<Args...>>(Data, Size, Tuple);
-}
-
-// Helper integer sequence templates.
-
-template <int...> struct Seq {};
-
-template <int N, int... S> struct GenSeq : GenSeq<N - 1, N - 1, S...> {};
-
-// GenSeq<N>::type is Seq<0, 1, ..., N-1>
-template <int... S> struct GenSeq<0, S...> { typedef Seq<S...> type; };
-
-// Function signature introspection.
-
-template <typename T> struct FnTraits {};
-
-template <typename ReturnType, typename... Args>
-struct FnTraits<ReturnType (*)(Args...)> {
-  enum { Arity = sizeof...(Args) };
-  typedef std::tuple<Args...> ArgsTupleT;
-};
-
-// Calling a function with arguments in a tuple.
-
-template <typename Fn, int... S>
-void ApplyImpl(Fn F, const typename FnTraits<Fn>::ArgsTupleT &Params,
-               Seq<S...>) {
-  F(std::get<S>(Params)...);
-}
-
-template <typename Fn>
-void Apply(Fn F, const typename FnTraits<Fn>::ArgsTupleT &Params) {
-  // S is Seq<0, ..., Arity-1>
-  auto S = typename GenSeq<FnTraits<Fn>::Arity>::type();
-  ApplyImpl(F, Params, S);
-}
-
-// Unpacking data into arguments tuple of correct type and calling the function.
-template <typename Fn>
-bool UnpackAndApply(Fn F, const uint8_t *Data, size_t Size) {
-  typename FnTraits<Fn>::ArgsTupleT Tuple;
-  if (!Unpack(Data, Size, &Tuple))
-    return false;
-
-  Apply(F, Tuple);
-  return true;
-}
-
-} // namespace impl
-
-template <typename Fn> bool Adapt(Fn F, const uint8_t *Data, size_t Size) {
-  return impl::UnpackAndApply(F, Data, Size);
-}
-
-} // namespace fuzzer
-
-#endif
--- a/tools/fuzzing/libfuzzer/FuzzerIO.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerIO.cpp
@@ -4,17 +4,16 @@
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 // IO functions.
 //===----------------------------------------------------------------------===//
 
-#include "mozilla/Unused.h"
 #include "FuzzerIO.h"
 #include "FuzzerDefs.h"
 #include "FuzzerExtFunctions.h"
 #include <algorithm>
 #include <cstdarg>
 #include <fstream>
 #include <iterator>
 #include <sys/stat.h>
@@ -34,17 +33,19 @@ long GetEpoch(const std::string &Path) {
 Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
   std::ifstream T(Path);
   if (ExitOnError && !T) {
     Printf("No such directory: %s; exiting\n", Path.c_str());
     exit(1);
   }
 
   T.seekg(0, T.end);
-  size_t FileLen = T.tellg();
+  auto EndPos = T.tellg();
+  if (EndPos < 0) return {};
+  size_t FileLen = EndPos;
   if (MaxSize)
     FileLen = std::min(FileLen, MaxSize);
 
   T.seekg(0, T.beg);
   Unit Res(FileLen);
   T.read(reinterpret_cast<char *>(Res.data()), FileLen);
   return Res;
 }
@@ -58,38 +59,47 @@ std::string FileToString(const std::stri
 void CopyFileToErr(const std::string &Path) {
   Printf("%s", FileToString(Path).c_str());
 }
 
 void WriteToFile(const Unit &U, const std::string &Path) {
   // Use raw C interface because this function may be called from a sig handler.
   FILE *Out = fopen(Path.c_str(), "w");
   if (!Out) return;
-  mozilla::Unused << fwrite(U.data(), sizeof(U[0]), U.size(), Out);
+  fwrite(U.data(), sizeof(U[0]), U.size(), Out);
   fclose(Out);
 }
 
-void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V,
+void ReadDirToVectorOfUnits(const char *Path, Vector<Unit> *V,
                             long *Epoch, size_t MaxSize, bool ExitOnError) {
   long E = Epoch ? *Epoch : 0;
-  std::vector<std::string> Files;
+  Vector<std::string> Files;
   ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true);
   size_t NumLoaded = 0;
   for (size_t i = 0; i < Files.size(); i++) {
     auto &X = Files[i];
     if (Epoch && GetEpoch(X) < E) continue;
     NumLoaded++;
     if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024)
       Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path);
     auto S = FileToVector(X, MaxSize, ExitOnError);
     if (!S.empty())
       V->push_back(S);
   }
 }
 
+
+void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V) {
+  Vector<std::string> Files;
+  ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/true);
+  for (auto &File : Files)
+    if (size_t Size = FileSize(File))
+      V->push_back({File, Size});
+}
+
 std::string DirPlusFile(const std::string &DirPath,
                         const std::string &FileName) {
   return DirPath + GetSeparator() + FileName;
 }
 
 void DupAndCloseStderr() {
   int OutputFd = DuplicateFile(2);
   if (OutputFd > 0) {
--- a/tools/fuzzing/libfuzzer/FuzzerIO.h
+++ b/tools/fuzzing/libfuzzer/FuzzerIO.h
@@ -22,17 +22,17 @@ Unit FileToVector(const std::string &Pat
                   bool ExitOnError = true);
 
 std::string FileToString(const std::string &Path);
 
 void CopyFileToErr(const std::string &Path);
 
 void WriteToFile(const Unit &U, const std::string &Path);
 
-void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V,
+void ReadDirToVectorOfUnits(const char *Path, Vector<Unit> *V,
                             long *Epoch, size_t MaxSize, bool ExitOnError);
 
 // Returns "Dir/FileName" or equivalent for the current OS.
 std::string DirPlusFile(const std::string &DirPath,
                         const std::string &FileName);
 
 // Returns the name of the dir, similar to the 'dirname' utility.
 std::string DirName(const std::string &FileName);
@@ -48,19 +48,28 @@ void CloseStdout();
 
 void Printf(const char *Fmt, ...);
 
 // Print using raw syscalls, useful when printing at early init stages.
 void RawPrint(const char *Str);
 
 // Platform specific functions:
 bool IsFile(const std::string &Path);
+size_t FileSize(const std::string &Path);
 
 void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
-                             std::vector<std::string> *V, bool TopDir);
+                             Vector<std::string> *V, bool TopDir);
+
+struct SizedFile {
+  std::string File;
+  size_t Size;
+  bool operator<(const SizedFile &B) const { return Size < B.Size; }
+};
+
+void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V);
 
 char GetSeparator();
 
 FILE* OpenFile(int Fd, const char *Mode);
 
 int CloseFile(int Fd);
 
 int DuplicateFile(int Fd);
--- a/tools/fuzzing/libfuzzer/FuzzerIOPosix.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerIOPosix.cpp
@@ -4,19 +4,18 @@
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 // IO functions implementation using Posix API.
 //===----------------------------------------------------------------------===//
 #include "FuzzerDefs.h"
-#if LIBFUZZER_POSIX
+#if LIBFUZZER_POSIX || LIBFUZZER_FUCHSIA
 
-#include "mozilla/Unused.h"
 #include "FuzzerExtFunctions.h"
 #include "FuzzerIO.h"
 #include <cstdarg>
 #include <cstdio>
 #include <dirent.h>
 #include <fstream>
 #include <iterator>
 #include <libgen.h>
@@ -28,32 +27,49 @@ namespace fuzzer {
 
 bool IsFile(const std::string &Path) {
   struct stat St;
   if (stat(Path.c_str(), &St))
     return false;
   return S_ISREG(St.st_mode);
 }
 
+static bool IsDirectory(const std::string &Path) {
+  struct stat St;
+  if (stat(Path.c_str(), &St))
+    return false;
+  return S_ISDIR(St.st_mode);
+}
+
+size_t FileSize(const std::string &Path) {
+  struct stat St;
+  if (stat(Path.c_str(), &St))
+    return 0;
+  return St.st_size;
+}
+
 void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
-                             std::vector<std::string> *V, bool TopDir) {
+                             Vector<std::string> *V, bool TopDir) {
   auto E = GetEpoch(Dir);
   if (Epoch)
     if (E && *Epoch >= E) return;
 
   DIR *D = opendir(Dir.c_str());
   if (!D) {
     Printf("No such directory: %s; exiting\n", Dir.c_str());
     exit(1);
   }
   while (auto E = readdir(D)) {
     std::string Path = DirPlusFile(Dir, E->d_name);
-    if (E->d_type == DT_REG || E->d_type == DT_LNK)
+    if (E->d_type == DT_REG || E->d_type == DT_LNK ||
+        (E->d_type == DT_UNKNOWN && IsFile(Path)))
       V->push_back(Path);
-    else if (E->d_type == DT_DIR && *E->d_name != '.')
+    else if ((E->d_type == DT_DIR ||
+             (E->d_type == DT_UNKNOWN && IsDirectory(Path))) &&
+             *E->d_name != '.')
       ListFilesInDirRecursive(Path, Epoch, V, false);
   }
   closedir(D);
   if (Epoch && TopDir)
     *Epoch = E;
 }
 
 char GetSeparator() {
@@ -111,14 +127,14 @@ bool IsInterestingCoverageFile(const std
     return false;
   if (FileName == "<null>")
     return false;
   return true;
 }
 
 
 void RawPrint(const char *Str) {
-  mozilla::Unused << write(2, Str, strlen(Str));
+  write(2, Str, strlen(Str));
 }
 
 }  // namespace fuzzer
 
 #endif // LIBFUZZER_POSIX
--- a/tools/fuzzing/libfuzzer/FuzzerIOWindows.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerIOWindows.cpp
@@ -68,17 +68,17 @@ bool IsFile(const std::string &Path) {
         Path.c_str(), GetLastError());
     return false;
   }
 
   return IsFile(Path, Att);
 }
 
 void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
-                             std::vector<std::string> *V, bool TopDir) {
+                             Vector<std::string> *V, bool TopDir) {
   auto E = GetEpoch(Dir);
   if (Epoch)
     if (E && *Epoch >= E) return;
 
   std::string Path(Dir);
   assert(!Path.empty());
   if (Path.back() != '\\')
       Path.push_back('\\');
@@ -177,32 +177,32 @@ static size_t ParseDrive(const std::stri
 static size_t ParseFileName(const std::string &FileName, const size_t Offset) {
   size_t Pos = Offset;
   const size_t End = FileName.size();
   for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
     ;
   return Pos - Offset;
 }
 
-// Parse a directory ending in separator, like: SomeDir\
+// Parse a directory ending in separator, like: `SomeDir\`
 // Returns number of characters considered if successful.
 static size_t ParseDir(const std::string &FileName, const size_t Offset) {
   size_t Pos = Offset;
   const size_t End = FileName.size();
   if (Pos >= End || IsSeparator(FileName[Pos]))
     return 0;
   for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
     ;
   if (Pos >= End)
     return 0;
   ++Pos; // Include separator.
   return Pos - Offset;
 }
 
-// Parse a servername and share, like: SomeServer\SomeShare\
+// Parse a servername and share, like: `SomeServer\SomeShare\`
 // Returns number of characters considered if successful.
 static size_t ParseServerAndShare(const std::string &FileName,
                                   const size_t Offset) {
   size_t Pos = Offset, Res;
   if (!(Res = ParseDir(FileName, Pos)))
     return 0;
   Pos += Res;
   if (!(Res = ParseDir(FileName, Pos)))
--- a/tools/fuzzing/libfuzzer/FuzzerInterface.h
+++ b/tools/fuzzing/libfuzzer/FuzzerInterface.h
@@ -25,43 +25,47 @@
 #ifdef __cplusplus
 extern "C" {
 #endif  // __cplusplus
 
 // Mandatory user-provided target function.
 // Executes the code under test with [Data, Data+Size) as the input.
 // libFuzzer will invoke this function *many* times with different inputs.
 // Must return 0.
-int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+__attribute__((visibility("default"))) int
+LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
 
 // Optional user-provided initialization function.
 // If provided, this function will be called by libFuzzer once at startup.
 // It may read and modify argc/argv.
 // Must return 0.
-int LLVMFuzzerInitialize(int *argc, char ***argv);
+__attribute__((visibility("default"))) int LLVMFuzzerInitialize(int *argc,
+                                                                char ***argv);
 
 // Optional user-provided custom mutator.
 // Mutates raw data in [Data, Data+Size) inplace.
 // Returns the new size, which is not greater than MaxSize.
 // Given the same Seed produces the same mutation.
-size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize,
-                               unsigned int Seed);
+__attribute__((visibility("default"))) size_t
+LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize,
+                        unsigned int Seed);
 
 // Optional user-provided custom cross-over function.
 // Combines pieces of Data1 & Data2 together into Out.
 // Returns the new size, which is not greater than MaxOutSize.
 // Should produce the same mutation given the same Seed.
-size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1,
-                                 const uint8_t *Data2, size_t Size2,
-                                 uint8_t *Out, size_t MaxOutSize,
-                                 unsigned int Seed);
+__attribute__((visibility("default"))) size_t
+LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1,
+                          const uint8_t *Data2, size_t Size2, uint8_t *Out,
+                          size_t MaxOutSize, unsigned int Seed);
 
 // Experimental, may go away in future.
 // libFuzzer-provided function to be used inside LLVMFuzzerCustomMutator.
 // Mutates raw data in [Data, Data+Size) inplace.
 // Returns the new size, which is not greater than MaxSize.
-size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
+__attribute__((visibility("default"))) size_t
+LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
 
 #ifdef __cplusplus
 }  // extern "C"
 #endif  // __cplusplus
 
 #endif  // LLVM_FUZZER_INTERFACE_H
--- a/tools/fuzzing/libfuzzer/FuzzerInternal.h
+++ b/tools/fuzzing/libfuzzer/FuzzerInternal.h
@@ -30,20 +30,19 @@ namespace fuzzer {
 using namespace std::chrono;
 
 class Fuzzer {
 public:
 
   Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
          FuzzingOptions Options);
   ~Fuzzer();
-  void Loop();
+  void Loop(const Vector<std::string> &CorpusDirs);
+  void ReadAndExecuteSeedCorpora(const Vector<std::string> &CorpusDirs);
   void MinimizeCrashLoop(const Unit &U);
-  void ShuffleAndMinimize(UnitVector *V);
-  void InitializeTraceState();
   void RereadOutputCorpus(size_t MaxSize);
 
   size_t secondsSinceProcessStartUp() {
     return duration_cast<seconds>(system_clock::now() - ProcessStartTime)
         .count();
   }
 
   bool TimedOut() {
@@ -56,28 +55,32 @@ public:
     size_t Seconds = secondsSinceProcessStartUp();
     return Seconds ? TotalNumberOfRuns / Seconds : 0;
   }
 
   size_t getTotalNumberOfRuns() { return TotalNumberOfRuns; }
 
   static void StaticAlarmCallback();
   static void StaticCrashSignalCallback();
+  static void StaticExitCallback();
   static void StaticInterruptCallback();
   static void StaticFileSizeExceedCallback();
+  static void StaticGracefulExitCallback();
 
   void ExecuteCallback(const uint8_t *Data, size_t Size);
-  size_t RunOne(const uint8_t *Data, size_t Size);
+  bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false,
+              InputInfo *II = nullptr, bool *FoundUniqFeatures = nullptr);
 
   // Merge Corpora[1:] into Corpora[0].
-  void Merge(const std::vector<std::string> &Corpora);
-  void CrashResistantMerge(const std::vector<std::string> &Args,
-                           const std::vector<std::string> &Corpora,
+  void Merge(const Vector<std::string> &Corpora);
+  void CrashResistantMerge(const Vector<std::string> &Args,
+                           const Vector<std::string> &Corpora,
                            const char *CoverageSummaryInputPathOrNull,
-                           const char *CoverageSummaryOutputPathOrNull);
+                           const char *CoverageSummaryOutputPathOrNull,
+                           const char *MergeControlFilePathOrNull);
   void CrashResistantMergeInternalStep(const std::string &ControlFilePath);
   MutationDispatcher &GetMD() { return MD; }
   void PrintFinalStats();
   void SetMaxInputLen(size_t MaxInputLen);
   void SetMaxMutationLen(size_t MaxMutationLen);
   void RssLimitCallback();
 
   bool InFuzzingThread() const { return IsMyThread; }
@@ -86,66 +89,67 @@ public:
                                bool DuringInitialCorpusExecution);
 
   void HandleMalloc(size_t Size);
   void AnnounceOutput(const uint8_t *Data, size_t Size);
 
 private:
   void AlarmCallback();
   void CrashCallback();
+  void ExitCallback();
+  void MaybeExitGracefully();
   void CrashOnOverwrittenData();
   void InterruptCallback();
   void MutateAndTestOne();
+  void PurgeAllocator();
   void ReportNewCoverage(InputInfo *II, const Unit &U);
-  size_t RunOne(const Unit &U) { return RunOne(U.data(), U.size()); }
+  void PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size);
   void WriteToOutputCorpus(const Unit &U);
   void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix);
   void PrintStats(const char *Where, const char *End = "\n", size_t Units = 0);
-  void PrintStatusForNewUnit(const Unit &U);
-  void ShuffleCorpus(UnitVector *V);
-  void AddToCorpus(const Unit &U);
+  void PrintStatusForNewUnit(const Unit &U, const char *Text);
   void CheckExitOnSrcPosOrItem();
 
-  // Trace-based fuzzing: we run a unit with some kind of tracing
-  // enabled and record potentially useful mutations. Then
-  // We apply these mutations one by one to the unit and run it again.
-
-  // Start tracing; forget all previously proposed mutations.
-  void StartTraceRecording();
-  // Stop tracing.
-  void StopTraceRecording();
-
   static void StaticDeathCallback();
   void DumpCurrentUnit(const char *Prefix);
   void DeathCallback();
 
   void AllocateCurrentUnitData();
   uint8_t *CurrentUnitData = nullptr;
   std::atomic<size_t> CurrentUnitSize;
   uint8_t BaseSha1[kSHA1NumBytes];  // Checksum of the base unit.
   bool RunningCB = false;
 
+  bool GracefulExitRequested = false;
+
   size_t TotalNumberOfRuns = 0;
   size_t NumberOfNewUnitsAdded = 0;
 
+  size_t LastCorpusUpdateRun = 0;
+
   bool HasMoreMallocsThanFrees = false;
   size_t NumberOfLeakDetectionAttempts = 0;
 
+  system_clock::time_point LastAllocatorPurgeAttemptTime = system_clock::now();
+
   UserCallback CB;
   InputCorpus &Corpus;
   MutationDispatcher &MD;
   FuzzingOptions Options;
 
   system_clock::time_point ProcessStartTime = system_clock::now();
   system_clock::time_point UnitStartTime, UnitStopTime;
   long TimeOfLongestUnitInSeconds = 0;
   long EpochOfLastReadOfOutputCorpus = 0;
 
   size_t MaxInputLen = 0;
   size_t MaxMutationLen = 0;
+  size_t TmpMaxMutationLen = 0;
+
+  Vector<uint32_t> UniqFeatureSetTmp;
 
   // Need to know our own thread.
   static thread_local bool IsMyThread;
 };
 
 } // namespace fuzzer
 
 #endif // LLVM_FUZZER_INTERNAL_H
--- a/tools/fuzzing/libfuzzer/FuzzerLoop.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerLoop.cpp
@@ -5,31 +5,29 @@
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 // Fuzzer's main loop.
 //===----------------------------------------------------------------------===//
 
 #include "FuzzerCorpus.h"
+#include "FuzzerIO.h"
 #include "FuzzerInternal.h"
-#include "FuzzerIO.h"
 #include "FuzzerMutate.h"
 #include "FuzzerRandom.h"
 #include "FuzzerShmem.h"
 #include "FuzzerTracePC.h"
 #include <algorithm>
 #include <cstring>
 #include <memory>
+#include <mutex>
 #include <set>
 
 #if defined(__has_include)
-#if __has_include(<sanitizer / coverage_interface.h>)
-#include <sanitizer/coverage_interface.h>
-#endif
 #if __has_include(<sanitizer / lsan_interface.h>)
 #include <sanitizer/lsan_interface.h>
 #endif
 #endif
 
 #define NO_SANITIZE_MEMORY
 #if defined(__has_feature)
 #if __has_feature(memory_sanitizer)
@@ -67,44 +65,71 @@ struct MallocFreeTracer {
     Mallocs = 0;
     Frees = 0;
     TraceLevel = 0;
     return Result;
   }
   std::atomic<size_t> Mallocs;
   std::atomic<size_t> Frees;
   int TraceLevel = 0;
+
+  std::recursive_mutex TraceMutex;
+  bool TraceDisabled = false;
 };
 
 static MallocFreeTracer AllocTracer;
 
+// Locks printing and avoids nested hooks triggered from mallocs/frees in
+// sanitizer.
+class TraceLock {
+public:
+  TraceLock() : Lock(AllocTracer.TraceMutex) {
+    AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled;
+  }
+  ~TraceLock() { AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled; }
+
+  bool IsDisabled() const {
+    // This is already inverted value.
+    return !AllocTracer.TraceDisabled;
+  }
+
+private:
+  std::lock_guard<std::recursive_mutex> Lock;
+};
+
 ATTRIBUTE_NO_SANITIZE_MEMORY
 void MallocHook(const volatile void *ptr, size_t size) {
   size_t N = AllocTracer.Mallocs++;
   F->HandleMalloc(size);
   if (int TraceLevel = AllocTracer.TraceLevel) {
+    TraceLock Lock;
+    if (Lock.IsDisabled())
+      return;
     Printf("MALLOC[%zd] %p %zd\n", N, ptr, size);
     if (TraceLevel >= 2 && EF)
       EF->__sanitizer_print_stack_trace();
   }
 }
 
 ATTRIBUTE_NO_SANITIZE_MEMORY
 void FreeHook(const volatile void *ptr) {
   size_t N = AllocTracer.Frees++;
   if (int TraceLevel = AllocTracer.TraceLevel) {
+    TraceLock Lock;
+    if (Lock.IsDisabled())
+      return;
     Printf("FREE[%zd]   %p\n", N, ptr);
     if (TraceLevel >= 2 && EF)
       EF->__sanitizer_print_stack_trace();
   }
 }
 
 // Crash on a single malloc that exceeds the rss limit.
 void Fuzzer::HandleMalloc(size_t Size) {
-  if (!Options.RssLimitMb || (Size >> 20) < (size_t)Options.RssLimitMb)
+  if (!Options.MallocLimitMb || (Size >> 20) < (size_t)Options.MallocLimitMb)
     return;
   Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(),
          Size);
   Printf("   To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
   if (EF->__sanitizer_print_stack_trace)
     EF->__sanitizer_print_stack_trace();
   DumpCurrentUnit("oom-");
   Printf("SUMMARY: libFuzzer: out-of-memory\n");
@@ -112,51 +137,53 @@ void Fuzzer::HandleMalloc(size_t Size) {
   _Exit(Options.ErrorExitCode); // Stop right now.
 }
 
 Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
                FuzzingOptions Options)
     : CB(CB), Corpus(Corpus), MD(MD), Options(Options) {
   if (EF->__sanitizer_set_death_callback)
     EF->__sanitizer_set_death_callback(StaticDeathCallback);
-  InitializeTraceState();
   assert(!F);
   F = this;
   TPC.ResetMaps();
   IsMyThread = true;
   if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks)
     EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);
   TPC.SetUseCounters(Options.UseCounters);
   TPC.SetUseValueProfile(Options.UseValueProfile);
-  TPC.SetPrintNewPCs(Options.PrintNewCovPcs);
+  TPC.SetUseClangCoverage(Options.UseClangCoverage);
 
   if (Options.Verbosity)
     TPC.PrintModuleInfo();
   if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec)
     EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus);
   MaxInputLen = MaxMutationLen = Options.MaxLen;
+  TmpMaxMutationLen = Max(size_t(4), Corpus.MaxInputSize());
   AllocateCurrentUnitData();
   CurrentUnitSize = 0;
   memset(BaseSha1, 0, sizeof(BaseSha1));
 }
 
-Fuzzer::~Fuzzer() { }
+Fuzzer::~Fuzzer() {}
 
 void Fuzzer::AllocateCurrentUnitData() {
-  if (CurrentUnitData || MaxInputLen == 0) return;
+  if (CurrentUnitData || MaxInputLen == 0)
+    return;
   CurrentUnitData = new uint8_t[MaxInputLen];
 }
 
 void Fuzzer::StaticDeathCallback() {
   assert(F);
   F->DeathCallback();
 }
 
 void Fuzzer::DumpCurrentUnit(const char *Prefix) {
-  if (!CurrentUnitData) return;  // Happens when running individual inputs.
+  if (!CurrentUnitData)
+    return; // Happens when running individual inputs.
   MD.PrintMutationSequence();
   Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str());
   size_t UnitSize = CurrentUnitSize;
   if (UnitSize <= kMaxUnitSizeToPrint) {
     PrintHexArray(CurrentUnitData, UnitSize, "\n");
     PrintASCII(CurrentUnitData, UnitSize, "\n");
   }
   WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize},
@@ -174,51 +201,82 @@ void Fuzzer::StaticAlarmCallback() {
   F->AlarmCallback();
 }
 
 void Fuzzer::StaticCrashSignalCallback() {
   assert(F);
   F->CrashCallback();
 }
 
+void Fuzzer::StaticExitCallback() {
+  assert(F);
+  F->ExitCallback();
+}
+
 void Fuzzer::StaticInterruptCallback() {
   assert(F);
   F->InterruptCallback();
 }
 
+void Fuzzer::StaticGracefulExitCallback() {
+  assert(F);
+  F->GracefulExitRequested = true;
+  Printf("INFO: signal received, trying to exit gracefully\n");
+}
+
 void Fuzzer::StaticFileSizeExceedCallback() {
   Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid());
   exit(1);
 }
 
 void Fuzzer::CrashCallback() {
   Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid());
   if (EF->__sanitizer_print_stack_trace)
     EF->__sanitizer_print_stack_trace();
   Printf("NOTE: libFuzzer has rudimentary signal handlers.\n"
          "      Combine libFuzzer with AddressSanitizer or similar for better "
          "crash reports.\n");
   Printf("SUMMARY: libFuzzer: deadly signal\n");
   DumpCurrentUnit("crash-");
   PrintFinalStats();
-  _Exit(Options.ErrorExitCode);  // Stop right now.
+  _Exit(Options.ErrorExitCode); // Stop right now.
+}
+
+void Fuzzer::ExitCallback() {
+  if (!RunningCB)
+    return; // This exit did not come from the user callback
+  Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid());
+  if (EF->__sanitizer_print_stack_trace)
+    EF->__sanitizer_print_stack_trace();
+  Printf("SUMMARY: libFuzzer: fuzz target exited\n");
+  DumpCurrentUnit("crash-");
+  PrintFinalStats();
+  _Exit(Options.ErrorExitCode);
+}
+
+void Fuzzer::MaybeExitGracefully() {
+  if (!GracefulExitRequested) return;
+  Printf("==%lu== INFO: libFuzzer: exiting as requested\n", GetPid());
+  PrintFinalStats();
+  _Exit(0);
 }
 
 void Fuzzer::InterruptCallback() {
   Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid());
   PrintFinalStats();
-  _Exit(0);  // Stop right now, don't perform any at-exit actions.
+  _Exit(0); // Stop right now, don't perform any at-exit actions.
 }
 
 NO_SANITIZE_MEMORY
 void Fuzzer::AlarmCallback() {
   assert(Options.UnitTimeoutSec > 0);
   // In Windows Alarm callback is executed by a different thread.
 #if !LIBFUZZER_WINDOWS
-  if (!InFuzzingThread()) return;
+  if (!InFuzzingThread())
+    return;
 #endif
   if (!RunningCB)
     return; // We have not started running units yet.
   size_t Seconds =
       duration_cast<seconds>(system_clock::now() - UnitStartTime).count();
   if (Seconds == 0)
     return;
   if (Options.Verbosity >= 2)
@@ -254,171 +312,170 @@ void Fuzzer::RssLimitCallback() {
 void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) {
   size_t ExecPerSec = execPerSec();
   if (!Options.Verbosity)
     return;
   Printf("#%zd\t%s", TotalNumberOfRuns, Where);
   if (size_t N = TPC.GetTotalPCCoverage())
     Printf(" cov: %zd", N);
   if (size_t N = Corpus.NumFeatures())
-    Printf( " ft: %zd", N);
+    Printf(" ft: %zd", N);
   if (!Corpus.empty()) {
     Printf(" corp: %zd", Corpus.NumActiveUnits());
     if (size_t N = Corpus.SizeInBytes()) {
-      if (N < (1<<14))
+      if (N < (1 << 14))
         Printf("/%zdb", N);
       else if (N < (1 << 24))
         Printf("/%zdKb", N >> 10);
       else
         Printf("/%zdMb", N >> 20);
     }
   }
+  if (TmpMaxMutationLen)
+    Printf(" lim: %zd", TmpMaxMutationLen);
   if (Units)
     Printf(" units: %zd", Units);
 
   Printf(" exec/s: %zd", ExecPerSec);
   Printf(" rss: %zdMb", GetPeakRSSMb());
   Printf("%s", End);
 }
 
 void Fuzzer::PrintFinalStats() {
   if (Options.PrintCoverage)
     TPC.PrintCoverage();
   if (Options.DumpCoverage)
     TPC.DumpCoverage();
   if (Options.PrintCorpusStats)
     Corpus.PrintStats();
-  if (!Options.PrintFinalStats) return;
+  if (!Options.PrintFinalStats)
+    return;
   size_t ExecPerSec = execPerSec();
   Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns);
   Printf("stat::average_exec_per_sec:     %zd\n", ExecPerSec);
   Printf("stat::new_units_added:          %zd\n", NumberOfNewUnitsAdded);
   Printf("stat::slowest_unit_time_sec:    %zd\n", TimeOfLongestUnitInSeconds);
   Printf("stat::peak_rss_mb:              %zd\n", GetPeakRSSMb());
 }
 
 void Fuzzer::SetMaxInputLen(size_t MaxInputLen) {
   assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0.
   assert(MaxInputLen);
   this->MaxInputLen = MaxInputLen;
   this->MaxMutationLen = MaxInputLen;
   AllocateCurrentUnitData();
-  Printf("INFO: -max_len is not provided, using %zd\n", MaxInputLen);
+  Printf("INFO: -max_len is not provided; "
+         "libFuzzer will not generate inputs larger than %zd bytes\n",
+         MaxInputLen);
 }
 
 void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) {
   assert(MaxMutationLen && MaxMutationLen <= MaxInputLen);
   this->MaxMutationLen = MaxMutationLen;
 }
 
 void Fuzzer::CheckExitOnSrcPosOrItem() {
   if (!Options.ExitOnSrcPos.empty()) {
-    static auto *PCsSet = new std::set<uintptr_t>;
-    for (size_t i = 1, N = TPC.GetNumPCs(); i < N; i++) {
-      uintptr_t PC = TPC.GetPC(i);
-      if (!PC) continue;
-      if (!PCsSet->insert(PC).second) continue;
-      std::string Descr = DescribePC("%L", PC);
+    static auto *PCsSet = new Set<uintptr_t>;
+    auto HandlePC = [&](uintptr_t PC) {
+      if (!PCsSet->insert(PC).second)
+        return;
+      std::string Descr = DescribePC("%F %L", PC + 1);
       if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) {
         Printf("INFO: found line matching '%s', exiting.\n",
                Options.ExitOnSrcPos.c_str());
         _Exit(0);
       }
-    }
+    };
+    TPC.ForEachObservedPC(HandlePC);
   }
   if (!Options.ExitOnItem.empty()) {
     if (Corpus.HasUnit(Options.ExitOnItem)) {
       Printf("INFO: found item with checksum '%s', exiting.\n",
              Options.ExitOnItem.c_str());
       _Exit(0);
     }
   }
 }
 
 void Fuzzer::RereadOutputCorpus(size_t MaxSize) {
-  if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return;
-  std::vector<Unit> AdditionalCorpus;
+  if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec)
+    return;
+  Vector<Unit> AdditionalCorpus;
   ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus,
                          &EpochOfLastReadOfOutputCorpus, MaxSize,
                          /*ExitOnError*/ false);
   if (Options.Verbosity >= 2)
     Printf("Reload: read %zd new units.\n", AdditionalCorpus.size());
   bool Reloaded = false;
   for (auto &U : AdditionalCorpus) {
     if (U.size() > MaxSize)
       U.resize(MaxSize);
     if (!Corpus.HasUnit(U)) {
-      if (size_t NumFeatures = RunOne(U)) {
+      if (RunOne(U.data(), U.size())) {
         CheckExitOnSrcPosOrItem();
-        Corpus.AddToCorpus(U, NumFeatures);
         Reloaded = true;
       }
     }
   }
   if (Reloaded)
     PrintStats("RELOAD");
 }
 
-void Fuzzer::ShuffleCorpus(UnitVector *V) {
-  std::shuffle(V->begin(), V->end(), MD.GetRand());
-  if (Options.PreferSmall)
-    std::stable_sort(V->begin(), V->end(), [](const Unit &A, const Unit &B) {
-      return A.size() < B.size();
-    });
-}
-
-void Fuzzer::ShuffleAndMinimize(UnitVector *InitialCorpus) {
-  Printf("#0\tREAD units: %zd\n", InitialCorpus->size());
-  if (Options.ShuffleAtStartUp)
-    ShuffleCorpus(InitialCorpus);
-
-  // Test the callback with empty input and never try it again.
-  uint8_t dummy;
-  ExecuteCallback(&dummy, 0);
-
-  for (const auto &U : *InitialCorpus) {
-    if (size_t NumFeatures = RunOne(U)) {
-      CheckExitOnSrcPosOrItem();
-      Corpus.AddToCorpus(U, NumFeatures);
-    }
-    TryDetectingAMemoryLeak(U.data(), U.size(),
-                            /*DuringInitialCorpusExecution*/ true);
-  }
-  PrintStats("INITED");
-  if (Corpus.empty()) {
-    Printf("ERROR: no interesting inputs were found. "
-           "Is the code instrumented for coverage? Exiting.\n");
-    exit(1);
-  }
-}
-
-size_t Fuzzer::RunOne(const uint8_t *Data, size_t Size) {
-  if (!Size) return 0;
-  TotalNumberOfRuns++;
-
-  ExecuteCallback(Data, Size);
-
-  size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
-  TPC.CollectFeatures([&](size_t Feature) {
-    Corpus.AddFeature(Feature, Size, Options.Shrink);
-  });
-  size_t NumUpdatesAfter = Corpus.NumFeatureUpdates();
-
+void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) {
   auto TimeOfUnit =
       duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
   if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) &&
       secondsSinceProcessStartUp() >= 2)
     PrintStats("pulse ");
   if (TimeOfUnit > TimeOfLongestUnitInSeconds * 1.1 &&
       TimeOfUnit >= Options.ReportSlowUnits) {
     TimeOfLongestUnitInSeconds = TimeOfUnit;
     Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds);
     WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-");
   }
-  return NumUpdatesAfter - NumUpdatesBefore;
+}
+
+bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
+                    InputInfo *II, bool *FoundUniqFeatures) {
+  if (!Size)
+    return false;
+
+  ExecuteCallback(Data, Size);
+
+  UniqFeatureSetTmp.clear();
+  size_t FoundUniqFeaturesOfII = 0;
+  size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
+  TPC.CollectFeatures([&](size_t Feature) {
+    if (Options.UseFeatureFrequency)
+      Corpus.UpdateFeatureFrequency(Feature);
+    if (Corpus.AddFeature(Feature, Size, Options.Shrink))
+      UniqFeatureSetTmp.push_back(Feature);
+    if (Options.ReduceInputs && II)
+      if (std::binary_search(II->UniqFeatureSet.begin(),
+                             II->UniqFeatureSet.end(), Feature))
+        FoundUniqFeaturesOfII++;
+  });
+  if (FoundUniqFeatures)
+    *FoundUniqFeatures = FoundUniqFeaturesOfII;
+  PrintPulseAndReportSlowInput(Data, Size);
+  size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore;
+  if (NumNewFeatures) {
+    TPC.UpdateObservedPCs();
+    Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile,
+                       UniqFeatureSetTmp);
+    return true;
+  }
+  if (II && FoundUniqFeaturesOfII &&
+      FoundUniqFeaturesOfII == II->UniqFeatureSet.size() &&
+      II->U.size() > Size) {
+    Corpus.Replace(II, {Data, Data + Size});
+    return true;
+  }
+  return false;
 }
 
 size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
   assert(InFuzzingThread());
   *Data = CurrentUnitData;
   return CurrentUnitSize;
 }
 
@@ -436,16 +493,18 @@ static bool LooseMemeq(const uint8_t *A,
   if (Size <= 64)
     return !memcmp(A, B, Size);
   // Compare first and last Limit/2 bytes.
   return !memcmp(A, B, Limit / 2) &&
          !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2);
 }
 
 void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
+  TPC.RecordInitialStack();
+  TotalNumberOfRuns++;
   assert(InFuzzingThread());
   if (SMR.IsClient())
     SMR.WriteByteArray(Data, Size);
   // We copy the contents of Unit into a separate heap buffer
   // so that we reliably find buffer overflows in it.
   uint8_t *DataCopy = new uint8_t[Size];
   memcpy(DataCopy, Data, Size);
   if (CurrentUnitData && CurrentUnitData != Data)
@@ -470,67 +529,74 @@ void Fuzzer::ExecuteCallback(const uint8
 void Fuzzer::WriteToOutputCorpus(const Unit &U) {
   if (Options.OnlyASCII)
     assert(IsASCII(U));
   if (Options.OutputCorpus.empty())
     return;
   std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
   WriteToFile(U, Path);
   if (Options.Verbosity >= 2)
-    Printf("Written to %s\n", Path.c_str());
+    Printf("Written %zd bytes to %s\n", U.size(), Path.c_str());
 }
 
 void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) {
   if (!Options.SaveArtifacts)
     return;
   std::string Path = Options.ArtifactPrefix + Prefix + Hash(U);
   if (!Options.ExactArtifactPath.empty())
     Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix.
   WriteToFile(U, Path);
   Printf("artifact_prefix='%s'; Test unit written to %s\n",
          Options.ArtifactPrefix.c_str(), Path.c_str());
   if (U.size() <= kMaxUnitSizeToPrint)
     Printf("Base64: %s\n", Base64(U).c_str());
 }
 
-void Fuzzer::PrintStatusForNewUnit(const Unit &U) {
+void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) {
   if (!Options.PrintNEW)
     return;
-  PrintStats("NEW   ", "");
+  PrintStats(Text, "");
   if (Options.Verbosity) {
-    Printf(" L: %zd ", U.size());
+    Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize());
     MD.PrintMutationSequence();
     Printf("\n");
   }
 }
 
 void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) {
   II->NumSuccessfullMutations++;
   MD.RecordSuccessfulMutationSequence();
-  PrintStatusForNewUnit(U);
+  PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : "NEW   ");
   WriteToOutputCorpus(U);
   NumberOfNewUnitsAdded++;
-  TPC.PrintNewPCs();
+  CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus.
+  LastCorpusUpdateRun = TotalNumberOfRuns;
 }
 
 // Tries detecting a memory leak on the particular input that we have just
 // executed before calling this function.
 void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
                                      bool DuringInitialCorpusExecution) {
-  if (!HasMoreMallocsThanFrees) return;  // mallocs==frees, a leak is unlikely.
-  if (!Options.DetectLeaks) return;
+  if (!HasMoreMallocsThanFrees)
+    return; // mallocs==frees, a leak is unlikely.
+  if (!Options.DetectLeaks)
+    return;
+  if (!DuringInitialCorpusExecution &&
+      TotalNumberOfRuns >= Options.MaxNumberOfRuns)
+    return;
   if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) ||
       !(EF->__lsan_do_recoverable_leak_check))
-    return;  // No lsan.
+    return; // No lsan.
   // Run the target once again, but with lsan disabled so that if there is
   // a real leak we do not report it twice.
   EF->__lsan_disable();
   ExecuteCallback(Data, Size);
   EF->__lsan_enable();
-  if (!HasMoreMallocsThanFrees) return;  // a leak is unlikely.
+  if (!HasMoreMallocsThanFrees)
+    return; // a leak is unlikely.
   if (NumberOfLeakDetectionAttempts++ > 1000) {
     Options.DetectLeaks = false;
     Printf("INFO: libFuzzer disabled leak detection after every mutation.\n"
            "      Most likely the target function accumulates allocated\n"
            "      memory in a global state w/o actually leaking it.\n"
            "      You may try running this binary with -trace_malloc=[12]"
            "      to get a trace of mallocs and frees.\n"
            "      If LeakSanitizer is enabled in this process it will still\n"
@@ -541,107 +607,194 @@ void Fuzzer::TryDetectingAMemoryLeak(con
   // we don't call it too often.
   if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it.
     if (DuringInitialCorpusExecution)
       Printf("\nINFO: a leak has been found in the initial corpus.\n\n");
     Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n");
     CurrentUnitSize = Size;
     DumpCurrentUnit("leak-");
     PrintFinalStats();
-    _Exit(Options.ErrorExitCode);  // not exit() to disable lsan further on.
+    _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on.
   }
 }
 
-static size_t ComputeMutationLen(size_t MaxInputSize, size_t MaxMutationLen,
-                                 Random &Rand) {
-  assert(MaxInputSize <= MaxMutationLen);
-  if (MaxInputSize == MaxMutationLen) return MaxMutationLen;
-  size_t Result = MaxInputSize;
-  size_t R = Rand.Rand();
-  if ((R % (1U << 7)) == 0)
-    Result++;
-  if ((R % (1U << 15)) == 0)
-    Result += 10 + Result / 2;
-  return Min(Result, MaxMutationLen);
-}
-
 void Fuzzer::MutateAndTestOne() {
   MD.StartMutationSequence();
 
   auto &II = Corpus.ChooseUnitToMutate(MD.GetRand());
+  if (Options.UseFeatureFrequency)
+    Corpus.UpdateFeatureFrequencyScore(&II);
   const auto &U = II.U;
   memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1));
   assert(CurrentUnitData);
   size_t Size = U.size();
   assert(Size <= MaxInputLen && "Oversized Unit");
   memcpy(CurrentUnitData, U.data(), Size);
 
   assert(MaxMutationLen > 0);
 
   size_t CurrentMaxMutationLen =
-      Options.ExperimentalLenControl
-          ? ComputeMutationLen(Corpus.MaxInputSize(), MaxMutationLen,
-                               MD.GetRand())
-          : MaxMutationLen;
+      Min(MaxMutationLen, Max(U.size(), TmpMaxMutationLen));
+  assert(CurrentMaxMutationLen > 0);
 
   for (int i = 0; i < Options.MutateDepth; i++) {
     if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
       break;
+    MaybeExitGracefully();
     size_t NewSize = 0;
     NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen);
     assert(NewSize > 0 && "Mutator returned empty unit");
-    assert(NewSize <= CurrentMaxMutationLen && "Mutator return overisized unit");
+    assert(NewSize <= CurrentMaxMutationLen && "Mutator return oversized unit");
     Size = NewSize;
-    if (i == 0)
-      StartTraceRecording();
     II.NumExecutedMutations++;
-    if (size_t NumFeatures = RunOne(CurrentUnitData, Size)) {
-      Corpus.AddToCorpus({CurrentUnitData, CurrentUnitData + Size}, NumFeatures,
-                         /*MayDeleteFile=*/true);
-      ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size});
-      CheckExitOnSrcPosOrItem();
-    }
-    StopTraceRecording();
+
+    bool FoundUniqFeatures = false;
+    bool NewCov = RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II,
+                         &FoundUniqFeatures);
     TryDetectingAMemoryLeak(CurrentUnitData, Size,
                             /*DuringInitialCorpusExecution*/ false);
+    if (NewCov) {
+      ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size});
+      break;  // We will mutate this input more in the next rounds.
+    }
+    if (Options.ReduceDepth && !FoundUniqFeatures)
+        break;
   }
 }
 
-void Fuzzer::Loop() {
-  TPC.InitializePrintNewPCs();
+void Fuzzer::PurgeAllocator() {
+  if (Options.PurgeAllocatorIntervalSec < 0 || !EF->__sanitizer_purge_allocator)
+    return;
+  if (duration_cast<seconds>(system_clock::now() -
+                             LastAllocatorPurgeAttemptTime)
+          .count() < Options.PurgeAllocatorIntervalSec)
+    return;
+
+  if (Options.RssLimitMb <= 0 ||
+      GetPeakRSSMb() > static_cast<size_t>(Options.RssLimitMb) / 2)
+    EF->__sanitizer_purge_allocator();
+
+  LastAllocatorPurgeAttemptTime = system_clock::now();
+}
+
+void Fuzzer::ReadAndExecuteSeedCorpora(const Vector<std::string> &CorpusDirs) {
+  const size_t kMaxSaneLen = 1 << 20;
+  const size_t kMinDefaultLen = 4096;
+  Vector<SizedFile> SizedFiles;
+  size_t MaxSize = 0;
+  size_t MinSize = -1;
+  size_t TotalSize = 0;
+  size_t LastNumFiles = 0;
+  for (auto &Dir : CorpusDirs) {
+    GetSizedFilesFromDir(Dir, &SizedFiles);
+    Printf("INFO: % 8zd files found in %s\n", SizedFiles.size() - LastNumFiles,
+           Dir.c_str());
+    LastNumFiles = SizedFiles.size();
+  }
+  for (auto &File : SizedFiles) {
+    MaxSize = Max(File.Size, MaxSize);
+    MinSize = Min(File.Size, MinSize);
+    TotalSize += File.Size;
+  }
+  if (Options.MaxLen == 0)
+    SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxSize), kMaxSaneLen));
+  assert(MaxInputLen > 0);
+
+  // Test the callback with empty input and never try it again.
+  uint8_t dummy = 0;
+  ExecuteCallback(&dummy, 0);
+
+  if (SizedFiles.empty()) {
+    Printf("INFO: A corpus is not provided, starting from an empty corpus\n");
+    Unit U({'\n'}); // Valid ASCII input.
+    RunOne(U.data(), U.size());
+  } else {
+    Printf("INFO: seed corpus: files: %zd min: %zdb max: %zdb total: %zdb"
+           " rss: %zdMb\n",
+           SizedFiles.size(), MinSize, MaxSize, TotalSize, GetPeakRSSMb());
+    if (Options.ShuffleAtStartUp)
+      std::shuffle(SizedFiles.begin(), SizedFiles.end(), MD.GetRand());
+
+    if (Options.PreferSmall) {
+      std::stable_sort(SizedFiles.begin(), SizedFiles.end());
+      assert(SizedFiles.front().Size <= SizedFiles.back().Size);
+    }
+
+    // Load and execute inputs one by one.
+    for (auto &SF : SizedFiles) {
+      auto U = FileToVector(SF.File, MaxInputLen, /*ExitOnError=*/false);
+      assert(U.size() <= MaxInputLen);
+      RunOne(U.data(), U.size());
+      CheckExitOnSrcPosOrItem();
+      TryDetectingAMemoryLeak(U.data(), U.size(),
+                              /*DuringInitialCorpusExecution*/ true);
+    }
+  }
+
+  PrintStats("INITED");
+  if (Corpus.empty()) {
+    Printf("ERROR: no interesting inputs were found. "
+           "Is the code instrumented for coverage? Exiting.\n");
+    exit(1);
+  }
+}
+
+void Fuzzer::Loop(const Vector<std::string> &CorpusDirs) {
+  ReadAndExecuteSeedCorpora(CorpusDirs);
+  TPC.SetPrintNewPCs(Options.PrintNewCovPcs);
+  TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs);
   system_clock::time_point LastCorpusReload = system_clock::now();
   if (Options.DoCrossOver)
     MD.SetCorpus(&Corpus);
   while (true) {
     auto Now = system_clock::now();
     if (duration_cast<seconds>(Now - LastCorpusReload).count() >=
         Options.ReloadIntervalSec) {
       RereadOutputCorpus(MaxInputLen);
       LastCorpusReload = system_clock::now();
     }
     if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
       break;
-    if (TimedOut()) break;
+    if (TimedOut())
+      break;
+
+    // Update TmpMaxMutationLen
+    if (Options.LenControl) {
+      if (TmpMaxMutationLen < MaxMutationLen &&
+          TotalNumberOfRuns - LastCorpusUpdateRun >
+              Options.LenControl * Log(TmpMaxMutationLen)) {
+        TmpMaxMutationLen =
+            Min(MaxMutationLen, TmpMaxMutationLen + Log(TmpMaxMutationLen));
+        LastCorpusUpdateRun = TotalNumberOfRuns;
+      }
+    } else {
+      TmpMaxMutationLen = MaxMutationLen;
+    }
+
     // Perform several mutations and runs.
     MutateAndTestOne();
+
+    PurgeAllocator();
   }
 
   PrintStats("DONE  ", "\n");
   MD.PrintRecommendedDictionary();
 }
 
 void Fuzzer::MinimizeCrashLoop(const Unit &U) {
-  if (U.size() <= 1) return;
+  if (U.size() <= 1)
+    return;
   while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) {
     MD.StartMutationSequence();
     memcpy(CurrentUnitData, U.data(), U.size());
     for (int i = 0; i < Options.MutateDepth; i++) {
       size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen);
       assert(NewSize > 0 && NewSize <= MaxMutationLen);
-      RunOne(CurrentUnitData, NewSize);
+      ExecuteCallback(CurrentUnitData, NewSize);
+      PrintPulseAndReportSlowInput(CurrentUnitData, NewSize);
       TryDetectingAMemoryLeak(CurrentUnitData, NewSize,
                               /*DuringInitialCorpusExecution*/ false);
     }
   }
 }
 
 void Fuzzer::AnnounceOutput(const uint8_t *Data, size_t Size) {
   if (SMR.IsServer()) {
@@ -652,32 +805,35 @@ void Fuzzer::AnnounceOutput(const uint8_
     size_t OtherSize = SMR.ReadByteArraySize();
     uint8_t *OtherData = SMR.GetByteArray();
     if (Size != OtherSize || memcmp(Data, OtherData, Size) != 0) {
       size_t i = 0;
       for (i = 0; i < Min(Size, OtherSize); i++)
         if (Data[i] != OtherData[i])
           break;
       Printf("==%lu== ERROR: libFuzzer: equivalence-mismatch. Sizes: %zd %zd; "
-             "offset %zd\n", GetPid(), Size, OtherSize, i);
+             "offset %zd\n",
+             GetPid(), Size, OtherSize, i);
       DumpCurrentUnit("mismatch-");
       Printf("SUMMARY: libFuzzer: equivalence-mismatch\n");
       PrintFinalStats();
       _Exit(Options.ErrorExitCode);
     }
   }
 }
 
 } // namespace fuzzer
 
 extern "C" {
 
-size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+__attribute__((visibility("default"))) size_t
+LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
   assert(fuzzer::F);
   return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize);
 }
 
 // Experimental
-void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) {
+__attribute__((visibility("default"))) void
+LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) {
   assert(fuzzer::F);
   fuzzer::F->AnnounceOutput(Data, Size);
 }
-}  // extern "C"
+} // extern "C"
--- a/tools/fuzzing/libfuzzer/FuzzerMain.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerMain.cpp
@@ -11,11 +11,11 @@
 
 #include "FuzzerDefs.h"
 
 extern "C" {
 // This function should be defined by the user.
 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
 }  // extern "C"
 
-int main(int argc, char **argv) {
+__attribute__((visibility("default"))) int main(int argc, char **argv) {
   return fuzzer::FuzzerDriver(&argc, &argv, LLVMFuzzerTestOneInput);
 }
--- a/tools/fuzzing/libfuzzer/FuzzerMerge.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerMerge.cpp
@@ -4,19 +4,20 @@
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 // Merging corpora.
 //===----------------------------------------------------------------------===//
 
-#include "FuzzerInternal.h"
+#include "FuzzerCommand.h"
+#include "FuzzerMerge.h"
 #include "FuzzerIO.h"
-#include "FuzzerMerge.h"
+#include "FuzzerInternal.h"
 #include "FuzzerTracePC.h"
 #include "FuzzerUtil.h"
 
 #include <fstream>
 #include <iterator>
 #include <set>
 #include <sstream>
 
@@ -69,17 +70,17 @@ bool Merger::Parse(std::istream &IS, boo
   for (size_t i = 0; i < NumFiles; i++)
     if (!std::getline(IS, Files[i].Name, '\n'))
       return false;
 
   // Parse STARTED and DONE lines.
   size_t ExpectedStartMarker = 0;
   const size_t kInvalidStartMarker = -1;
   size_t LastSeenStartMarker = kInvalidStartMarker;
-  std::vector<uint32_t> TmpFeatures;
+  Vector<uint32_t> TmpFeatures;
   while (std::getline(IS, Line, '\n')) {
     std::istringstream ISS1(Line);
     std::string Marker;
     size_t N;
     ISS1 >> Marker;
     ISS1 >> N;
     if (Marker == "STARTED") {
       // STARTED FILE_ID FILE_SIZE
@@ -117,33 +118,33 @@ size_t Merger::ApproximateMemoryConsumpt
   size_t Res = 0;
   for (const auto &F: Files)
     Res += sizeof(F) + F.Features.size() * sizeof(F.Features[0]);
   return Res;
 }
 
 // Decides which files need to be merged (add thost to NewFiles).
 // Returns the number of new features added.
-size_t Merger::Merge(const std::set<uint32_t> &InitialFeatures,
-                     std::vector<std::string> *NewFiles) {
+size_t Merger::Merge(const Set<uint32_t> &InitialFeatures,
+                     Vector<std::string> *NewFiles) {
   NewFiles->clear();
   assert(NumFilesInFirstCorpus <= Files.size());
-  std::set<uint32_t> AllFeatures(InitialFeatures);
+  Set<uint32_t> AllFeatures(InitialFeatures);
 
   // What features are in the initial corpus?
   for (size_t i = 0; i < NumFilesInFirstCorpus; i++) {
     auto &Cur = Files[i].Features;
     AllFeatures.insert(Cur.begin(), Cur.end());
   }
   size_t InitialNumFeatures = AllFeatures.size();
 
   // Remove all features that we already know from all other inputs.
   for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) {
     auto &Cur = Files[i].Features;
-    std::vector<uint32_t> Tmp;
+    Vector<uint32_t> Tmp;
     std::set_difference(Cur.begin(), Cur.end(), AllFeatures.begin(),
                         AllFeatures.end(), std::inserter(Tmp, Tmp.begin()));
     Cur.swap(Tmp);
   }
 
   // Sort. Give preference to
   //   * smaller files
   //   * files with more features.
@@ -173,26 +174,26 @@ void Merger::PrintSummary(std::ostream &
     OS << std::hex;
     OS << File.Name << " size: " << File.Size << " features: ";
     for (auto Feature : File.Features)
       OS << " " << Feature;
     OS << "\n";
   }
 }
 
-std::set<uint32_t> Merger::AllFeatures() const {
-  std::set<uint32_t> S;
+Set<uint32_t> Merger::AllFeatures() const {
+  Set<uint32_t> S;
   for (auto &File : Files)
     S.insert(File.Features.begin(), File.Features.end());
   return S;
 }
 
-std::set<uint32_t> Merger::ParseSummary(std::istream &IS) {
+Set<uint32_t> Merger::ParseSummary(std::istream &IS) {
   std::string Line, Tmp;
-  std::set<uint32_t> Res;
+  Set<uint32_t> Res;
   while (std::getline(IS, Line, '\n')) {
     size_t N;
     std::istringstream ISS1(Line);
     ISS1 >> Tmp;  // Name
     ISS1 >> Tmp;  // size:
     assert(Tmp == "size:" && "Corrupt summary file");
     ISS1 >> std::hex;
     ISS1 >> N;    // File Size
@@ -216,89 +217,139 @@ void Fuzzer::CrashResistantMergeInternal
            M.LastFailure.c_str());
 
   Printf("MERGE-INNER: %zd total files;"
          " %zd processed earlier; will process %zd files now\n",
          M.Files.size(), M.FirstNotProcessedFile,
          M.Files.size() - M.FirstNotProcessedFile);
 
   std::ofstream OF(CFPath, std::ofstream::out | std::ofstream::app);
+  Set<size_t> AllFeatures;
   for (size_t i = M.FirstNotProcessedFile; i < M.Files.size(); i++) {
+    MaybeExitGracefully();
     auto U = FileToVector(M.Files[i].Name);
     if (U.size() > MaxInputLen) {
       U.resize(MaxInputLen);
       U.shrink_to_fit();
     }
     std::ostringstream StartedLine;
     // Write the pre-run marker.
     OF << "STARTED " << std::dec << i << " " << U.size() << "\n";
-    OF.flush();  // Flush is important since ExecuteCommand may crash.
+    OF.flush();  // Flush is important since Command::Execute may crash.
     // Run.
     TPC.ResetMaps();
     ExecuteCallback(U.data(), U.size());
-    // Collect coverage.
-    std::set<size_t> Features;
-    TPC.CollectFeatures([&](size_t Feature) -> bool {
-      Features.insert(Feature);
-      return true;
+    // Collect coverage. We are iterating over the files in this order:
+    // * First, files in the initial corpus ordered by size, smallest first.
+    // * Then, all other files, smallest first.
+    // So it makes no sense to record all features for all files, instead we
+    // only record features that were not seen before.
+    Set<size_t> UniqFeatures;
+    TPC.CollectFeatures([&](size_t Feature) {
+      if (AllFeatures.insert(Feature).second)
+        UniqFeatures.insert(Feature);
     });
     // Show stats.
-    TotalNumberOfRuns++;
     if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)))
       PrintStats("pulse ");
     // Write the post-run marker and the coverage.
     OF << "DONE " << i;
-    for (size_t F : Features)
+    for (size_t F : UniqFeatures)
       OF << " " << std::hex << F;
     OF << "\n";
+    OF.flush();
   }
 }
 
-// Outer process. Does not call the target code and thus sohuld not fail.
-void Fuzzer::CrashResistantMerge(const std::vector<std::string> &Args,
-                                 const std::vector<std::string> &Corpora,
-                                 const char *CoverageSummaryInputPathOrNull,
-                                 const char *CoverageSummaryOutputPathOrNull) {
-  if (Corpora.size() <= 1) {
-    Printf("Merge requires two or more corpus dirs\n");
-    return;
-  }
-  std::vector<std::string> AllFiles;
-  ListFilesInDirRecursive(Corpora[0], nullptr, &AllFiles, /*TopDir*/true);
-  size_t NumFilesInFirstCorpus = AllFiles.size();
-  for (size_t i = 1; i < Corpora.size(); i++)
-    ListFilesInDirRecursive(Corpora[i], nullptr, &AllFiles, /*TopDir*/true);
-  Printf("MERGE-OUTER: %zd files, %zd in the initial corpus\n",
-         AllFiles.size(), NumFilesInFirstCorpus);
-  auto CFPath = DirPlusFile(TmpDir(),
-                       "libFuzzerTemp." + std::to_string(GetPid()) + ".txt");
-  // Write the control file.
+static void WriteNewControlFile(const std::string &CFPath,
+                                const Vector<SizedFile> &AllFiles,
+                                size_t NumFilesInFirstCorpus) {
   RemoveFile(CFPath);
   std::ofstream ControlFile(CFPath);
   ControlFile << AllFiles.size() << "\n";
   ControlFile << NumFilesInFirstCorpus << "\n";
-  for (auto &Path: AllFiles)
-    ControlFile << Path << "\n";
+  for (auto &SF: AllFiles)
+    ControlFile << SF.File << "\n";
   if (!ControlFile) {
     Printf("MERGE-OUTER: failed to write to the control file: %s\n",
            CFPath.c_str());
     exit(1);
   }
-  ControlFile.close();
+}
+
+// Outer process. Does not call the target code and thus sohuld not fail.
+void Fuzzer::CrashResistantMerge(const Vector<std::string> &Args,
+                                 const Vector<std::string> &Corpora,
+                                 const char *CoverageSummaryInputPathOrNull,
+                                 const char *CoverageSummaryOutputPathOrNull,
+                                 const char *MergeControlFilePathOrNull) {
+  if (Corpora.size() <= 1) {
+    Printf("Merge requires two or more corpus dirs\n");
+    return;
+  }
+  auto CFPath =
+      MergeControlFilePathOrNull
+          ? MergeControlFilePathOrNull
+          : DirPlusFile(TmpDir(),
+                        "libFuzzerTemp." + std::to_string(GetPid()) + ".txt");
 
-  // Execute the inner process untill it passes.
+  size_t NumAttempts = 0;
+  if (MergeControlFilePathOrNull && FileSize(MergeControlFilePathOrNull)) {
+    Printf("MERGE-OUTER: non-empty control file provided: '%s'\n",
+           MergeControlFilePathOrNull);
+    Merger M;
+    std::ifstream IF(MergeControlFilePathOrNull);
+    if (M.Parse(IF, /*ParseCoverage=*/false)) {
+      Printf("MERGE-OUTER: control file ok, %zd files total,"
+             " first not processed file %zd\n",
+             M.Files.size(), M.FirstNotProcessedFile);
+      if (!M.LastFailure.empty())
+        Printf("MERGE-OUTER: '%s' will be skipped as unlucky "
+               "(merge has stumbled on it the last time)\n",
+               M.LastFailure.c_str());
+      if (M.FirstNotProcessedFile >= M.Files.size()) {
+        Printf("MERGE-OUTER: nothing to do, merge has been completed before\n");
+        exit(0);
+      }
+
+      NumAttempts = M.Files.size() - M.FirstNotProcessedFile;
+    } else {
+      Printf("MERGE-OUTER: bad control file, will overwrite it\n");
+    }
+  }
+
+  if (!NumAttempts) {
+    // The supplied control file is empty or bad, create a fresh one.
+    Vector<SizedFile> AllFiles;
+    GetSizedFilesFromDir(Corpora[0], &AllFiles);
+    size_t NumFilesInFirstCorpus = AllFiles.size();
+    std::sort(AllFiles.begin(), AllFiles.end());
+    for (size_t i = 1; i < Corpora.size(); i++)
+      GetSizedFilesFromDir(Corpora[i], &AllFiles);
+    std::sort(AllFiles.begin() + NumFilesInFirstCorpus, AllFiles.end());
+    Printf("MERGE-OUTER: %zd files, %zd in the initial corpus\n",
+           AllFiles.size(), NumFilesInFirstCorpus);
+    WriteNewControlFile(CFPath, AllFiles, NumFilesInFirstCorpus);
+    NumAttempts = AllFiles.size();
+  }
+
+  // Execute the inner process until it passes.
   // Every inner process should execute at least one input.
-  std::string BaseCmd = CloneArgsWithoutX(Args, "keep-all-flags");
+  Command BaseCmd(Args);
+  BaseCmd.removeFlag("merge");
   bool Success = false;
-  for (size_t i = 1; i <= AllFiles.size(); i++) {
-    Printf("MERGE-OUTER: attempt %zd\n", i);
-    auto ExitCode =
-        ExecuteCommand(BaseCmd + " -merge_control_file=" + CFPath);
+  for (size_t Attempt = 1; Attempt <= NumAttempts; Attempt++) {
+    MaybeExitGracefully();
+    Printf("MERGE-OUTER: attempt %zd\n", Attempt);
+    Command Cmd(BaseCmd);
+    Cmd.addFlag("merge_control_file", CFPath);
+    Cmd.addFlag("merge_inner", "1");
+    auto ExitCode = ExecuteCommand(Cmd);
     if (!ExitCode) {
-      Printf("MERGE-OUTER: succesfull in %zd attempt(s)\n", i);
+      Printf("MERGE-OUTER: succesfull in %zd attempt(s)\n", Attempt);
       Success = true;
       break;
     }
   }
   if (!Success) {
     Printf("MERGE-OUTER: zero succesfull attempts, exiting\n");
     exit(1);
   }
@@ -313,26 +364,27 @@ void Fuzzer::CrashResistantMerge(const s
   Printf("MERGE-OUTER: consumed %zdMb (%zdMb rss) to parse the control file\n",
          M.ApproximateMemoryConsumption() >> 20, GetPeakRSSMb());
   if (CoverageSummaryOutputPathOrNull) {
     Printf("MERGE-OUTER: writing coverage summary for %zd files to %s\n",
            M.Files.size(), CoverageSummaryOutputPathOrNull);
     std::ofstream SummaryOut(CoverageSummaryOutputPathOrNull);
     M.PrintSummary(SummaryOut);
   }
-  std::vector<std::string> NewFiles;
-  std::set<uint32_t> InitialFeatures;
+  Vector<std::string> NewFiles;
+  Set<uint32_t> InitialFeatures;
   if (CoverageSummaryInputPathOrNull) {
     std::ifstream SummaryIn(CoverageSummaryInputPathOrNull);
     InitialFeatures = M.ParseSummary(SummaryIn);
     Printf("MERGE-OUTER: coverage summary loaded from %s, %zd features found\n",
            CoverageSummaryInputPathOrNull, InitialFeatures.size());
   }
   size_t NumNewFeatures = M.Merge(InitialFeatures, &NewFiles);
   Printf("MERGE-OUTER: %zd new files with %zd new features added\n",
          NewFiles.size(), NumNewFeatures);
   for (auto &F: NewFiles)
-    WriteToOutputCorpus(FileToVector(F));
-  // We are done, delete the control file.
-  RemoveFile(CFPath);
+    WriteToOutputCorpus(FileToVector(F, MaxInputLen));
+  // We are done, delete the control file if it was a temporary one.
+  if (!MergeControlFilePathOrNull)
+    RemoveFile(CFPath);
 }
 
 } // namespace fuzzer
--- a/tools/fuzzing/libfuzzer/FuzzerMerge.h
+++ b/tools/fuzzing/libfuzzer/FuzzerMerge.h
@@ -47,34 +47,34 @@
 #include <set>
 #include <vector>
 
 namespace fuzzer {
 
 struct MergeFileInfo {
   std::string Name;
   size_t Size = 0;
-  std::vector<uint32_t> Features;
+  Vector<uint32_t> Features;
 };
 
 struct Merger {
-  std::vector<MergeFileInfo> Files;
+  Vector<MergeFileInfo> Files;
   size_t NumFilesInFirstCorpus = 0;
   size_t FirstNotProcessedFile = 0;
   std::string LastFailure;
 
   bool Parse(std::istream &IS, bool ParseCoverage);
   bool Parse(const std::string &Str, bool ParseCoverage);
   void ParseOrExit(std::istream &IS, bool ParseCoverage);
   void PrintSummary(std::ostream &OS);
-  std::set<uint32_t> ParseSummary(std::istream &IS);
-  size_t Merge(const std::set<uint32_t> &InitialFeatures,
-               std::vector<std::string> *NewFiles);
-  size_t Merge(std::vector<std::string> *NewFiles) {
-    return Merge(std::set<uint32_t>{}, NewFiles);
+  Set<uint32_t> ParseSummary(std::istream &IS);
+  size_t Merge(const Set<uint32_t> &InitialFeatures,
+               Vector<std::string> *NewFiles);
+  size_t Merge(Vector<std::string> *NewFiles) {
+    return Merge(Set<uint32_t>{}, NewFiles);
   }
   size_t ApproximateMemoryConsumption() const;
-  std::set<uint32_t> AllFeatures() const;
+  Set<uint32_t> AllFeatures() const;
 };
 
 }  // namespace fuzzer
 
 #endif  // LLVM_FUZZER_MERGE_H
--- a/tools/fuzzing/libfuzzer/FuzzerMutate.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerMutate.cpp
@@ -4,21 +4,21 @@
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 // Mutate a test input.
 //===----------------------------------------------------------------------===//
 
+#include "FuzzerMutate.h"
 #include "FuzzerCorpus.h"
 #include "FuzzerDefs.h"
 #include "FuzzerExtFunctions.h"
 #include "FuzzerIO.h"
-#include "FuzzerMutate.h"
 #include "FuzzerOptions.h"
 
 namespace fuzzer {
 
 const size_t Dictionary::kMaxDictSize;
 
 static void PrintASCII(const Word &W, const char *PrintAfter) {
   PrintASCII(W.data(), W.size(), PrintAfter);
@@ -38,18 +38,16 @@ MutationDispatcher::MutationDispatcher(R
           {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"},
           {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"},
           {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"},
           {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"},
           {&MutationDispatcher::Mutate_CopyPart, "CopyPart"},
           {&MutationDispatcher::Mutate_CrossOver, "CrossOver"},
           {&MutationDispatcher::Mutate_AddWordFromManualDictionary,
            "ManualDict"},
-          {&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary,
-           "TempAutoDict"},
           {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
            "PersAutoDict"},
       });
   if(Options.UseCmp)
     DefaultMutators.push_back(
         {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"});
 
   if (EF->LLVMFuzzerCustomMutator)
@@ -59,17 +57,17 @@ MutationDispatcher::MutationDispatcher(R
 
   if (EF->LLVMFuzzerCustomCrossOver)
     Mutators.push_back(
         {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"});
 }
 
 static char RandCh(Random &Rand) {
   if (Rand.RandBool()) return Rand(256);
-  const char *Special = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00";
+  const char Special[] = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00";
   return Special[Rand(sizeof(Special) - 1)];
 }
 
 size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size,
                                          size_t MaxSize) {
   return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand());
 }
 
@@ -160,21 +158,16 @@ size_t MutationDispatcher::Mutate_Change
 }
 
 size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data,
                                                               size_t Size,
                                                               size_t MaxSize) {
   return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize);
 }
 
-size_t MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary(
-    uint8_t *Data, size_t Size, size_t MaxSize) {
-  return AddWordFromDictionary(TempAutoDictionary, Data, Size, MaxSize);
-}
-
 size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size,
                                                 size_t MaxSize,
                                                 DictionaryEntry &DE) {
   const Word &W = DE.GetW();
   bool UsePositionHint = DE.HasPositionHint() &&
                          DE.GetPositionHint() + W.size() < Size &&
                          Rand.RandBool();
   if (Rand.RandBool()) {  // Insert W.
@@ -246,32 +239,36 @@ DictionaryEntry MutationDispatcher::Make
   return MakeDictionaryEntryFromCMP(Arg1.data(), Arg2.data(), Arg1.data(),
                                     Arg2.data(), Arg1.size(), Data, Size);
 }
 
 size_t MutationDispatcher::Mutate_AddWordFromTORC(
     uint8_t *Data, size_t Size, size_t MaxSize) {
   Word W;
   DictionaryEntry DE;
-  switch (Rand(3)) {
+  switch (Rand(4)) {
   case 0: {
     auto X = TPC.TORC8.Get(Rand.Rand());
     DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
   } break;
   case 1: {
     auto X = TPC.TORC4.Get(Rand.Rand());
     if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool())
       DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data, Size);
     else
       DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
   } break;
   case 2: {
     auto X = TPC.TORCW.Get(Rand.Rand());
     DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
   } break;
+  case 3: if (Options.UseMemmem) {
+    auto X = TPC.MMT.Get(Rand.Rand());
+    DE = DictionaryEntry(X);
+  } break;
   default:
     assert(0);
   }
   if (!DE.GetW().size()) return 0;
   Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
   if (!Size) return 0;
   DictionaryEntry &DERef =
       CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ %
@@ -464,17 +461,17 @@ void MutationDispatcher::RecordSuccessfu
     assert(DE->GetW().size());
     // Linear search is fine here as this happens seldom.
     if (!PersistentAutoDictionary.ContainsWord(DE->GetW()))
       PersistentAutoDictionary.push_back({DE->GetW(), 1});
   }
 }
 
 void MutationDispatcher::PrintRecommendedDictionary() {
-  std::vector<DictionaryEntry> V;
+  Vector<DictionaryEntry> V;
   for (auto &DE : PersistentAutoDictionary)
     if (!ManualDictionary.ContainsWord(DE.GetW()))
       V.push_back(DE);
   if (V.empty()) return;
   Printf("###### Recommended dictionary. ######\n");
   for (auto &DE: V) {
     assert(DE.GetW().size());
     Printf("\"");
@@ -504,17 +501,17 @@ size_t MutationDispatcher::Mutate(uint8_
 size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size,
                                          size_t MaxSize) {
   return MutateImpl(Data, Size, MaxSize, DefaultMutators);
 }
 
 // Mutates Data in place, returns new size.
 size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,
                                       size_t MaxSize,
-                                      const std::vector<Mutator> &Mutators) {
+                                      Vector<Mutator> &Mutators) {
   assert(MaxSize > 0);
   // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize),
   // in which case they will return 0.
   // Try several times before returning un-mutated data.
   for (int Iter = 0; Iter < 100; Iter++) {
     auto M = Mutators[Rand(Mutators.size())];
     size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);
     if (NewSize && NewSize <= MaxSize) {
@@ -528,19 +525,9 @@ size_t MutationDispatcher::MutateImpl(ui
   return 1;   // Fallback, should not happen frequently.
 }
 
 void MutationDispatcher::AddWordToManualDictionary(const Word &W) {
   ManualDictionary.push_back(
       {W, std::numeric_limits<size_t>::max()});
 }
 
-void MutationDispatcher::AddWordToAutoDictionary(DictionaryEntry DE) {
-  static const size_t kMaxAutoDictSize = 1 << 14;
-  if (TempAutoDictionary.size() >= kMaxAutoDictSize) return;
-  TempAutoDictionary.push_back(DE);
-}
-
-void MutationDispatcher::ClearAutoDictionary() {
-  TempAutoDictionary.clear();
-}
-
 }  // namespace fuzzer
--- a/tools/fuzzing/libfuzzer/FuzzerMutate.h
+++ b/tools/fuzzing/libfuzzer/FuzzerMutate.h
@@ -22,17 +22,17 @@ namespace fuzzer {
 class MutationDispatcher {
 public:
   MutationDispatcher(Random &Rand, const FuzzingOptions &Options);
   ~MutationDispatcher() {}
   /// Indicate that we are about to start a new sequence of mutations.
   void StartMutationSequence();
   /// Print the current sequence of mutations.
   void PrintMutationSequence();
-  /// Indicate that the current sequence of mutations was successfull.
+  /// Indicate that the current sequence of mutations was successful.
   void RecordSuccessfulMutationSequence();
   /// Mutates data by invoking user-provided mutator.
   size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize);
   /// Mutates data by invoking user-provided crossover.
   size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize);
   /// Mutates data by shuffling bytes.
   size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize);
   /// Mutates data by erasing bytes.
@@ -47,20 +47,16 @@ public:
   size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize);
   /// Mutates data by copying/inserting a part of data into a different place.
   size_t Mutate_CopyPart(uint8_t *Data, size_t Size, size_t MaxSize);
 
   /// Mutates data by adding a word from the manual dictionary.
   size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size,
                                             size_t MaxSize);
 
-  /// Mutates data by adding a word from the temporary automatic dictionary.
-  size_t Mutate_AddWordFromTemporaryAutoDictionary(uint8_t *Data, size_t Size,
-                                                   size_t MaxSize);
-
   /// Mutates data by adding a word from the TORC.
   size_t Mutate_AddWordFromTORC(uint8_t *Data, size_t Size, size_t MaxSize);
 
   /// Mutates data by adding a word from the persistent automatic dictionary.
   size_t Mutate_AddWordFromPersistentAutoDictionary(uint8_t *Data, size_t Size,
                                                     size_t MaxSize);
 
   /// Tries to find an ASCII integer in Data, changes it to another ASCII int.
@@ -79,35 +75,33 @@ public:
   size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize);
 
   /// Creates a cross-over of two pieces of Data, returns its size.
   size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2,
                    size_t Size2, uint8_t *Out, size_t MaxOutSize);
 
   void AddWordToManualDictionary(const Word &W);
 
-  void AddWordToAutoDictionary(DictionaryEntry DE);
-  void ClearAutoDictionary();
   void PrintRecommendedDictionary();
 
   void SetCorpus(const InputCorpus *Corpus) { this->Corpus = Corpus; }
 
   Random &GetRand() { return Rand; }
 
 private:
 
   struct Mutator {
     size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max);
     const char *Name;
   };
 
   size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size,
                                size_t MaxSize);
   size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize,
-                    const std::vector<Mutator> &Mutators);
+                    Vector<Mutator> &Mutators);
 
   size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
                       size_t ToSize, size_t MaxToSize);
   size_t CopyPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
                     size_t ToSize);
   size_t ApplyDictionaryEntry(uint8_t *Data, size_t Size, size_t MaxSize,
                               DictionaryEntry &DE);
 
@@ -126,31 +120,31 @@ private:
   const FuzzingOptions Options;
 
   // Dictionary provided by the user via -dict=DICT_FILE.
   Dictionary ManualDictionary;
   // Temporary dictionary modified by the fuzzer itself,
   // recreated periodically.
   Dictionary TempAutoDictionary;
   // Persistent dictionary modified by the fuzzer, consists of
-  // entries that led to successfull discoveries in the past mutations.
+  // entries that led to successful discoveries in the past mutations.
   Dictionary PersistentAutoDictionary;
 
-  std::vector<Mutator> CurrentMutatorSequence;
-  std::vector<DictionaryEntry *> CurrentDictionaryEntrySequence;
+  Vector<Mutator> CurrentMutatorSequence;
+  Vector<DictionaryEntry *> CurrentDictionaryEntrySequence;
 
   static const size_t kCmpDictionaryEntriesDequeSize = 16;
   DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize];
   size_t CmpDictionaryEntriesDequeIdx = 0;
 
   const InputCorpus *Corpus = nullptr;
-  std::vector<uint8_t> MutateInPlaceHere;
+  Vector<uint8_t> MutateInPlaceHere;
   // CustomCrossOver needs its own buffer as a custom implementation may call
   // LLVMFuzzerMutate, which in turn may resize MutateInPlaceHere.
-  std::vector<uint8_t> CustomCrossOverInPlaceHere;
+  Vector<uint8_t> CustomCrossOverInPlaceHere;
 
-  std::vector<Mutator> Mutators;
-  std::vector<Mutator> DefaultMutators;
+  Vector<Mutator> Mutators;
+  Vector<Mutator> DefaultMutators;
 };
 
 }  // namespace fuzzer
 
 #endif  // LLVM_FUZZER_MUTATE_H
--- a/tools/fuzzing/libfuzzer/FuzzerOptions.h
+++ b/tools/fuzzing/libfuzzer/FuzzerOptions.h
@@ -13,55 +13,63 @@
 
 #include "FuzzerDefs.h"
 
 namespace fuzzer {
 
 struct FuzzingOptions {
   int Verbosity = 1;
   size_t MaxLen = 0;
-  bool ExperimentalLenControl = false;
+  size_t LenControl = 1000;
   int UnitTimeoutSec = 300;
   int TimeoutExitCode = 77;
   int ErrorExitCode = 77;
   int MaxTotalTimeSec = 0;
   int RssLimitMb = 0;
+  int MallocLimitMb = 0;
   bool DoCrossOver = true;
   int MutateDepth = 5;
+  bool ReduceDepth = false;
   bool UseCounters = false;
-  bool UseIndirCalls = true;
   bool UseMemmem = true;
   bool UseCmp = false;
   bool UseValueProfile = false;
   bool Shrink = false;
+  bool ReduceInputs = false;
   int ReloadIntervalSec = 1;
   bool ShuffleAtStartUp = true;
   bool PreferSmall = true;
   size_t MaxNumberOfRuns = -1L;
   int ReportSlowUnits = 10;
   bool OnlyASCII = false;
   std::string OutputCorpus;
   std::string ArtifactPrefix = "./";
   std::string ExactArtifactPath;
   std::string ExitOnSrcPos;
   std::string ExitOnItem;
   bool SaveArtifacts = true;
   bool PrintNEW = true; // Print a status line when new units are found;
   bool PrintNewCovPcs = false;
+  int PrintNewCovFuncs = 0;
   bool PrintFinalStats = false;
   bool PrintCorpusStats = false;
   bool PrintCoverage = false;
   bool DumpCoverage = false;
+  bool UseClangCoverage = false;
   bool DetectLeaks = true;
+  int PurgeAllocatorIntervalSec = 1;
+  int UseFeatureFrequency = false;
   int  TraceMalloc = 0;
   bool HandleAbrt = false;
   bool HandleBus = false;
   bool HandleFpe = false;
   bool HandleIll = false;
   bool HandleInt = false;
   bool HandleSegv = false;
   bool HandleTerm = false;
   bool HandleXfsz = false;
+  bool HandleUsr1 = false;
+  bool HandleUsr2 = false;
 };
 
 }  // namespace fuzzer
 
 #endif  // LLVM_FUZZER_OPTIONS_H
new file mode 100644
--- /dev/null
+++ b/tools/fuzzing/libfuzzer/FuzzerShmemFuchsia.cpp
@@ -0,0 +1,38 @@
+//===- FuzzerShmemPosix.cpp - Posix shared memory ---------------*- C++ -* ===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// SharedMemoryRegion.  For Fuchsia, this is just stubs as equivalence servers
+// are not currently supported.
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+
+#if LIBFUZZER_FUCHSIA
+
+#include "FuzzerShmem.h"
+
+namespace fuzzer {
+
+bool SharedMemoryRegion::Create(const char *Name) {
+  return false;
+}
+
+bool SharedMemoryRegion::Open(const char *Name) {
+  return false;
+}
+
+bool SharedMemoryRegion::Destroy(const char *Name) {
+  return false;
+}
+
+void SharedMemoryRegion::Post(int Idx) {}
+
+void SharedMemoryRegion::Wait(int Idx) {}
+
+}  // namespace fuzzer
+
+#endif  // LIBFUZZER_FUCHSIA
--- a/tools/fuzzing/libfuzzer/FuzzerShmemPosix.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerShmemPosix.cpp
@@ -9,24 +9,24 @@
 // SharedMemoryRegion
 //===----------------------------------------------------------------------===//
 #include "FuzzerDefs.h"
 #if LIBFUZZER_POSIX
 
 #include "FuzzerIO.h"
 #include "FuzzerShmem.h"
 
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <sys/mman.h>
 #include <semaphore.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 namespace fuzzer {
 
 std::string SharedMemoryRegion::Path(const char *Name) {
   return DirPlusFile(TmpDir(), Name);
 }
 
--- a/tools/fuzzing/libfuzzer/FuzzerShmemWindows.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerShmemWindows.cpp
@@ -9,20 +9,20 @@
 // SharedMemoryRegion
 //===----------------------------------------------------------------------===//
 #include "FuzzerDefs.h"
 #if LIBFUZZER_WINDOWS
 
 #include "FuzzerIO.h"
 #include "FuzzerShmem.h"
 
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <fcntl.h>
 #include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 namespace fuzzer {
 
 std::string SharedMemoryRegion::Path(const char *Name) {
   return DirPlusFile(TmpDir(), Name);
 }
 
 std::string SharedMemoryRegion::SemName(const char *Name, int Idx) {
--- a/tools/fuzzing/libfuzzer/FuzzerTracePC.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerTracePC.cpp
@@ -7,57 +7,83 @@
 //
 //===----------------------------------------------------------------------===//
 // Trace PCs.
 // This module implements __sanitizer_cov_trace_pc_guard[_init],
 // the callback required for -fsanitize-coverage=trace-pc-guard instrumentation.
 //
 //===----------------------------------------------------------------------===//
 
+#include "FuzzerTracePC.h"
 #include "FuzzerCorpus.h"
 #include "FuzzerDefs.h"
 #include "FuzzerDictionary.h"
 #include "FuzzerExtFunctions.h"
 #include "FuzzerIO.h"
-#include "FuzzerTracePC.h"
 #include "FuzzerUtil.h"
 #include "FuzzerValueBitMap.h"
-#include <map>
 #include <set>
-#include <sstream>
 
 // The coverage counters and PCs.
 // These are declared as global variables named "__sancov_*" to simplify
 // experiments with inlined instrumentation.
 alignas(64) ATTRIBUTE_INTERFACE
 uint8_t __sancov_trace_pc_guard_8bit_counters[fuzzer::TracePC::kNumPCs];
 
 ATTRIBUTE_INTERFACE
 uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs];
 
+// Used by -fsanitize-coverage=stack-depth to track stack depth
+ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec")))
+thread_local uintptr_t __sancov_lowest_stack;
+
 namespace fuzzer {
 
 TracePC TPC;
 
+int ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr;
+
 uint8_t *TracePC::Counters() const {
   return __sancov_trace_pc_guard_8bit_counters;
 }
 
 uintptr_t *TracePC::PCs() const {
   return __sancov_trace_pc_pcs;
 }
 
 size_t TracePC::GetTotalPCCoverage() {
+  if (ObservedPCs.size())
+    return ObservedPCs.size();
   size_t Res = 0;
   for (size_t i = 1, N = GetNumPCs(); i < N; i++)
     if (PCs()[i])
       Res++;
   return Res;
 }
 
+
+void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) {
+  if (Start == Stop) return;
+  if (NumModulesWithInline8bitCounters &&
+      ModuleCounters[NumModulesWithInline8bitCounters-1].Start == Start) return;
+  assert(NumModulesWithInline8bitCounters <
+         sizeof(ModuleCounters) / sizeof(ModuleCounters[0]));
+  ModuleCounters[NumModulesWithInline8bitCounters++] = {Start, Stop};
+  NumInline8bitCounters += Stop - Start;
+}
+
+void TracePC::HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop) {
+  const PCTableEntry *B = reinterpret_cast<const PCTableEntry *>(Start);
+  const PCTableEntry *E = reinterpret_cast<const PCTableEntry *>(Stop);
+  if (NumPCTables && ModulePCTable[NumPCTables - 1].Start == B) return;
+  assert(NumPCTables < sizeof(ModulePCTable) / sizeof(ModulePCTable[0]));
+  ModulePCTable[NumPCTables++] = {B, E};
+  NumPCsInPCTables += E - B;
+}
+
 void TracePC::HandleInit(uint32_t *Start, uint32_t *Stop) {
   if (Start == Stop || *Start) return;
   assert(NumModules < sizeof(Modules) / sizeof(Modules[0]));
   for (uint32_t *P = Start; P < Stop; P++) {
     NumGuards++;
     if (NumGuards == kNumPCs) {
       RawPrint(
           "WARNING: The binary has too many instrumented PCs.\n"
@@ -67,161 +93,197 @@ void TracePC::HandleInit(uint32_t *Start
     *P = NumGuards % kNumPCs;
   }
   Modules[NumModules].Start = Start;
   Modules[NumModules].Stop = Stop;
   NumModules++;
 }
 
 void TracePC::PrintModuleInfo() {
-  Printf("INFO: Loaded %zd modules (%zd guards): ", NumModules, NumGuards);
-  for (size_t i = 0; i < NumModules; i++)
-    Printf("[%p, %p), ", Modules[i].Start, Modules[i].Stop);
-  Printf("\n");
+  if (NumGuards) {
+    Printf("INFO: Loaded %zd modules   (%zd guards): ", NumModules, NumGuards);
+    for (size_t i = 0; i < NumModules; i++)
+      Printf("%zd [%p, %p), ", Modules[i].Stop - Modules[i].Start,
+             Modules[i].Start, Modules[i].Stop);
+    Printf("\n");
+  }
+  if (NumModulesWithInline8bitCounters) {
+    Printf("INFO: Loaded %zd modules   (%zd inline 8-bit counters): ",
+           NumModulesWithInline8bitCounters, NumInline8bitCounters);
+    for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++)
+      Printf("%zd [%p, %p), ", ModuleCounters[i].Stop - ModuleCounters[i].Start,
+             ModuleCounters[i].Start, ModuleCounters[i].Stop);
+    Printf("\n");
+  }
+  if (NumPCTables) {
+    Printf("INFO: Loaded %zd PC tables (%zd PCs): ", NumPCTables,
+           NumPCsInPCTables);
+    for (size_t i = 0; i < NumPCTables; i++) {
+      Printf("%zd [%p,%p), ", ModulePCTable[i].Stop - ModulePCTable[i].Start,
+             ModulePCTable[i].Start, ModulePCTable[i].Stop);
+    }
+    Printf("\n");
+
+    if ((NumGuards && NumGuards != NumPCsInPCTables) ||
+        (NumInline8bitCounters && NumInline8bitCounters != NumPCsInPCTables)) {
+      Printf("ERROR: The size of coverage PC tables does not match the\n"
+             "number of instrumented PCs. This might be a compiler bug,\n"
+             "please contact the libFuzzer developers.\n"
+             "Also check https://bugs.llvm.org/show_bug.cgi?id=34636\n"
+             "for possible workarounds (tl;dr: don't use the old GNU ld)\n");
+      _Exit(1);
+    }
+  }
+  if (size_t NumClangCounters = ClangCountersEnd() - ClangCountersBegin())
+    Printf("INFO: %zd Clang Coverage Counters\n", NumClangCounters);
 }
 
 ATTRIBUTE_NO_SANITIZE_ALL
 void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
   const uintptr_t kBits = 12;
   const uintptr_t kMask = (1 << kBits) - 1;
   uintptr_t Idx = (Caller & kMask) | ((Callee & kMask) << kBits);
   ValueProfileMap.AddValueModPrime(Idx);
 }
 
-void TracePC::InitializePrintNewPCs() {
-  if (!DoPrintNewPCs) return;
-  assert(!PrintedPCs);
-  PrintedPCs = new std::set<uintptr_t>;
-  for (size_t i = 1; i < GetNumPCs(); i++)
-    if (PCs()[i])
-      PrintedPCs->insert(PCs()[i]);
+void TracePC::UpdateObservedPCs() {
+  Vector<uintptr_t> CoveredFuncs;
+  auto ObservePC = [&](uintptr_t PC) {
+    if (ObservedPCs.insert(PC).second && DoPrintNewPCs)
+      PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PC + 1);
+  };
+
+  auto Observe = [&](const PCTableEntry &TE) {
+    if (TE.PCFlags & 1)
+      if (ObservedFuncs.insert(TE.PC).second && NumPrintNewFuncs)
+        CoveredFuncs.push_back(TE.PC);
+    ObservePC(TE.PC);
+  };
+
+  if (NumPCsInPCTables) {
+    if (NumInline8bitCounters == NumPCsInPCTables) {
+      for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) {
+        uint8_t *Beg = ModuleCounters[i].Start;
+        size_t Size = ModuleCounters[i].Stop - Beg;
+        assert(Size ==
+               (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
+        for (size_t j = 0; j < Size; j++)
+          if (Beg[j])
+            Observe(ModulePCTable[i].Start[j]);
+      }
+    } else if (NumGuards == NumPCsInPCTables) {
+      size_t GuardIdx = 1;
+      for (size_t i = 0; i < NumModules; i++) {
+        uint32_t *Beg = Modules[i].Start;
+        size_t Size = Modules[i].Stop - Beg;
+        assert(Size ==
+               (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
+        for (size_t j = 0; j < Size; j++, GuardIdx++)
+          if (Counters()[GuardIdx])
+            Observe(ModulePCTable[i].Start[j]);
+      }
+    }
+  }
+  if (size_t NumClangCounters =
+      ClangCountersEnd() - ClangCountersBegin()) {
+    auto P = ClangCountersBegin();
+    for (size_t Idx = 0; Idx < NumClangCounters; Idx++)
+      if (P[Idx])
+        ObservePC((uintptr_t)Idx);
+  }
+
+  for (size_t i = 0, N = Min(CoveredFuncs.size(), NumPrintNewFuncs); i < N; i++) {
+    Printf("\tNEW_FUNC[%zd/%zd]: ", i, CoveredFuncs.size());
+    PrintPC("%p %F %L\n", "%p\n", CoveredFuncs[i] + 1);
+  }
 }
 
-void TracePC::PrintNewPCs() {
-  if (!DoPrintNewPCs) return;
-  assert(PrintedPCs);
-  for (size_t i = 1; i < GetNumPCs(); i++)
-    if (PCs()[i] && PrintedPCs->insert(PCs()[i]).second)
-      PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PCs()[i]);
+inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) {
+  // TODO: this implementation is x86 only.
+  // see sanitizer_common GetPreviousInstructionPc for full implementation.
+  return PC - 1;
+}
+
+inline ALWAYS_INLINE uintptr_t GetNextInstructionPc(uintptr_t PC) {
+  // TODO: this implementation is x86 only.
+  // see sanitizer_common GetPreviousInstructionPc for full implementation.
+  return PC + 1;
+}
+
+static std::string GetModuleName(uintptr_t PC) {
+  char ModulePathRaw[4096] = "";  // What's PATH_MAX in portable C++?
+  void *OffsetRaw = nullptr;
+  if (!EF->__sanitizer_get_module_and_offset_for_pc(
+      reinterpret_cast<void *>(PC), ModulePathRaw,
+      sizeof(ModulePathRaw), &OffsetRaw))
+    return "";
+  return ModulePathRaw;
 }
 
 void TracePC::PrintCoverage() {
   if (!EF->__sanitizer_symbolize_pc ||
       !EF->__sanitizer_get_module_and_offset_for_pc) {
     Printf("INFO: __sanitizer_symbolize_pc or "
            "__sanitizer_get_module_and_offset_for_pc is not available,"
            " not printing coverage\n");
     return;
   }
-  std::map<std::string, std::vector<uintptr_t>> CoveredPCsPerModule;
-  std::map<std::string, uintptr_t> ModuleOffsets;
-  std::set<std::string> CoveredDirs, CoveredFiles, CoveredFunctions,
-      CoveredLines;
   Printf("COVERAGE:\n");
-  for (size_t i = 1; i < GetNumPCs(); i++) {
-    uintptr_t PC = PCs()[i];
-    if (!PC) continue;
-    std::string FileStr = DescribePC("%s", PC);
-    if (!IsInterestingCoverageFile(FileStr)) continue;
-    std::string FixedPCStr = DescribePC("%p", PC);
-    std::string FunctionStr = DescribePC("%F", PC);
-    std::string LineStr = DescribePC("%l", PC);
-    char ModulePathRaw[4096] = "";  // What's PATH_MAX in portable C++?
-    void *OffsetRaw = nullptr;
-    if (!EF->__sanitizer_get_module_and_offset_for_pc(
-            reinterpret_cast<void *>(PC), ModulePathRaw,
-            sizeof(ModulePathRaw), &OffsetRaw))
-      continue;
-    std::string Module = ModulePathRaw;
-    uintptr_t FixedPC = std::stoull(FixedPCStr, 0, 16);
-    uintptr_t PcOffset = reinterpret_cast<uintptr_t>(OffsetRaw);
-    ModuleOffsets[Module] = FixedPC - PcOffset;
-    CoveredPCsPerModule[Module].push_back(PcOffset);
-    CoveredFunctions.insert(FunctionStr);
-    CoveredFiles.insert(FileStr);
-    CoveredDirs.insert(DirName(FileStr));
-    if (!CoveredLines.insert(FileStr + ":" + LineStr).second)
-      continue;
-    Printf("COVERED: %s %s:%s\n", FunctionStr.c_str(),
-           FileStr.c_str(), LineStr.c_str());
-  }
+  std::string LastFunctionName = "";
+  std::string LastFileStr = "";
+  Set<size_t> UncoveredLines;
+  Set<size_t> CoveredLines;
 
-  std::string CoveredDirsStr;
-  for (auto &Dir : CoveredDirs) {
-    if (!CoveredDirsStr.empty())
-      CoveredDirsStr += ",";
-    CoveredDirsStr += Dir;
-  }
-  Printf("COVERED_DIRS: %s\n", CoveredDirsStr.c_str());
+  auto FunctionEndCallback = [&](const std::string &CurrentFunc,
+                                 const std::string &CurrentFile) {
+    if (LastFunctionName != CurrentFunc) {
+      if (CoveredLines.empty() && !UncoveredLines.empty()) {
+        Printf("UNCOVERED_FUNC: %s\n", LastFunctionName.c_str());
+      } else {
+        for (auto Line : UncoveredLines) {
+          if (!CoveredLines.count(Line))
+            Printf("UNCOVERED_LINE: %s %s:%zd\n", LastFunctionName.c_str(),
+                   LastFileStr.c_str(), Line);
+        }
+      }
 
-  for (auto &M : CoveredPCsPerModule) {
-    std::set<std::string> UncoveredFiles, UncoveredFunctions;
-    std::map<std::string, std::set<int> > UncoveredLines;  // Func+File => lines
-    auto &ModuleName = M.first;
-    auto &CoveredOffsets = M.second;
-    uintptr_t ModuleOffset = ModuleOffsets[ModuleName];
-    std::sort(CoveredOffsets.begin(), CoveredOffsets.end());
-    Printf("MODULE_WITH_COVERAGE: %s\n", ModuleName.c_str());
-    // sancov does not yet fully support DSOs.
-    // std::string Cmd = "sancov -print-coverage-pcs " + ModuleName;
-    std::string Cmd = DisassembleCmd(ModuleName) + " | " +
-        SearchRegexCmd("call.*__sanitizer_cov_trace_pc_guard");
-    std::string SanCovOutput;
-    if (!ExecuteCommandAndReadOutput(Cmd, &SanCovOutput)) {
-      Printf("INFO: Command failed: %s\n", Cmd.c_str());
-      continue;
+      UncoveredLines.clear();
+      CoveredLines.clear();
+      LastFunctionName = CurrentFunc;
+      LastFileStr = CurrentFile;
     }
-    std::istringstream ISS(SanCovOutput);
-    std::string S;
-    while (std::getline(ISS, S, '\n')) {
-      size_t PcOffsetEnd = S.find(':');
-      if (PcOffsetEnd == std::string::npos)
-        continue;
-      S.resize(PcOffsetEnd);
-      uintptr_t PcOffset = std::stoull(S, 0, 16);
-      if (!std::binary_search(CoveredOffsets.begin(), CoveredOffsets.end(),
-                              PcOffset)) {
-        uintptr_t PC = ModuleOffset + PcOffset;
-        auto FileStr = DescribePC("%s", PC);
-        if (!IsInterestingCoverageFile(FileStr)) continue;
-        if (CoveredFiles.count(FileStr) == 0) {
-          UncoveredFiles.insert(FileStr);
-          continue;
-        }
-        auto FunctionStr = DescribePC("%F", PC);
-        if (CoveredFunctions.count(FunctionStr) == 0) {
-          UncoveredFunctions.insert(FunctionStr);
-          continue;
-        }
-        std::string LineStr = DescribePC("%l", PC);
-        uintptr_t Line = std::stoi(LineStr);
-        std::string FileLineStr = FileStr + ":" + LineStr;
-        if (CoveredLines.count(FileLineStr) == 0)
-          UncoveredLines[FunctionStr + " " + FileStr].insert(Line);
-      }
+  };
+
+  for (size_t i = 0; i < NumPCTables; i++) {
+    auto &M = ModulePCTable[i];
+    assert(M.Start < M.Stop);
+    auto ModuleName = GetModuleName(M.Start->PC);
+    for (auto Ptr = M.Start; Ptr < M.Stop; Ptr++) {
+      auto PC = Ptr->PC;
+      auto VisualizePC = GetNextInstructionPc(PC);
+      bool IsObserved = ObservedPCs.count(PC);
+      std::string FileStr = DescribePC("%s", VisualizePC);
+      if (!IsInterestingCoverageFile(FileStr)) continue;
+      std::string FunctionStr = DescribePC("%F", VisualizePC);
+      FunctionEndCallback(FunctionStr, FileStr);
+      std::string LineStr = DescribePC("%l", VisualizePC);
+      size_t Line = std::stoul(LineStr);
+      if (IsObserved && CoveredLines.insert(Line).second)
+        Printf("COVERED: %s %s:%zd\n", FunctionStr.c_str(), FileStr.c_str(),
+               Line);
+      else
+        UncoveredLines.insert(Line);
     }
-    for (auto &FileLine: UncoveredLines)
-      for (int Line : FileLine.second)
-        Printf("UNCOVERED_LINE: %s:%d\n", FileLine.first.c_str(), Line);
-    for (auto &Func : UncoveredFunctions)
-      Printf("UNCOVERED_FUNC: %s\n", Func.c_str());
-    for (auto &File : UncoveredFiles)
-      Printf("UNCOVERED_FILE: %s\n", File.c_str());
   }
-}
-
-inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) {
-  // TODO: this implementation is x86 only.
-  // see sanitizer_common GetPreviousInstructionPc for full implementation.
-  return PC - 1;
+  FunctionEndCallback("", "");
 }
 
 void TracePC::DumpCoverage() {
   if (EF->__sanitizer_dump_coverage) {
-    std::vector<uintptr_t> PCsCopy(GetNumPCs());
+    Vector<uintptr_t> PCsCopy(GetNumPCs());
     for (size_t i = 0; i < GetNumPCs(); i++)
       PCsCopy[i] = PCs()[i] ? GetPreviousInstructionPc(PCs()[i]) : 0;
     EF->__sanitizer_dump_coverage(PCsCopy.data(), PCsCopy.size());
   }
 }
 
 // Value profile.
 // We keep track of various values that affect control flow.
@@ -270,16 +332,48 @@ void TracePC::HandleCmp(uintptr_t PC, T 
   uintptr_t Idx = ((PC & 4095) + 1) * ArgDistance;
   if (sizeof(T) == 4)
       TORC4.Insert(ArgXor, Arg1, Arg2);
   else if (sizeof(T) == 8)
       TORC8.Insert(ArgXor, Arg1, Arg2);
   ValueProfileMap.AddValue(Idx);
 }
 
+static size_t InternalStrnlen(const char *S, size_t MaxLen) {
+  size_t Len = 0;
+  for (; Len < MaxLen && S[Len]; Len++) {}
+  return Len;
+}
+
+// Finds min of (strlen(S1), strlen(S2)).
+// Needed bacause one of these strings may actually be non-zero terminated.
+static size_t InternalStrnlen2(const char *S1, const char *S2) {
+  size_t Len = 0;
+  for (; S1[Len] && S2[Len]; Len++)  {}
+  return Len;
+}
+
+void TracePC::ClearInlineCounters() {
+  for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) {
+    uint8_t *Beg = ModuleCounters[i].Start;
+    size_t Size = ModuleCounters[i].Stop - Beg;
+    memset(Beg, 0, Size);
+  }
+}
+
+ATTRIBUTE_NO_SANITIZE_ALL
+void TracePC::RecordInitialStack() {
+  int stack;
+  __sancov_lowest_stack = InitialStack = reinterpret_cast<uintptr_t>(&stack);
+}
+
+uintptr_t TracePC::GetMaxStackOffset() const {
+  return InitialStack - __sancov_lowest_stack;  // Stack grows down
+}
+
 } // namespace fuzzer
 
 extern "C" {
 ATTRIBUTE_INTERFACE
 ATTRIBUTE_NO_SANITIZE_ALL
 void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
   uint32_t Idx = *Guard;
@@ -299,16 +393,27 @@ void __sanitizer_cov_trace_pc() {
 }
 
 ATTRIBUTE_INTERFACE
 void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) {
   fuzzer::TPC.HandleInit(Start, Stop);
 }
 
 ATTRIBUTE_INTERFACE
+void __sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop) {
+  fuzzer::TPC.HandleInline8bitCountersInit(Start, Stop);
+}
+
+ATTRIBUTE_INTERFACE
+void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
+                              const uintptr_t *pcs_end) {
+  fuzzer::TPC.HandlePCsInit(pcs_beg, pcs_end);
+}
+
+ATTRIBUTE_INTERFACE
 ATTRIBUTE_NO_SANITIZE_ALL
 void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) {
   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
   fuzzer::TPC.HandleCallerCallee(PC, Callee);
 }
 
 ATTRIBUTE_INTERFACE
 ATTRIBUTE_NO_SANITIZE_ALL
@@ -316,40 +421,75 @@ ATTRIBUTE_TARGET_POPCNT
 void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
   fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
 }
 
 ATTRIBUTE_INTERFACE
 ATTRIBUTE_NO_SANITIZE_ALL
 ATTRIBUTE_TARGET_POPCNT
+// Now the __sanitizer_cov_trace_const_cmp[1248] callbacks just mimic
+// the behaviour of __sanitizer_cov_trace_cmp[1248] ones. This, however,
+// should be changed later to make full use of instrumentation.
+void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
 void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
   fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
 }
 
 ATTRIBUTE_INTERFACE
 ATTRIBUTE_NO_SANITIZE_ALL
 ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
 void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
   fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
 }
 
 ATTRIBUTE_INTERFACE
 ATTRIBUTE_NO_SANITIZE_ALL
 ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
 void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {
   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
   fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
 }
 
 ATTRIBUTE_INTERFACE
 ATTRIBUTE_NO_SANITIZE_ALL
 ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
 void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
   uint64_t N = Cases[0];
   uint64_t ValSizeInBits = Cases[1];
   uint64_t *Vals = Cases + 2;
   // Skip the most common and the most boring case.
   if (Vals[N - 1]  < 256 && Val < 256)
     return;
   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
@@ -387,9 +527,76 @@ void __sanitizer_cov_trace_div8(uint64_t
 
 ATTRIBUTE_INTERFACE
 ATTRIBUTE_NO_SANITIZE_ALL
 ATTRIBUTE_TARGET_POPCNT
 void __sanitizer_cov_trace_gep(uintptr_t Idx) {
   uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
   fuzzer::TPC.HandleCmp(PC, Idx, (uintptr_t)0);
 }
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
+                                  const void *s2, size_t n, int result) {
+  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+  if (result == 0) return;  // No reason to mutate.
+  if (n <= 1) return;  // Not interesting.
+  fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/false);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
+                                   const char *s2, size_t n, int result) {
+  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+  if (result == 0) return;  // No reason to mutate.
+  size_t Len1 = fuzzer::InternalStrnlen(s1, n);
+  size_t Len2 = fuzzer::InternalStrnlen(s2, n);
+  n = std::min(n, Len1);
+  n = std::min(n, Len2);
+  if (n <= 1) return;  // Not interesting.
+  fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/true);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
+                                   const char *s2, int result) {
+  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+  if (result == 0) return;  // No reason to mutate.
+  size_t N = fuzzer::InternalStrnlen2(s1, s2);
+  if (N <= 1) return;  // Not interesting.
+  fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, N, /*StopAtZero*/true);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
+                                       const char *s2, size_t n, int result) {
+  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+  return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
+                                      const char *s2, int result) {
+  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+  return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,
+                                  const char *s2, char *result) {
+  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+  fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,
+                                      const char *s2, char *result) {
+  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+  fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,
+                                  const void *s2, size_t len2, void *result) {
+  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
+  fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), len2);
+}
 }  // extern "C"
--- a/tools/fuzzing/libfuzzer/FuzzerTracePC.h
+++ b/tools/fuzzing/libfuzzer/FuzzerTracePC.h
@@ -40,123 +40,258 @@ struct TableOfRecentCompares {
     Table[Idx].B = Arg2;
   }
 
   Pair Get(size_t I) { return Table[I % kSize]; }
 
   Pair Table[kSize];
 };
 
+template <size_t kSizeT>
+struct MemMemTable {
+  static const size_t kSize = kSizeT;
+  Word MemMemWords[kSize];
+  Word EmptyWord;
+
+  void Add(const uint8_t *Data, size_t Size) {
+    if (Size <= 2) return;
+    Size = std::min(Size, Word::GetMaxSize());
+    size_t Idx = SimpleFastHash(Data, Size) % kSize;
+    MemMemWords[Idx].Set(Data, Size);
+  }
+  const Word &Get(size_t Idx) {
+    for (size_t i = 0; i < kSize; i++) {
+      const Word &W = MemMemWords[(Idx + i) % kSize];
+      if (W.size()) return W;
+    }
+    EmptyWord.Set(nullptr, 0);
+    return EmptyWord;
+  }
+};
+
 class TracePC {
  public:
   static const size_t kNumPCs = 1 << 21;
   // How many bits of PC are used from __sanitizer_cov_trace_pc.
   static const size_t kTracePcBits = 18;
 
-  void HandleInit(uint32_t *start, uint32_t *stop);
+  void HandleInit(uint32_t *Start, uint32_t *Stop);
+  void HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop);
+  void HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop);
   void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee);
   template <class T> void HandleCmp(uintptr_t PC, T Arg1, T Arg2);
   size_t GetTotalPCCoverage();
   void SetUseCounters(bool UC) { UseCounters = UC; }
+  void SetUseClangCoverage(bool UCC) { UseClangCoverage = UCC; }
   void SetUseValueProfile(bool VP) { UseValueProfile = VP; }
   void SetPrintNewPCs(bool P) { DoPrintNewPCs = P; }
+  void SetPrintNewFuncs(size_t P) { NumPrintNewFuncs = P; }
+  void UpdateObservedPCs();
   template <class Callback> void CollectFeatures(Callback CB) const;
 
   void ResetMaps() {
     ValueProfileMap.Reset();
-    memset(Counters(), 0, GetNumPCs());
+    if (NumModules)
+      memset(Counters(), 0, GetNumPCs());
     ClearExtraCounters();
+    ClearInlineCounters();
+    if (UseClangCoverage)
+      ClearClangCounters();
   }
 
+  void ClearInlineCounters();
+
   void UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize);
   void PrintFeatureSet();
 
   void PrintModuleInfo();
 
   void PrintCoverage();
   void DumpCoverage();
 
   void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
                          size_t n, bool StopAtZero);
 
   TableOfRecentCompares<uint32_t, 32> TORC4;
   TableOfRecentCompares<uint64_t, 32> TORC8;
   TableOfRecentCompares<Word, 32> TORCW;
+  MemMemTable<1024> MMT;
 
-  void PrintNewPCs();
-  void InitializePrintNewPCs();
   size_t GetNumPCs() const {
     return NumGuards == 0 ? (1 << kTracePcBits) : Min(kNumPCs, NumGuards + 1);
   }
   uintptr_t GetPC(size_t Idx) {
     assert(Idx < GetNumPCs());
     return PCs()[Idx];
   }
 
+  void RecordInitialStack();
+  uintptr_t GetMaxStackOffset() const;
+
+  template<class CallBack>
+  void ForEachObservedPC(CallBack CB) {
+    for (auto PC : ObservedPCs)
+      CB(PC);
+  }
+
 private:
   bool UseCounters = false;
   bool UseValueProfile = false;
+  bool UseClangCoverage = false;
   bool DoPrintNewPCs = false;
+  size_t NumPrintNewFuncs = 0;
 
   struct Module {
     uint32_t *Start, *Stop;
   };
 
   Module Modules[4096];
   size_t NumModules;  // linker-initialized.
   size_t NumGuards;  // linker-initialized.
 
+  struct { uint8_t *Start, *Stop; } ModuleCounters[4096];
+  size_t NumModulesWithInline8bitCounters;  // linker-initialized.
+  size_t NumInline8bitCounters;
+
+  struct PCTableEntry {
+    uintptr_t PC, PCFlags;
+  };
+
+  struct { const PCTableEntry *Start, *Stop; } ModulePCTable[4096];
+  size_t NumPCTables;
+  size_t NumPCsInPCTables;
+
   uint8_t *Counters() const;
   uintptr_t *PCs() const;
 
-  std::set<uintptr_t> *PrintedPCs;
+  Set<uintptr_t> ObservedPCs;
+  Set<uintptr_t> ObservedFuncs;
 
   ValueBitMap ValueProfileMap;
+  uintptr_t InitialStack;
 };
 
-template <class Callback> // void Callback(size_t Idx, uint8_t Value);
+template <class Callback>
+// void Callback(size_t FirstFeature, size_t Idx, uint8_t Value);
 ATTRIBUTE_NO_SANITIZE_ALL
 void ForEachNonZeroByte(const uint8_t *Begin, const uint8_t *End,
                         size_t FirstFeature, Callback Handle8bitCounter) {
   typedef uintptr_t LargeType;
   const size_t Step = sizeof(LargeType) / sizeof(uint8_t);
-  assert(!(reinterpret_cast<uintptr_t>(Begin) % 64));
-  for (auto P = Begin; P < End; P += Step)
+  const size_t StepMask = Step - 1;
+  auto P = Begin;
+  // Iterate by 1 byte until either the alignment boundary or the end.
+  for (; reinterpret_cast<uintptr_t>(P) & StepMask && P < End; P++)
+    if (uint8_t V = *P)
+      Handle8bitCounter(FirstFeature, P - Begin, V);
+
+  // Iterate by Step bytes at a time.
+  for (; P < End; P += Step)
     if (LargeType Bundle = *reinterpret_cast<const LargeType *>(P))
       for (size_t I = 0; I < Step; I++, Bundle >>= 8)
         if (uint8_t V = Bundle & 0xff)
-          Handle8bitCounter(FirstFeature + P - Begin + I, V);
+          Handle8bitCounter(FirstFeature, P - Begin + I, V);
+
+  // Iterate by 1 byte until the end.
+  for (; P < End; P++)
+    if (uint8_t V = *P)
+      Handle8bitCounter(FirstFeature, P - Begin, V);
 }
 
-template <class Callback>  // bool Callback(size_t Feature)
-ATTRIBUTE_NO_SANITIZE_ALL
-__attribute__((noinline))
-void TracePC::CollectFeatures(Callback HandleFeature) const {
-  uint8_t *Counters = this->Counters();
-  size_t N = GetNumPCs();
-  auto Handle8bitCounter = [&](size_t Idx, uint8_t Counter) {
+// Given a non-zero Counter returns a number in the range [0,7].
+template<class T>
+unsigned CounterToFeature(T Counter) {
+    // Returns a feature number by placing Counters into buckets as illustrated
+    // below.
+    //
+    // Counter bucket: [1] [2] [3] [4-7] [8-15] [16-31] [32-127] [128+]
+    // Feature number:  0   1   2    3     4       5       6       7
+    //
+    // This is a heuristic taken from AFL (see
+    // http://lcamtuf.coredump.cx/afl/technical_details.txt).
+    //
+    // This implementation may change in the future so clients should
+    // not rely on it.
     assert(Counter);
     unsigned Bit = 0;
     /**/ if (Counter >= 128) Bit = 7;
     else if (Counter >= 32) Bit = 6;
     else if (Counter >= 16) Bit = 5;
     else if (Counter >= 8) Bit = 4;
     else if (Counter >= 4) Bit = 3;
     else if (Counter >= 3) Bit = 2;
     else if (Counter >= 2) Bit = 1;
-    HandleFeature(Idx * 8 + Bit);
+    return Bit;
+}
+
+template <class Callback>  // void Callback(size_t Feature)
+ATTRIBUTE_NO_SANITIZE_ADDRESS
+__attribute__((noinline))
+void TracePC::CollectFeatures(Callback HandleFeature) const {
+  uint8_t *Counters = this->Counters();
+  size_t N = GetNumPCs();
+  auto Handle8bitCounter = [&](size_t FirstFeature,
+                               size_t Idx, uint8_t Counter) {
+    if (UseCounters)
+      HandleFeature(FirstFeature + Idx * 8 + CounterToFeature(Counter));
+    else
+      HandleFeature(FirstFeature + Idx);
   };
 
-  ForEachNonZeroByte(Counters, Counters + N, 0, Handle8bitCounter);
-  ForEachNonZeroByte(ExtraCountersBegin(), ExtraCountersEnd(), N * 8,
-                     Handle8bitCounter);
+  size_t FirstFeature = 0;
+
+  if (!NumInline8bitCounters) {
+    ForEachNonZeroByte(Counters, Counters + N, FirstFeature, Handle8bitCounter);
+    FirstFeature += N * 8;
+  }
+
+  if (NumInline8bitCounters) {
+    for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) {
+      ForEachNonZeroByte(ModuleCounters[i].Start, ModuleCounters[i].Stop,
+                         FirstFeature, Handle8bitCounter);
+      FirstFeature += 8 * (ModuleCounters[i].Stop - ModuleCounters[i].Start);
+    }
+  }
 
-  if (UseValueProfile)
+  if (size_t NumClangCounters = ClangCountersEnd() - ClangCountersBegin()) {
+    auto P = ClangCountersBegin();
+    for (size_t Idx = 0; Idx < NumClangCounters; Idx++)
+      if (auto Cnt = P[Idx]) {
+        if (UseCounters)
+          HandleFeature(FirstFeature + Idx * 8 + CounterToFeature(Cnt));
+        else
+          HandleFeature(FirstFeature + Idx);
+      }
+    FirstFeature += NumClangCounters;
+  }
+
+  ForEachNonZeroByte(ExtraCountersBegin(), ExtraCountersEnd(), FirstFeature,
+                     Handle8bitCounter);
+  FirstFeature += (ExtraCountersEnd() - ExtraCountersBegin()) * 8;
+
+  if (UseValueProfile) {
     ValueProfileMap.ForEach([&](size_t Idx) {
-      HandleFeature(N * 8 + Idx);
+      HandleFeature(FirstFeature + Idx);
     });
+    FirstFeature += ValueProfileMap.SizeInBits();
+  }
+
+  // Step function, grows similar to 8 * Log_2(A).
+  auto StackDepthStepFunction = [](uint32_t A) -> uint32_t {
+    if (!A) return A;
+    uint32_t Log2 = Log(A);
+    if (Log2 < 3) return A;
+    Log2 -= 3;
+    return (Log2 + 1) * 8 + ((A >> Log2) & 7);
+  };
+  assert(StackDepthStepFunction(1024) == 64);
+  assert(StackDepthStepFunction(1024 * 4) == 80);
+  assert(StackDepthStepFunction(1024 * 1024) == 144);
+
+  if (auto MaxStackOffset = GetMaxStackOffset())
+    HandleFeature(FirstFeature + StackDepthStepFunction(MaxStackOffset / 8));
 }
 
 extern TracePC TPC;
 
 }  // namespace fuzzer
 
 #endif  // LLVM_FUZZER_TRACE_PC
deleted file mode 100644
--- a/tools/fuzzing/libfuzzer/FuzzerTraceState.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-//===- FuzzerTraceState.cpp - Trace-based fuzzer mutator ------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-// Data tracing.
-//===----------------------------------------------------------------------===//
-
-#include "FuzzerDictionary.h"
-#include "FuzzerInternal.h"
-#include "FuzzerIO.h"
-#include "FuzzerMutate.h"
-#include "FuzzerTracePC.h"
-#include <algorithm>
-#include <cstring>
-#include <map>
-#include <set>
-#include <thread>
-
-namespace fuzzer {
-
-// Declared as static globals for faster checks inside the hooks.
-static bool RecordingMemmem = false;
-
-int ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr;
-
-class TraceState {
-public:
-  TraceState(MutationDispatcher &MD, const FuzzingOptions &Options,
-             const Fuzzer *F)
-      : MD(MD), Options(Options), F(F) {}
-
-  void StartTraceRecording() {
-    if (!Options.UseMemmem)
-      return;
-    RecordingMemmem = true;
-    InterestingWords.clear();
-    MD.ClearAutoDictionary();
-  }
-
-  void StopTraceRecording() {
-    if (!RecordingMemmem)
-      return;
-    for (auto &W : InterestingWords)
-      MD.AddWordToAutoDictionary({W});
-  }
-
-  void AddInterestingWord(const uint8_t *Data, size_t Size) {
-    if (!RecordingMemmem || !F->InFuzzingThread()) return;
-    if (Size <= 1) return;
-    Size = std::min(Size, Word::GetMaxSize());
-    Word W(Data, Size);
-    InterestingWords.insert(W);
-  }
-
- private:
-
-  // TODO: std::set is too inefficient, need to have a custom DS here.
-  std::set<Word> InterestingWords;
-  MutationDispatcher &MD;
-  const FuzzingOptions Options;
-  const Fuzzer *F;
-};
-
-static TraceState *TS;
-
-void Fuzzer::StartTraceRecording() {
-  if (!TS) return;
-  TS->StartTraceRecording();
-}
-
-void Fuzzer::StopTraceRecording() {
-  if (!TS) return;
-  TS->StopTraceRecording();
-}
-
-void Fuzzer::InitializeTraceState() {
-  if (!Options.UseMemmem) return;
-  TS = new TraceState(MD, Options, this);
-}
-
-static size_t InternalStrnlen(const char *S, size_t MaxLen) {
-  size_t Len = 0;
-  for (; Len < MaxLen && S[Len]; Len++) {}
-  return Len;
-}
-
-// Finds min of (strlen(S1), strlen(S2)).
-// Needed bacause one of these strings may actually be non-zero terminated.
-static size_t InternalStrnlen2(const char *S1, const char *S2) {
-  size_t Len = 0;
-  for (; S1[Len] && S2[Len]; Len++)  {}
-  return Len;
-}
-
-}  // namespace fuzzer
-
-using fuzzer::TS;
-
-extern "C" {
-
-// We may need to avoid defining weak hooks to stay compatible with older clang.
-#ifndef LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
-# define LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS 1
-#endif
-
-#if LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
-
-ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
-void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
-                                  const void *s2, size_t n, int result) {
-  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
-  if (result == 0) return;  // No reason to mutate.
-  if (n <= 1) return;  // Not interesting.
-  fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/false);
-}
-
-ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
-void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
-                                   const char *s2, size_t n, int result) {
-  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
-  if (result == 0) return;  // No reason to mutate.
-  size_t Len1 = fuzzer::InternalStrnlen(s1, n);
-  size_t Len2 = fuzzer::InternalStrnlen(s2, n);
-  n = std::min(n, Len1);
-  n = std::min(n, Len2);
-  if (n <= 1) return;  // Not interesting.
-  fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/true);
-}
-
-
-ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
-void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
-                                   const char *s2, int result) {
-  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
-  if (result == 0) return;  // No reason to mutate.
-  size_t N = fuzzer::InternalStrnlen2(s1, s2);
-  if (N <= 1) return;  // Not interesting.
-  fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, N, /*StopAtZero*/true);
-}
-
-ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
-void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
-                                       const char *s2, size_t n, int result) {
-  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
-  return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result);
-}
-
-ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
-void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
-                                      const char *s2, int result) {
-  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
-  return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result);
-}
-
-ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
-void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,
-                                  const char *s2, char *result) {
-  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
-  TS->AddInterestingWord(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
-}
-
-ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
-void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,
-                                      const char *s2, char *result) {
-  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
-  TS->AddInterestingWord(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
-}
-
-ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
-void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,
-                                  const void *s2, size_t len2, void *result) {
-  if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
-  TS->AddInterestingWord(reinterpret_cast<const uint8_t *>(s2), len2);
-}
-
-#endif  // LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
-}  // extern "C"
--- a/tools/fuzzing/libfuzzer/FuzzerUtil.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerUtil.cpp
@@ -119,17 +119,17 @@ bool ParseOneDictionaryEntry(const std::
     } else {
       // Any other character.
       U->push_back(V);
     }
   }
   return true;
 }
 
-bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units) {
+bool ParseDictionaryFile(const std::string &Text, Vector<Unit> *Units) {
   if (Text.empty()) {
     Printf("ParseDictionaryFile: file does not exist or is empty\n");
     return false;
   }
   std::istringstream ISS(Text);
   Units->clear();
   Unit U;
   int LineNo = 0;
@@ -176,17 +176,17 @@ std::string Base64(const Unit &U) {
     Res += Table[(x >> 6) & 63];
     Res += "=";
   }
   return Res;
 }
 
 std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) {
   if (!EF->__sanitizer_symbolize_pc) return "<can not symbolize>";
-  char PcDescr[1024];
+  char PcDescr[1024] = {};
   EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC),
                                SymbolizedFMT, PcDescr, sizeof(PcDescr));
   PcDescr[sizeof(PcDescr) - 1] = 0;  // Just in case.
   return PcDescr;
 }
 
 void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) {
   if (EF->__sanitizer_symbolize_pc)
@@ -200,19 +200,16 @@ unsigned NumberOfCpuCores() {
   if (!N) {
     Printf("WARNING: std::thread::hardware_concurrency not well defined for "
            "your platform. Assuming CPU count of 1.\n");
     N = 1;
   }
   return N;
 }
 
-bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out) {
-  FILE *Pipe = OpenProcessPipe(Command.c_str(), "r");
-  if (!Pipe) return false;
-  char Buff[1024];
-  size_t N;
-  while ((N = fread(Buff, 1, sizeof(Buff), Pipe)) > 0)
-    Out->append(Buff, N);
-  return true;
+size_t SimpleFastHash(const uint8_t *Data, size_t Size) {
+  size_t Res = 0;
+  for (size_t i = 0; i < Size; i++)
+    Res = Res * 11 + Data[i];
+  return Res;
 }
 
 }  // namespace fuzzer
--- a/tools/fuzzing/libfuzzer/FuzzerUtil.h
+++ b/tools/fuzzing/libfuzzer/FuzzerUtil.h
@@ -8,16 +8,17 @@
 //===----------------------------------------------------------------------===//
 // Util functions.
 //===----------------------------------------------------------------------===//
 
 #ifndef LLVM_FUZZER_UTIL_H
 #define LLVM_FUZZER_UTIL_H
 
 #include "FuzzerDefs.h"
+#include "FuzzerCommand.h"
 
 namespace fuzzer {
 
 void PrintHexArray(const Unit &U, const char *PrintAfter = "");
 
 void PrintHexArray(const uint8_t *Data, size_t Size,
                    const char *PrintAfter = "");
 
@@ -36,41 +37,51 @@ bool IsASCII(const uint8_t *Data, size_t
 std::string Base64(const Unit &U);
 
 void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC);
 
 std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC);
 
 unsigned NumberOfCpuCores();
 
-bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out);
-
 // Platform specific functions.
 void SetSignalHandler(const FuzzingOptions& Options);
 
 void SleepSeconds(int Seconds);
 
 unsigned long GetPid();
 
 size_t GetPeakRSSMb();
 
-int ExecuteCommand(const std::string &Command);
+int ExecuteCommand(const Command &Cmd);
 
 FILE *OpenProcessPipe(const char *Command, const char *Mode);
 
 const void *SearchMemory(const void *haystack, size_t haystacklen,
                          const void *needle, size_t needlelen);
 
-std::string CloneArgsWithoutX(const std::vector<std::string> &Args,
+std::string CloneArgsWithoutX(const Vector<std::string> &Args,
                               const char *X1, const char *X2);
 
-inline std::string CloneArgsWithoutX(const std::vector<std::string> &Args,
+inline std::string CloneArgsWithoutX(const Vector<std::string> &Args,
                                      const char *X) {
   return CloneArgsWithoutX(Args, X, X);
 }
 
+inline std::pair<std::string, std::string> SplitBefore(std::string X,
+                                                       std::string S) {
+  auto Pos = S.find(X);
+  if (Pos == std::string::npos)
+    return std::make_pair(S, "");
+  return std::make_pair(S.substr(0, Pos), S.substr(Pos));
+}
+
 std::string DisassembleCmd(const std::string &FileName);
 
 std::string SearchRegexCmd(const std::string &Regex);
 
+size_t SimpleFastHash(const uint8_t *Data, size_t Size);
+
+inline uint32_t Log(uint32_t X) { return 32 - __builtin_clz(X) - 1; }
+
 }  // namespace fuzzer
 
 #endif  // LLVM_FUZZER_UTIL_H
--- a/tools/fuzzing/libfuzzer/FuzzerUtilDarwin.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerUtilDarwin.cpp
@@ -5,21 +5,23 @@
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 // Misc utils for Darwin.
 //===----------------------------------------------------------------------===//
 #include "FuzzerDefs.h"
 #if LIBFUZZER_APPLE
-
+#include "FuzzerCommand.h"
 #include "FuzzerIO.h"
 #include <mutex>
 #include <signal.h>
 #include <spawn.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/wait.h>
 
 // There is no header for this on macOS so declare here
 extern "C" char **environ;
 
 namespace fuzzer {
 
 static std::mutex SignalMutex;
@@ -31,17 +33,18 @@ static struct sigaction OldSigQuitAction
 static sigset_t OldBlockedSignalsSet;
 
 // This is a reimplementation of Libc's `system()`. On Darwin the Libc
 // implementation contains a mutex which prevents it from being used
 // concurrently. This implementation **can** be used concurrently. It sets the
 // signal handlers when the first thread enters and restores them when the last
 // thread finishes execution of the function and ensures this is not racey by
 // using a mutex.
-int ExecuteCommand(const std::string &Command) {
+int ExecuteCommand(const Command &Cmd) {
+  std::string CmdLine = Cmd.toString();
   posix_spawnattr_t SpawnAttributes;
   if (posix_spawnattr_init(&SpawnAttributes))
     return -1;
   // Block and ignore signals of the current process when the first thread
   // enters.
   {
     std::lock_guard<std::mutex> Lock(SignalMutex);
     if (ActiveThreadCount == 0) {
@@ -91,22 +94,27 @@ int ExecuteCommand(const std::string &Co
   (void)posix_spawnattr_setsigdefault(&SpawnAttributes, &DefaultSigSet);
   // Make sure the child process doesn't block SIGCHLD
   (void)posix_spawnattr_setsigmask(&SpawnAttributes, &OldBlockedSignalsSet);
   short SpawnFlags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
   (void)posix_spawnattr_setflags(&SpawnAttributes, SpawnFlags);
 
   pid_t Pid;
   char **Environ = environ; // Read from global
-  const char *CommandCStr = Command.c_str();
-  const char *Argv[] = {"sh", "-c", CommandCStr, NULL};
+  const char *CommandCStr = CmdLine.c_str();
+  char *const Argv[] = {
+    strdup("sh"),
+    strdup("-c"),
+    strdup(CommandCStr),
+    NULL
+  };
   int ErrorCode = 0, ProcessStatus = 0;
   // FIXME: We probably shouldn't hardcode the shell path.
   ErrorCode = posix_spawn(&Pid, "/bin/sh", NULL, &SpawnAttributes,
-                          (char *const *)Argv, Environ);
+                          Argv, Environ);
   (void)posix_spawnattr_destroy(&SpawnAttributes);
   if (!ErrorCode) {
     pid_t SavedPid = Pid;
     do {
       // Repeat until call completes uninterrupted.
       Pid = waitpid(SavedPid, &ProcessStatus, /*options=*/0);
     } while (Pid == -1 && errno == EINTR);
     if (Pid == -1) {
@@ -115,16 +123,18 @@ int ExecuteCommand(const std::string &Co
     }
   } else if (ErrorCode == ENOMEM || ErrorCode == EAGAIN) {
     // Fork failure.
     ProcessStatus = -1;
   } else {
     // Shell execution failure.
     ProcessStatus = W_EXITCODE(127, 0);
   }
+  for (unsigned i = 0, n = sizeof(Argv) / sizeof(Argv[0]); i < n; ++i)
+    free(Argv[i]);
 
   // Restore the signal handlers of the current process when the last thread
   // using this function finishes.
   {
     std::lock_guard<std::mutex> Lock(SignalMutex);
     --ActiveThreadCount;
     if (ActiveThreadCount == 0) {
       bool FailedRestore = false;
new file mode 100644
--- /dev/null
+++ b/tools/fuzzing/libfuzzer/FuzzerUtilFuchsia.cpp
@@ -0,0 +1,240 @@
+//===- FuzzerUtilFuchsia.cpp - Misc utils for Fuchsia. --------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Misc utils implementation using Fuchsia/Zircon APIs.
+//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+
+#if LIBFUZZER_FUCHSIA
+
+#include "FuzzerInternal.h"
+#include "FuzzerUtil.h"
+#include <cerrno>
+#include <cinttypes>
+#include <cstdint>
+#include <fcntl.h>
+#include <launchpad/launchpad.h>
+#include <string>
+#include <thread>
+#include <unistd.h>
+#include <zircon/errors.h>
+#include <zircon/process.h>
+#include <zircon/status.h>
+#include <zircon/syscalls.h>
+#include <zircon/syscalls/port.h>
+#include <zircon/types.h>
+
+namespace fuzzer {
+
+namespace {
+
+// A magic value for the Zircon exception port, chosen to spell 'FUZZING'
+// when interpreted as a byte sequence on little-endian platforms.
+const uint64_t kFuzzingCrash = 0x474e495a5a5546;
+
+void AlarmHandler(int Seconds) {
+  while (true) {
+    SleepSeconds(Seconds);
+    Fuzzer::StaticAlarmCallback();
+  }
+}
+
+void InterruptHandler() {
+  // Ctrl-C sends ETX in Zircon.
+  while (getchar() != 0x03);
+  Fuzzer::StaticInterruptCallback();
+}
+
+void CrashHandler(zx_handle_t *Port) {
+  std::unique_ptr<zx_handle_t> ExceptionPort(Port);
+  zx_port_packet_t Packet;
+  _zx_port_wait(*ExceptionPort, ZX_TIME_INFINITE, &Packet, 1);
+  // Unbind as soon as possible so we don't receive exceptions from this thread.
+  if (_zx_task_bind_exception_port(ZX_HANDLE_INVALID, ZX_HANDLE_INVALID,
+                                   kFuzzingCrash, 0) != ZX_OK) {
+    // Shouldn't happen; if it does the safest option is to just exit.
+    Printf("libFuzzer: unable to unbind exception port; aborting!\n");
+    exit(1);
+  }
+  if (Packet.key != kFuzzingCrash) {
+    Printf("libFuzzer: invalid crash key: %" PRIx64 "; aborting!\n",
+           Packet.key);
+    exit(1);
+  }
+  // CrashCallback should not return from this call
+  Fuzzer::StaticCrashSignalCallback();
+}
+
+} // namespace
+
+// Platform specific functions.
+void SetSignalHandler(const FuzzingOptions &Options) {
+  zx_status_t rc;
+
+  // Set up alarm handler if needed.
+  if (Options.UnitTimeoutSec > 0) {
+    std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1);
+    T.detach();
+  }
+
+  // Set up interrupt handler if needed.
+  if (Options.HandleInt || Options.HandleTerm) {
+    std::thread T(InterruptHandler);
+    T.detach();
+  }
+
+  // Early exit if no crash handler needed.
+  if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll &&
+      !Options.HandleFpe && !Options.HandleAbrt)
+    return;
+
+  // Create an exception port
+  zx_handle_t *ExceptionPort = new zx_handle_t;
+  if ((rc = _zx_port_create(0, ExceptionPort)) != ZX_OK) {
+    Printf("libFuzzer: zx_port_create failed: %s\n", _zx_status_get_string(rc));
+    exit(1);
+  }
+
+  // Bind the port to receive exceptions from our process
+  if ((rc = _zx_task_bind_exception_port(_zx_process_self(), *ExceptionPort,
+                                         kFuzzingCrash, 0)) != ZX_OK) {
+    Printf("libFuzzer: unable to bind exception port: %s\n",
+           zx_status_get_string(rc));
+    exit(1);
+  }
+
+  // Set up the crash handler.
+  std::thread T(CrashHandler, ExceptionPort);
+  T.detach();
+}
+
+void SleepSeconds(int Seconds) {
+  _zx_nanosleep(_zx_deadline_after(ZX_SEC(Seconds)));
+}
+
+unsigned long GetPid() {
+  zx_status_t rc;
+  zx_info_handle_basic_t Info;
+  if ((rc = zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info,
+                               sizeof(Info), NULL, NULL)) != ZX_OK) {
+    Printf("libFuzzer: unable to get info about self: %s\n",
+           zx_status_get_string(rc));
+    exit(1);
+  }
+  return Info.koid;
+}
+
+size_t GetPeakRSSMb() {
+  zx_status_t rc;
+  zx_info_task_stats_t Info;
+  if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_TASK_STATS, &Info,
+                               sizeof(Info), NULL, NULL)) != ZX_OK) {
+    Printf("libFuzzer: unable to get info about self: %s\n",
+           _zx_status_get_string(rc));
+    exit(1);
+  }
+  return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20;
+}
+
+template <typename Fn>
+class RunOnDestruction {
+ public:
+  explicit RunOnDestruction(Fn fn) : fn_(fn) {}
+  ~RunOnDestruction() { fn_(); }
+
+ private:
+  Fn fn_;
+};
+
+template <typename Fn>
+RunOnDestruction<Fn> at_scope_exit(Fn fn) {
+  return RunOnDestruction<Fn>(fn);
+}
+
+int ExecuteCommand(const Command &Cmd) {
+  zx_status_t rc;
+
+  // Convert arguments to C array
+  auto Args = Cmd.getArguments();
+  size_t Argc = Args.size();
+  assert(Argc != 0);
+  std::unique_ptr<const char *[]> Argv(new const char *[Argc]);
+  for (size_t i = 0; i < Argc; ++i)
+    Argv[i] = Args[i].c_str();
+
+  // Create the basic launchpad.  Clone everything except stdio.
+  launchpad_t *lp;
+  launchpad_create(ZX_HANDLE_INVALID, Argv[0], &lp);
+  launchpad_load_from_file(lp, Argv[0]);
+  launchpad_set_args(lp, Argc, Argv.get());
+  launchpad_clone(lp, LP_CLONE_ALL & (~LP_CLONE_FDIO_STDIO));
+
+  // Determine stdout
+  int FdOut = STDOUT_FILENO;
+
+  if (Cmd.hasOutputFile()) {
+    auto Filename = Cmd.getOutputFile();
+    FdOut = open(Filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0);
+    if (FdOut == -1) {
+      Printf("libFuzzer: failed to open %s: %s\n", Filename.c_str(),
+             strerror(errno));
+      return ZX_ERR_IO;
+    }
+  }
+  auto CloseFdOut = at_scope_exit([&]() { close(FdOut); } );
+
+  // Determine stderr
+  int FdErr = STDERR_FILENO;
+  if (Cmd.isOutAndErrCombined())
+    FdErr = FdOut;
+
+  // Clone the file descriptors into the new process
+  if ((rc = launchpad_clone_fd(lp, STDIN_FILENO, STDIN_FILENO)) != ZX_OK ||
+      (rc = launchpad_clone_fd(lp, FdOut, STDOUT_FILENO)) != ZX_OK ||
+      (rc = launchpad_clone_fd(lp, FdErr, STDERR_FILENO)) != ZX_OK) {
+    Printf("libFuzzer: failed to clone FDIO: %s\n", _zx_status_get_string(rc));
+    return rc;
+  }
+
+  // Start the process
+  zx_handle_t ProcessHandle = ZX_HANDLE_INVALID;
+  const char *ErrorMsg = nullptr;
+  if ((rc = launchpad_go(lp, &ProcessHandle, &ErrorMsg)) != ZX_OK) {
+    Printf("libFuzzer: failed to launch '%s': %s, %s\n", Argv[0], ErrorMsg,
+           _zx_status_get_string(rc));
+    return rc;
+  }
+  auto CloseHandle = at_scope_exit([&]() { _zx_handle_close(ProcessHandle); });
+
+  // Now join the process and return the exit status.
+  if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED,
+                                ZX_TIME_INFINITE, nullptr)) != ZX_OK) {
+    Printf("libFuzzer: failed to join '%s': %s\n", Argv[0],
+           _zx_status_get_string(rc));
+    return rc;
+  }
+
+  zx_info_process_t Info;
+  if ((rc = _zx_object_get_info(ProcessHandle, ZX_INFO_PROCESS, &Info,
+                                sizeof(Info), nullptr, nullptr)) != ZX_OK) {
+    Printf("libFuzzer: unable to get return code from '%s': %s\n", Argv[0],
+           zx_status_get_string(rc));
+    return rc;
+  }
+
+  return Info.return_code;
+}
+
+const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
+                         size_t PattLen) {
+  return memmem(Data, DataLen, Patt, PattLen);
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_FUCHSIA
--- a/tools/fuzzing/libfuzzer/FuzzerUtilLinux.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerUtilLinux.cpp
@@ -4,21 +4,23 @@
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 // Misc utils for Linux.
 //===----------------------------------------------------------------------===//
 #include "FuzzerDefs.h"
-#if LIBFUZZER_LINUX
+#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD
+#include "FuzzerCommand.h"
 
 #include <stdlib.h>
 
 namespace fuzzer {
 
-int ExecuteCommand(const std::string &Command) {
-  return system(Command.c_str());
+int ExecuteCommand(const Command &Cmd) {
+  std::string CmdLine = Cmd.toString();
+  return system(CmdLine.c_str());
 }
 
 } // namespace fuzzer
 
-#endif // LIBFUZZER_LINUX
+#endif // LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD
--- a/tools/fuzzing/libfuzzer/FuzzerUtilPosix.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerUtilPosix.cpp
@@ -13,17 +13,16 @@
 #include "FuzzerIO.h"
 #include "FuzzerInternal.h"
 #include <cassert>
 #include <chrono>
 #include <cstring>
 #include <errno.h>
 #include <iomanip>
 #include <signal.h>
-#include <sstream>
 #include <stdio.h>
 #include <sys/resource.h>
 #include <sys/syscall.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <thread>
 #include <unistd.h>
 
@@ -36,24 +35,41 @@ static void AlarmHandler(int, siginfo_t 
 static void CrashHandler(int, siginfo_t *, void *) {
   Fuzzer::StaticCrashSignalCallback();
 }
 
 static void InterruptHandler(int, siginfo_t *, void *) {
   Fuzzer::StaticInterruptCallback();
 }
 
+static void GracefulExitHandler(int, siginfo_t *, void *) {
+  Fuzzer::StaticGracefulExitCallback();
+}
+
 static void FileSizeExceedHandler(int, siginfo_t *, void *) {
   Fuzzer::StaticFileSizeExceedCallback();
 }
 
 static void SetSigaction(int signum,
                          void (*callback)(int, siginfo_t *, void *)) {
-  struct sigaction sigact;
-  memset(&sigact, 0, sizeof(sigact));
+  struct sigaction sigact = {};
+  if (sigaction(signum, nullptr, &sigact)) {
+    Printf("libFuzzer: sigaction failed with %d\n", errno);
+    exit(1);
+  }
+  if (sigact.sa_flags & SA_SIGINFO) {
+    if (sigact.sa_sigaction)
+      return;
+  } else {
+    if (sigact.sa_handler != SIG_DFL && sigact.sa_handler != SIG_IGN &&
+        sigact.sa_handler != SIG_ERR)
+      return;
+  }
+
+  sigact = {};
   sigact.sa_sigaction = callback;
   if (sigaction(signum, &sigact, 0)) {
     Printf("libFuzzer: sigaction failed with %d\n", errno);
     exit(1);
   }
 }
 
 void SetTimer(int Seconds) {
@@ -81,29 +97,33 @@ void SetSignalHandler(const FuzzingOptio
   if (Options.HandleAbrt)
     SetSigaction(SIGABRT, CrashHandler);
   if (Options.HandleIll)
     SetSigaction(SIGILL, CrashHandler);
   if (Options.HandleFpe)
     SetSigaction(SIGFPE, CrashHandler);
   if (Options.HandleXfsz)
     SetSigaction(SIGXFSZ, FileSizeExceedHandler);
+  if (Options.HandleUsr1)
+    SetSigaction(SIGUSR1, GracefulExitHandler);
+  if (Options.HandleUsr2)
+    SetSigaction(SIGUSR2, GracefulExitHandler);
 }
 
 void SleepSeconds(int Seconds) {
   sleep(Seconds); // Use C API to avoid coverage from instrumented libc++.
 }
 
 unsigned long GetPid() { return (unsigned long)getpid(); }
 
 size_t GetPeakRSSMb() {
   struct rusage usage;
   if (getrusage(RUSAGE_SELF, &usage))
     return 0;
-  if (LIBFUZZER_LINUX) {
+  if (LIBFUZZER_LINUX || LIBFUZZER_FREEBSD || LIBFUZZER_NETBSD) {
     // ru_maxrss is in KiB
     return usage.ru_maxrss >> 10;
   } else if (LIBFUZZER_APPLE) {
     // ru_maxrss is in bytes
     return usage.ru_maxrss >> 20;
   }
   assert(0 && "GetPeakRSSMb() is not implemented for your platform");
   return 0;
--- a/tools/fuzzing/libfuzzer/FuzzerUtilWindows.cpp
+++ b/tools/fuzzing/libfuzzer/FuzzerUtilWindows.cpp
@@ -5,29 +5,31 @@
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 // Misc utils implementation for Windows.
 //===----------------------------------------------------------------------===//
 #include "FuzzerDefs.h"
 #if LIBFUZZER_WINDOWS
+#include "FuzzerCommand.h"
 #include "FuzzerIO.h"
 #include "FuzzerInternal.h"
 #include <cassert>
 #include <chrono>
 #include <cstring>
 #include <errno.h>
 #include <iomanip>
 #include <signal.h>
-#include <sstream>
 #include <stdio.h>
 #include <sys/types.h>
 #include <windows.h>
-#include <psapi.h>
+
+// This must be included after windows.h.
+#include <Psapi.h>
 
 namespace fuzzer {
 
 static const FuzzingOptions* HandlerOpt = nullptr;
 
 static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
   switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
     case EXCEPTION_ACCESS_VIOLATION:
@@ -145,18 +147,19 @@ size_t GetPeakRSSMb() {
     return 0;
   return info.PeakWorkingSetSize >> 20;
 }
 
 FILE *OpenProcessPipe(const char *Command, const char *Mode) {
   return _popen(Command, Mode);
 }
 
-int ExecuteCommand(const std::string &Command) {
-  return system(Command.c_str());
+int ExecuteCommand(const Command &Cmd) {
+  std::string CmdLine = Cmd.toString();
+  return system(CmdLine.c_str());
 }
 
 const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
                          size_t PattLen) {
   // TODO: make this implementation more efficient.
   const char *Cdata = (const char *)Data;
   const char *Cpatt = (const char *)Patt;
 
--- a/tools/fuzzing/libfuzzer/FuzzerValueBitMap.h
+++ b/tools/fuzzing/libfuzzer/FuzzerValueBitMap.h
@@ -47,48 +47,27 @@ struct ValueBitMap {
 
   inline bool Get(uintptr_t Idx) {
     assert(Idx < kMapSizeInBits);
     uintptr_t WordIdx = Idx / kBitsInWord;
     uintptr_t BitIdx = Idx % kBitsInWord;
     return Map[WordIdx] & (1UL << BitIdx);
   }
 
-  size_t GetNumBitsSinceLastMerge() const { return NumBits; }
-
-  // Merges 'Other' into 'this', clears 'Other', updates NumBits,
-  // returns true if new bits were added.
-  ATTRIBUTE_TARGET_POPCNT
-  bool MergeFrom(ValueBitMap &Other) {
-    uintptr_t Res = 0;
-    size_t OldNumBits = NumBits;
-    for (size_t i = 0; i < kMapSizeInWords; i++) {
-      auto O = Other.Map[i];
-      auto M = Map[i];
-      if (O) {
-        Map[i] = (M |= O);
-        Other.Map[i] = 0;
-      }
-      if (M)
-        Res += __builtin_popcountll(M);
-    }
-    NumBits = Res;
-    return OldNumBits < NumBits;
-  }
+  size_t SizeInBits() const { return kMapSizeInBits; }
 
   template <class Callback>
   ATTRIBUTE_NO_SANITIZE_ALL
   void ForEach(Callback CB) const {
     for (size_t i = 0; i < kMapSizeInWords; i++)
       if (uintptr_t M = Map[i])
         for (size_t j = 0; j < sizeof(M) * 8; j++)
           if (M & ((uintptr_t)1 << j))
             CB(i * sizeof(M) * 8 + j);
   }
 
  private:
-  size_t NumBits = 0;
   uintptr_t Map[kMapSizeInWords] __attribute__((aligned(512)));
 };
 
 }  // namespace fuzzer
 
 #endif  // LLVM_FUZZER_VALUE_BIT_MAP_H
--- a/tools/fuzzing/libfuzzer/moz.build
+++ b/tools/fuzzing/libfuzzer/moz.build
@@ -6,16 +6,17 @@
 
 Library('fuzzer')
 
 EXPORTS += [
     'FuzzerDefs.h',
 ]
 
 SOURCES += [
+    'FuzzerClangCounters.cpp',
     'FuzzerCrossOver.cpp',
     'FuzzerDriver.cpp',
     'FuzzerExtFunctionsDlsym.cpp',
     'FuzzerExtFunctionsDlsymWin.cpp',
     'FuzzerExtFunctionsWeak.cpp',
     'FuzzerExtFunctionsWeakAlias.cpp',
     'FuzzerExtraCounters.cpp',
     'FuzzerIO.cpp',
@@ -23,17 +24,16 @@ SOURCES += [
     'FuzzerIOWindows.cpp',
     'FuzzerLoop.cpp',
     'FuzzerMerge.cpp',
     'FuzzerMutate.cpp',
     'FuzzerSHA1.cpp',
     'FuzzerShmemPosix.cpp',
     'FuzzerShmemWindows.cpp',
     'FuzzerTracePC.cpp',
-    'FuzzerTraceState.cpp',
     'FuzzerUtil.cpp',
     'FuzzerUtilDarwin.cpp',
     'FuzzerUtilLinux.cpp',
     'FuzzerUtilPosix.cpp',
     'FuzzerUtilWindows.cpp'
 ]
 
 if CONFIG['CC_TYPE'] == 'clang':