summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/fuzzer/FuzzerCorpus.h6
-rw-r--r--lib/fuzzer/FuzzerDriver.cpp2
-rw-r--r--lib/fuzzer/FuzzerFlags.def5
-rw-r--r--lib/fuzzer/FuzzerLoop.cpp25
-rw-r--r--lib/fuzzer/FuzzerOptions.h1
-rw-r--r--lib/fuzzer/FuzzerTracePC.cpp21
-rw-r--r--lib/fuzzer/FuzzerTracePC.h13
-rw-r--r--test/fuzzer/handle_unstable_minunstable.test12
8 files changed, 66 insertions, 19 deletions
diff --git a/lib/fuzzer/FuzzerCorpus.h b/lib/fuzzer/FuzzerCorpus.h
index f844c07c7..8ad14656c 100644
--- a/lib/fuzzer/FuzzerCorpus.h
+++ b/lib/fuzzer/FuzzerCorpus.h
@@ -238,6 +238,12 @@ class InputCorpus {
return false;
}
+ bool IsFeatureNew(size_t Idx, uint32_t NewSize, bool Shrink) {
+ assert(NewSize);
+ uint32_t OldSize = GetFeature(Idx % kFeatureSetSize);
+ return OldSize == 0 || (Shrink && OldSize > NewSize);
+ }
+
size_t NumFeatures() const { return NumAddedFeatures; }
size_t NumFeatureUpdates() const { return NumUpdatedFeatures; }
diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp
index eb849fcd0..4f40d6abf 100644
--- a/lib/fuzzer/FuzzerDriver.cpp
+++ b/lib/fuzzer/FuzzerDriver.cpp
@@ -619,6 +619,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
Options.PrintCorpusStats = Flags.print_corpus_stats;
Options.PrintCoverage = Flags.print_coverage;
Options.PrintUnstableStats = Flags.print_unstable_stats;
+ if (Flags.handle_unstable)
+ Options.HandleUnstable = Flags.handle_unstable;
Options.DumpCoverage = Flags.dump_coverage;
if (Flags.exit_on_src_pos)
Options.ExitOnSrcPos = Flags.exit_on_src_pos;
diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def
index dc92758e4..aa3a987b1 100644
--- a/lib/fuzzer/FuzzerFlags.def
+++ b/lib/fuzzer/FuzzerFlags.def
@@ -110,6 +110,11 @@ FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text"
FUZZER_FLAG_INT(dump_coverage, 0, "Deprecated."
" If 1, dump coverage information as a"
" .sancov file at exit.")
+FUZZER_FLAG_INT(handle_unstable, 0, "Experimental."
+ " Executes every input 3 times in total if a unique feature"
+ " is found during the first execution."
+ " If 1, we only use the minimum hit count from the 3 runs"
+ " to determine whether an input is interesting.")
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.")
diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp
index ffcd3419c..e63ee7361 100644
--- a/lib/fuzzer/FuzzerLoop.cpp
+++ b/lib/fuzzer/FuzzerLoop.cpp
@@ -465,11 +465,15 @@ void Fuzzer::CheckForUnstableCounters(const uint8_t *Data, size_t Size) {
// First Rerun
CBSetupAndRun();
- TPC.UpdateUnstableCounters();
+ TPC.UpdateUnstableCounters(Options.HandleUnstable);
// Second Rerun
CBSetupAndRun();
- TPC.UpdateUnstableCounters();
+ TPC.UpdateUnstableCounters(Options.HandleUnstable);
+
+ // Move minimum hit counts back to ModuleInline8bitCounters
+ if (Options.HandleUnstable)
+ TPC.ApplyUnstableCounters();
}
bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
@@ -482,6 +486,17 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
UniqFeatureSetTmp.clear();
size_t FoundUniqFeaturesOfII = 0;
size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
+ bool NewFeaturesUnstable = false;
+
+ if (Options.HandleUnstable || Options.PrintUnstableStats) {
+ TPC.CollectFeatures([&](size_t Feature) {
+ if (Corpus.IsFeatureNew(Feature, Size, Options.Shrink))
+ NewFeaturesUnstable = true;
+ });
+ if (NewFeaturesUnstable)
+ CheckForUnstableCounters(Data, Size);
+ }
+
TPC.CollectFeatures([&](size_t Feature) {
if (Corpus.AddFeature(Feature, Size, Options.Shrink))
UniqFeatureSetTmp.push_back(Feature);
@@ -490,16 +505,12 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
II->UniqFeatureSet.end(), Feature))
FoundUniqFeaturesOfII++;
});
+
if (FoundUniqFeatures)
*FoundUniqFeatures = FoundUniqFeaturesOfII;
PrintPulseAndReportSlowInput(Data, Size);
size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore;
- // If print_unstable_stats, execute the same input two more times to detect
- // unstable edges.
- if (NumNewFeatures && Options.PrintUnstableStats)
- CheckForUnstableCounters(Data, Size);
-
if (NumNewFeatures) {
TPC.UpdateObservedPCs();
Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile,
diff --git a/lib/fuzzer/FuzzerOptions.h b/lib/fuzzer/FuzzerOptions.h
index daa9104f5..ce39c0876 100644
--- a/lib/fuzzer/FuzzerOptions.h
+++ b/lib/fuzzer/FuzzerOptions.h
@@ -56,6 +56,7 @@ struct FuzzingOptions {
bool PrintCorpusStats = false;
bool PrintCoverage = false;
bool PrintUnstableStats = false;
+ int HandleUnstable = 0;
bool DumpCoverage = false;
bool DetectLeaks = true;
int PurgeAllocatorIntervalSec = 1;
diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp
index 983b47411..859ff6333 100644
--- a/lib/fuzzer/FuzzerTracePC.cpp
+++ b/lib/fuzzer/FuzzerTracePC.cpp
@@ -75,17 +75,26 @@ void TracePC::IterateInline8bitCounters(CallBack CB) const {
// counters.
void TracePC::InitializeUnstableCounters() {
IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
- if (UnstableCounters[UnstableIdx] != kUnstableCounter)
- UnstableCounters[UnstableIdx] = ModuleCounters[i].Start[j];
+ UnstableCounters[UnstableIdx].Counter = ModuleCounters[i].Start[j];
});
}
// Compares the current counters with counters from previous runs
// and records differences as unstable edges.
-void TracePC::UpdateUnstableCounters() {
+void TracePC::UpdateUnstableCounters(int UnstableMode) {
IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
- if (ModuleCounters[i].Start[j] != UnstableCounters[UnstableIdx])
- UnstableCounters[UnstableIdx] = kUnstableCounter;
+ if (ModuleCounters[i].Start[j] != UnstableCounters[UnstableIdx].Counter)
+ UnstableCounters[UnstableIdx].IsUnstable = true;
+ if (UnstableMode &&
+ ModuleCounters[i].Start[j] < UnstableCounters[UnstableIdx].Counter)
+ UnstableCounters[UnstableIdx].Counter = ModuleCounters[i].Start[j];
+ });
+}
+
+// Moves the minimum hit counts to ModuleCounters.
+void TracePC::ApplyUnstableCounters() {
+ IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
+ ModuleCounters[i].Start[j] = UnstableCounters[UnstableIdx].Counter;
});
}
@@ -340,7 +349,7 @@ void TracePC::DumpCoverage() {
void TracePC::PrintUnstableStats() {
size_t count = 0;
for (size_t i = 0; i < NumInline8bitCounters; i++)
- if (UnstableCounters[i] == kUnstableCounter)
+ if (UnstableCounters[i].IsUnstable)
count++;
Printf("stat::stability_rate: %.2f\n",
100 - static_cast<float>(count * 100) / NumInline8bitCounters);
diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h
index b37989dbd..a051568c4 100644
--- a/lib/fuzzer/FuzzerTracePC.h
+++ b/lib/fuzzer/FuzzerTracePC.h
@@ -138,15 +138,16 @@ class TracePC {
bool ObservedFocusFunction();
void InitializeUnstableCounters();
- void UpdateUnstableCounters();
+ void UpdateUnstableCounters(int UnstableMode);
+ void ApplyUnstableCounters();
private:
- // Value used to represent unstable edge.
- static constexpr int16_t kUnstableCounter = -1;
+ struct UnstableEdge {
+ uint8_t Counter;
+ bool IsUnstable;
+ };
- // Uses 16-bit signed type to be able to accommodate any possible value from
- // uint8_t counter and -1 constant as well.
- int16_t UnstableCounters[kNumPCs];
+ UnstableEdge UnstableCounters[kNumPCs];
bool UseCounters = false;
uint32_t UseValueProfileMask = false;
diff --git a/test/fuzzer/handle_unstable_minunstable.test b/test/fuzzer/handle_unstable_minunstable.test
new file mode 100644
index 000000000..fa082c4c5
--- /dev/null
+++ b/test/fuzzer/handle_unstable_minunstable.test
@@ -0,0 +1,12 @@
+RUN: %cpp_compiler %S/PrintUnstableStatsTest.cpp -o %t-HandleUnstableMinUnstableTest
+RUN: %run %t-HandleUnstableMinUnstableTest -print_coverage=1 -handle_unstable=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=UNSTABLE
+UNSTABLE-NOT: ini0()
+UNSTABLE-NOT: ini1()
+UNSTABLE-NOT: ini2()
+
+RUN: %run %t-HandleUnstableMinUnstableTest -print_coverage=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=NORMAL
+NORMAL-DAG: ini0()
+NORMAL-DAG: ini1()
+NORMAL-DAG: ini2()
+
+