Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit ea5478c

Browse files
committed
[libFuzzer] Handle unstable edges by using minimum hit counts
Summary: Created unstable_handle flag that takes 1 or 2, depending on the handling type. Modified RunOne to accommodate the following heuristic: Use the first CollectFeatures to count how many features there are. If no new features, CollectFeatures like before. If there is new feature, we run CB 2 more times, Check which edges are unstable per input and we store the least amount of hit counts for each edge. Apply these hit counts back to inline8bitcounters so that CollectFeatures can work as intended. Modified UnstableCounters to 8int_t and created a bitset UnstableSet to tell which edges are unstable. Patch by Kyungtak Woo (@kevinwkt). Reviewers: Dor1s, metzman, morehouse Reviewed By: Dor1s, morehouse Subscribers: delcypher, #sanitizers, llvm-commits, kcc Differential Revision: https://reviews.llvm.org/D49525 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@337696 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 9e45fcd commit ea5478c

File tree

8 files changed

+66
-19
lines changed

8 files changed

+66
-19
lines changed

lib/fuzzer/FuzzerCorpus.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,12 @@ class InputCorpus {
238238
return false;
239239
}
240240

241+
bool IsFeatureNew(size_t Idx, uint32_t NewSize, bool Shrink) {
242+
assert(NewSize);
243+
uint32_t OldSize = GetFeature(Idx % kFeatureSetSize);
244+
return OldSize == 0 || (Shrink && OldSize > NewSize);
245+
}
246+
241247
size_t NumFeatures() const { return NumAddedFeatures; }
242248
size_t NumFeatureUpdates() const { return NumUpdatedFeatures; }
243249

lib/fuzzer/FuzzerDriver.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
619619
Options.PrintCorpusStats = Flags.print_corpus_stats;
620620
Options.PrintCoverage = Flags.print_coverage;
621621
Options.PrintUnstableStats = Flags.print_unstable_stats;
622+
if (Flags.handle_unstable)
623+
Options.HandleUnstable = Flags.handle_unstable;
622624
Options.DumpCoverage = Flags.dump_coverage;
623625
if (Flags.exit_on_src_pos)
624626
Options.ExitOnSrcPos = Flags.exit_on_src_pos;

lib/fuzzer/FuzzerFlags.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text"
110110
FUZZER_FLAG_INT(dump_coverage, 0, "Deprecated."
111111
" If 1, dump coverage information as a"
112112
" .sancov file at exit.")
113+
FUZZER_FLAG_INT(handle_unstable, 0, "Experimental."
114+
" Executes every input 3 times in total if a unique feature"
115+
" is found during the first execution."
116+
" If 1, we only use the minimum hit count from the 3 runs"
117+
" to determine whether an input is interesting.")
113118
FUZZER_FLAG_INT(print_unstable_stats, 0, "Experimental."
114119
" If 1, print unstable statistics at exit.")
115120
FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.")

lib/fuzzer/FuzzerLoop.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -465,11 +465,15 @@ void Fuzzer::CheckForUnstableCounters(const uint8_t *Data, size_t Size) {
465465

466466
// First Rerun
467467
CBSetupAndRun();
468-
TPC.UpdateUnstableCounters();
468+
TPC.UpdateUnstableCounters(Options.HandleUnstable);
469469

470470
// Second Rerun
471471
CBSetupAndRun();
472-
TPC.UpdateUnstableCounters();
472+
TPC.UpdateUnstableCounters(Options.HandleUnstable);
473+
474+
// Move minimum hit counts back to ModuleInline8bitCounters
475+
if (Options.HandleUnstable)
476+
TPC.ApplyUnstableCounters();
473477
}
474478

475479
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,
482486
UniqFeatureSetTmp.clear();
483487
size_t FoundUniqFeaturesOfII = 0;
484488
size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
489+
bool NewFeaturesUnstable = false;
490+
491+
if (Options.HandleUnstable || Options.PrintUnstableStats) {
492+
TPC.CollectFeatures([&](size_t Feature) {
493+
if (Corpus.IsFeatureNew(Feature, Size, Options.Shrink))
494+
NewFeaturesUnstable = true;
495+
});
496+
if (NewFeaturesUnstable)
497+
CheckForUnstableCounters(Data, Size);
498+
}
499+
485500
TPC.CollectFeatures([&](size_t Feature) {
486501
if (Corpus.AddFeature(Feature, Size, Options.Shrink))
487502
UniqFeatureSetTmp.push_back(Feature);
@@ -490,16 +505,12 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
490505
II->UniqFeatureSet.end(), Feature))
491506
FoundUniqFeaturesOfII++;
492507
});
508+
493509
if (FoundUniqFeatures)
494510
*FoundUniqFeatures = FoundUniqFeaturesOfII;
495511
PrintPulseAndReportSlowInput(Data, Size);
496512
size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore;
497513

498-
// If print_unstable_stats, execute the same input two more times to detect
499-
// unstable edges.
500-
if (NumNewFeatures && Options.PrintUnstableStats)
501-
CheckForUnstableCounters(Data, Size);
502-
503514
if (NumNewFeatures) {
504515
TPC.UpdateObservedPCs();
505516
Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile,

lib/fuzzer/FuzzerOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct FuzzingOptions {
5656
bool PrintCorpusStats = false;
5757
bool PrintCoverage = false;
5858
bool PrintUnstableStats = false;
59+
int HandleUnstable = 0;
5960
bool DumpCoverage = false;
6061
bool DetectLeaks = true;
6162
int PurgeAllocatorIntervalSec = 1;

lib/fuzzer/FuzzerTracePC.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,26 @@ void TracePC::IterateInline8bitCounters(CallBack CB) const {
7575
// counters.
7676
void TracePC::InitializeUnstableCounters() {
7777
IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
78-
if (UnstableCounters[UnstableIdx] != kUnstableCounter)
79-
UnstableCounters[UnstableIdx] = ModuleCounters[i].Start[j];
78+
UnstableCounters[UnstableIdx].Counter = ModuleCounters[i].Start[j];
8079
});
8180
}
8281

8382
// Compares the current counters with counters from previous runs
8483
// and records differences as unstable edges.
85-
void TracePC::UpdateUnstableCounters() {
84+
void TracePC::UpdateUnstableCounters(int UnstableMode) {
8685
IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
87-
if (ModuleCounters[i].Start[j] != UnstableCounters[UnstableIdx])
88-
UnstableCounters[UnstableIdx] = kUnstableCounter;
86+
if (ModuleCounters[i].Start[j] != UnstableCounters[UnstableIdx].Counter)
87+
UnstableCounters[UnstableIdx].IsUnstable = true;
88+
if (UnstableMode &&
89+
ModuleCounters[i].Start[j] < UnstableCounters[UnstableIdx].Counter)
90+
UnstableCounters[UnstableIdx].Counter = ModuleCounters[i].Start[j];
91+
});
92+
}
93+
94+
// Moves the minimum hit counts to ModuleCounters.
95+
void TracePC::ApplyUnstableCounters() {
96+
IterateInline8bitCounters([&](int i, int j, int UnstableIdx) {
97+
ModuleCounters[i].Start[j] = UnstableCounters[UnstableIdx].Counter;
8998
});
9099
}
91100

@@ -340,7 +349,7 @@ void TracePC::DumpCoverage() {
340349
void TracePC::PrintUnstableStats() {
341350
size_t count = 0;
342351
for (size_t i = 0; i < NumInline8bitCounters; i++)
343-
if (UnstableCounters[i] == kUnstableCounter)
352+
if (UnstableCounters[i].IsUnstable)
344353
count++;
345354
Printf("stat::stability_rate: %.2f\n",
346355
100 - static_cast<float>(count * 100) / NumInline8bitCounters);

lib/fuzzer/FuzzerTracePC.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,16 @@ class TracePC {
138138
bool ObservedFocusFunction();
139139

140140
void InitializeUnstableCounters();
141-
void UpdateUnstableCounters();
141+
void UpdateUnstableCounters(int UnstableMode);
142+
void ApplyUnstableCounters();
142143

143144
private:
144-
// Value used to represent unstable edge.
145-
static constexpr int16_t kUnstableCounter = -1;
145+
struct UnstableEdge {
146+
uint8_t Counter;
147+
bool IsUnstable;
148+
};
146149

147-
// Uses 16-bit signed type to be able to accommodate any possible value from
148-
// uint8_t counter and -1 constant as well.
149-
int16_t UnstableCounters[kNumPCs];
150+
UnstableEdge UnstableCounters[kNumPCs];
150151

151152
bool UseCounters = false;
152153
uint32_t UseValueProfileMask = false;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
RUN: %cpp_compiler %S/PrintUnstableStatsTest.cpp -o %t-HandleUnstableMinUnstableTest
2+
RUN: %run %t-HandleUnstableMinUnstableTest -print_coverage=1 -handle_unstable=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=UNSTABLE
3+
UNSTABLE-NOT: ini0()
4+
UNSTABLE-NOT: ini1()
5+
UNSTABLE-NOT: ini2()
6+
7+
RUN: %run %t-HandleUnstableMinUnstableTest -print_coverage=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=NORMAL
8+
NORMAL-DAG: ini0()
9+
NORMAL-DAG: ini1()
10+
NORMAL-DAG: ini2()
11+
12+

0 commit comments

Comments
 (0)