Index: lib/fuzzer/FuzzerDriver.cpp
===================================================================
--- lib/fuzzer/FuzzerDriver.cpp
+++ lib/fuzzer/FuzzerDriver.cpp
@@ -15,6 +15,7 @@
 #include "FuzzerInterface.h"
 #include "FuzzerInternal.h"
 #include "FuzzerMutate.h"
+#include "FuzzerOptions.h"
 #include "FuzzerRandom.h"
 #include "FuzzerShmem.h"
 #include "FuzzerTracePC.h"
@@ -619,9 +620,9 @@
   Options.PrintCorpusStats = Flags.print_corpus_stats;
   Options.PrintCoverage = Flags.print_coverage;
   Options.PrintUnstableStats = Flags.print_unstable_stats;
-  if (Flags.handle_unstable == TracePC::MinUnstable ||
-      Flags.handle_unstable == TracePC::ZeroUnstable)
-    Options.HandleUnstable = Flags.handle_unstable;
+  if (Flags.handle_unstable > (int)UnstableMode::Start &&
+      Flags.handle_unstable < (int)UnstableMode::End)
+    Options.HandleUnstable = static_cast<UnstableMode>(Flags.handle_unstable);
   Options.DumpCoverage = Flags.dump_coverage;
   if (Flags.exit_on_src_pos)
     Options.ExitOnSrcPos = Flags.exit_on_src_pos;
Index: lib/fuzzer/FuzzerFlags.def
===================================================================
--- lib/fuzzer/FuzzerFlags.def
+++ lib/fuzzer/FuzzerFlags.def
@@ -116,7 +116,10 @@
                    " If 1, we only use the minimum hit count from the 3 runs"
                    " to determine whether an input is interesting."
                    " If 2, we disregard edges that are found unstable for"
-                   " feature collection.")
+                   " feature collection."
+                   " If 3, we collect features if a new stable edge is found."
+                   " Unstable edges will only be taken into account if it is"
+                   " found with a new stable edge.")
 FUZZER_FLAG_INT(print_unstable_stats, 0, "Experimental."
 				  " If 1, print unstable statistics at exit.")
 FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.")
Index: lib/fuzzer/FuzzerInternal.h
===================================================================
--- lib/fuzzer/FuzzerInternal.h
+++ lib/fuzzer/FuzzerInternal.h
@@ -67,7 +67,7 @@
   static void StaticGracefulExitCallback();
 
   void ExecuteCallback(const uint8_t *Data, size_t Size);
-  void CheckForUnstableCounters(const uint8_t *Data, size_t Size);
+  size_t CheckForUnstableCounters(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);
 
Index: lib/fuzzer/FuzzerLoop.cpp
===================================================================
--- lib/fuzzer/FuzzerLoop.cpp
+++ lib/fuzzer/FuzzerLoop.cpp
@@ -449,7 +449,7 @@
   }
 }
 
-void Fuzzer::CheckForUnstableCounters(const uint8_t *Data, size_t Size) {
+size_t Fuzzer::CheckForUnstableCounters(const uint8_t *Data, size_t Size) {
   auto CBSetupAndRun = [&]() {
     ScopedEnableMsanInterceptorChecks S;
     UnitStartTime = system_clock::now();
@@ -465,16 +465,19 @@
 
   // First Rerun
   CBSetupAndRun();
-  TPC.UpdateUnstableCounters(Options.HandleUnstable);
+  size_t NumNewUnstableEdges =
+      TPC.UpdateUnstableCounters(Options.HandleUnstable);
 
   // Second Rerun
   CBSetupAndRun();
-  TPC.UpdateUnstableCounters(Options.HandleUnstable);
+  NumNewUnstableEdges += TPC.UpdateUnstableCounters(Options.HandleUnstable);
 
   // Move minimum hit counts back to ModuleInline8bitCounters
-  if (Options.HandleUnstable == TracePC::MinUnstable ||
-      Options.HandleUnstable == TracePC::ZeroUnstable)
+  if (Options.HandleUnstable == UnstableMode::Min ||
+      Options.HandleUnstable == UnstableMode::Zero)
     TPC.ApplyUnstableCounters();
+
+  return NumNewUnstableEdges;
 }
 
 bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
@@ -488,14 +491,15 @@
   size_t FoundUniqFeaturesOfII = 0;
   size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
   bool NewFeaturesUnstable = false;
+  size_t NumNewUnstableEdges = 0;
 
-  if (Options.HandleUnstable || Options.PrintUnstableStats) {
+  if ((int)Options.HandleUnstable || Options.PrintUnstableStats) {
     TPC.CollectFeatures([&](size_t Feature) {
       if (Corpus.IsFeatureNew(Feature, Size, Options.Shrink))
         NewFeaturesUnstable = true;
     });
     if (NewFeaturesUnstable)
-      CheckForUnstableCounters(Data, Size);
+      NumNewUnstableEdges = CheckForUnstableCounters(Data, Size);
   }
 
   TPC.CollectFeatures([&](size_t Feature) {
@@ -512,6 +516,11 @@
   PrintPulseAndReportSlowInput(Data, Size);
   size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore;
 
+  if (Options.HandleUnstable == UnstableMode::Poison) {
+    assert(NumNewFeatures >= NumNewUnstableEdges);
+    NumNewFeatures -= NumNewUnstableEdges;
+  }
+
   if (NumNewFeatures) {
     TPC.UpdateObservedPCs();
     Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile,
Index: lib/fuzzer/FuzzerOptions.h
===================================================================
--- lib/fuzzer/FuzzerOptions.h
+++ lib/fuzzer/FuzzerOptions.h
@@ -15,6 +15,14 @@
 
 namespace fuzzer {
 
+enum class UnstableMode {
+  Start = 0,
+  Min = 1,
+  Zero = 2,
+  Poison = 3,
+  End = 4,
+};
+
 struct FuzzingOptions {
   int Verbosity = 1;
   size_t MaxLen = 0;
@@ -56,7 +64,7 @@
   bool PrintCorpusStats = false;
   bool PrintCoverage = false;
   bool PrintUnstableStats = false;
-  int HandleUnstable = 0;
+  UnstableMode HandleUnstable = UnstableMode::Start;
   bool DumpCoverage = false;
   bool DetectLeaks = true;
   int PurgeAllocatorIntervalSec = 1;
Index: lib/fuzzer/FuzzerTracePC.h
===================================================================
--- lib/fuzzer/FuzzerTracePC.h
+++ lib/fuzzer/FuzzerTracePC.h
@@ -14,6 +14,7 @@
 
 #include "FuzzerDefs.h"
 #include "FuzzerDictionary.h"
+#include "FuzzerOptions.h"
 #include "FuzzerValueBitMap.h"
 
 #include <set>
@@ -74,11 +75,6 @@
   // How many bits of PC are used from __sanitizer_cov_trace_pc.
   static const size_t kTracePcBits = 18;
 
-  enum HandleUnstableOptions {
-    MinUnstable = 1,
-    ZeroUnstable = 2,
-  };
-
   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);
@@ -143,7 +139,7 @@
   bool ObservedFocusFunction();
 
   void InitializeUnstableCounters();
-  void UpdateUnstableCounters(int UnstableMode);
+  size_t UpdateUnstableCounters(UnstableMode Mode);
   void ApplyUnstableCounters();
 
 private:
Index: lib/fuzzer/FuzzerTracePC.cpp
===================================================================
--- lib/fuzzer/FuzzerTracePC.cpp
+++ lib/fuzzer/FuzzerTracePC.cpp
@@ -81,17 +81,21 @@
 
 // Compares the current counters with counters from previous runs
 // and records differences as unstable edges.
-void TracePC::UpdateUnstableCounters(int UnstableMode) {
+size_t TracePC::UpdateUnstableCounters(UnstableMode Mode) {
+  size_t NumNewUnstableEdges = 0;
   IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
-    if (ModuleCounters[i].Start[j] != UnstableCounters[UnstableIdx].Counter) {
-      UnstableCounters[UnstableIdx].IsUnstable = true;
-      if (UnstableMode == ZeroUnstable)
-        UnstableCounters[UnstableIdx].Counter = 0;
-      else if (UnstableMode == MinUnstable)
-        UnstableCounters[UnstableIdx].Counter = std::min(
-            ModuleCounters[i].Start[j], UnstableCounters[UnstableIdx].Counter);
-    }
+    if (ModuleCounters[i].Start[j] == UnstableCounters[UnstableIdx].Counter)
+      return;
+    if (!UnstableCounters[UnstableIdx].IsUnstable)
+      NumNewUnstableEdges++;
+    UnstableCounters[UnstableIdx].IsUnstable = true;
+    if (Mode == UnstableMode::Zero)
+      UnstableCounters[UnstableIdx].Counter = 0;
+    else if (Mode == UnstableMode::Min)
+      UnstableCounters[UnstableIdx].Counter = std::min(
+          ModuleCounters[i].Start[j], UnstableCounters[UnstableIdx].Counter);
   });
+  return NumNewUnstableEdges;
 }
 
 // Moves the minimum hit counts to ModuleCounters.
Index: test/fuzzer/HandleUnstableTest.cpp
===================================================================
--- /dev/null
+++ test/fuzzer/HandleUnstableTest.cpp
@@ -0,0 +1,73 @@
+#include <assert.h>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+
+int x = 0;
+int c = 0;
+bool skip0 = false;
+bool skip1 = false;
+bool skip2 = false;
+
+__attribute__((noinline)) void det0() { x++; }
+__attribute__((noinline)) void det1() { x++; }
+__attribute__((noinline)) void det2() { x++; }
+
+__attribute__((noinline)) void ini0() { x++; }
+__attribute__((noinline)) void ini1() { x++; }
+__attribute__((noinline)) void ini2() { x++; }
+
+__attribute__((noinline)) void t0() { x++; }
+__attribute__((noinline)) void t1() { x++; }
+__attribute__((noinline)) void t2() { x++; }
+
+__attribute__((noinline)) void poison0() { x++; }
+__attribute__((noinline)) void poison1() { x++; }
+__attribute__((noinline)) void poison2() { x++; }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+  if (Size == 1 && Data[0] == 'A' && !skip0) {
+    skip0 = true;
+    ini0();
+  }
+  if (Size == 1 && Data[0] == 'B' && !skip1) {
+    skip1 = true;
+    ini1();
+  }
+  if (Size == 1 && Data[0] == 'C' && !skip2) {
+    skip2 = true;
+    ini2();
+  }
+
+  det0();
+  det1();
+  det2();
+
+  // c < 1000 on purpose so that when it enters the else condition, t0() gets
+  // collected since we detect new stable edge poison0().
+  if (c < 1000) {
+    switch (c % 3) {
+    case 0:
+      t0();
+      poison0();
+      break;
+    case 1:
+      t1();
+      poison1();
+      break;
+    case 2:
+      t2();
+      poison2();
+      break;
+    default:
+      assert(false);
+    }
+  } else {
+    poison0();
+    poison1();
+    poison2();
+  }
+  c++;
+
+  return 0;
+}
Index: test/fuzzer/handle-unstable.test
===================================================================
--- test/fuzzer/handle-unstable.test
+++ test/fuzzer/handle-unstable.test
@@ -1,42 +1,62 @@
 # Tests -handle_unstable
 UNSUPPORTED: aarch64
 
-RUN: %cpp_compiler %S/PrintUnstableStatsTest.cpp -o %t-HandleUnstableTest
+RUN: %cpp_compiler %S/HandleUnstableTest.cpp -o %t-HandleUnstableTest
 
 ; Normal
 RUN: %run %t-HandleUnstableTest -print_coverage=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=NORMAL
 NORMAL-DAG: det0()
 NORMAL-DAG: det1()
 NORMAL-DAG: det2()
-NORMAL-DAG: det3()
-NORMAL-DAG: det4()
 NORMAL-DAG: ini0()
 NORMAL-DAG: ini1()
 NORMAL-DAG: ini2()
 NORMAL-DAG: t0()
 NORMAL-DAG: t1()
 NORMAL-DAG: t2()
-NORMAL-DAG: t3()
-NORMAL-DAG: t4()
 
 ; MinUnstable
-RUN: %run %t-HandleUnstableTest -print_coverage=1 -handle_unstable=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=MIN
-MIN-NOT: ini0()
-MIN-NOT: ini1()
-MIN-NOT: ini2()
+run: %run %t-handleunstabletest -print_coverage=1 -handle_unstable=1 -runs=100000 2>&1 | filecheck %s --check-prefix=min
 MIN: det0()
 MIN: det1()
 MIN: det2()
-MIN: det3()
-MIN: det4()
+MIN: poison0()
+MIN: poison1()
+MIN: poison2()
+MIN-NOT: ini0()
+MIN-NOT: ini1()
+MIN-NOT: ini2()
+MIN-NOT: t0()
+MIN-NOT: t1()
+MIN-NOT: t2()
 
 ; ZeroUnstable
-RUN: %run %t-HandleUnstableTest -print_coverage=1 -handle_unstable=2 -runs=1 2>&1 | FileCheck %s --check-prefix=ZERO
-ZERO-NOT: ini0()
-ZERO-NOT: ini1()
-ZERO-NOT: ini2()
+run: %run %t-handleunstabletest -print_coverage=1 -handle_unstable=2 -runs=100000 2>&1 | filecheck %s --check-prefix=zero
 ZERO: det0()
 ZERO: det1()
 ZERO: det2()
-ZERO: det3()
-ZERO: det4()
+ZERO: poison0()
+ZERO: poison1()
+ZERO: poison2()
+ZERO-NOT: ini0()
+ZERO-NOT: ini1()
+ZERO-NOT: ini2()
+ZERO-NOT: t0()
+ZERO-NOT: t1()
+ZERO-NOT: t2()
+
+; PoisonUnstable
+RUN: %run %t-HandleUnstableTest -print_coverage=1 -handle_unstable=3 -runs=100000 2>&1 | FileCheck %s --check-prefix=POISON
+POISON: det0()
+POISON: det1()
+POISON: det2()
+; t0 is triggered because last iteration hits poison0() and it's next iterations always hit poison0() causing the input to collect t0() as well.
+POISON: t0()
+POISON: poison0()
+POISON: poison1()
+POISON: poison2()
+POISON-NOT: {{\b}}t1()
+POISON-NOT: {{\b}}t2()
+POISON-NOT: ini0()
+POISON-NOT: ini1()
+POISON-NOT: ini2()