[libFuzzer] implement the -shrink=1 option that tires to make elements of the corpus smaller, off by default
llvm-svn: 282995
diff --git a/llvm/lib/Fuzzer/FuzzerCorpus.h b/llvm/lib/Fuzzer/FuzzerCorpus.h
index 6438a60..802f700 100644
--- a/llvm/lib/Fuzzer/FuzzerCorpus.h
+++ b/llvm/lib/Fuzzer/FuzzerCorpus.h
@@ -58,6 +58,7 @@
ConstIter end() const { return Inputs.end(); }
bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); }
+ bool HasUnit(const std::string &H) { return Hashes.count(H); }
InputInfo &ChooseUnitToMutate(Random &Rand) {
return Inputs[ChooseUnitIdxToMutate(Rand)];
};
@@ -81,7 +82,7 @@
}
void PrintFeatureSet() {
- Printf("Features [id: cnt idx sz] ");
+ Printf("Features [id: idx sz] ");
for (size_t i = 0; i < kFeatureSetSize; i++) {
auto &Fe = FeatureSet[i];
if (!Fe.Count) continue;
diff --git a/llvm/lib/Fuzzer/FuzzerDriver.cpp b/llvm/lib/Fuzzer/FuzzerDriver.cpp
index 484d890..8f7820d 100644
--- a/llvm/lib/Fuzzer/FuzzerDriver.cpp
+++ b/llvm/lib/Fuzzer/FuzzerDriver.cpp
@@ -398,6 +398,7 @@
Options.UseMemcmp = Flags.use_memcmp;
Options.UseMemmem = Flags.use_memmem;
Options.UseValueProfile = Flags.use_value_profile;
+ Options.Shrink = Flags.shrink;
Options.ShuffleAtStartUp = Flags.shuffle;
Options.PreferSmall = Flags.prefer_small;
Options.Reload = Flags.reload;
@@ -429,6 +430,8 @@
Options.PrintCoverage = Flags.print_coverage;
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.
diff --git a/llvm/lib/Fuzzer/FuzzerFlags.def b/llvm/lib/Fuzzer/FuzzerFlags.def
index 230ad57..ea998bb 100644
--- a/llvm/lib/Fuzzer/FuzzerFlags.def
+++ b/llvm/lib/Fuzzer/FuzzerFlags.def
@@ -49,6 +49,7 @@
"Use hints from intercepting memmem, strstr, etc")
FUZZER_FLAG_INT(use_value_profile, 0,
"Experimental. Use value profile to guide fuzzing.")
+FUZZER_FLAG_INT(shrink, 0, "Experimental. Try to shrink corpus elements.")
FUZZER_FLAG_INT(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.")
@@ -95,6 +96,9 @@
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_DEPRECATED_FLAG(exit_on_first)
FUZZER_DEPRECATED_FLAG(save_minimized_corpus)
diff --git a/llvm/lib/Fuzzer/FuzzerInternal.h b/llvm/lib/Fuzzer/FuzzerInternal.h
index e85bd8a..ba538b8 100644
--- a/llvm/lib/Fuzzer/FuzzerInternal.h
+++ b/llvm/lib/Fuzzer/FuzzerInternal.h
@@ -117,6 +117,7 @@
bool DuringInitialCorpusExecution);
void AddToCorpus(const Unit &U);
void CheckExitOnSrcPos();
+ void CheckExitOnItem();
// Trace-based fuzzing: we run a unit with some kind of tracing
// enabled and record potentially useful mutations. Then
diff --git a/llvm/lib/Fuzzer/FuzzerLoop.cpp b/llvm/lib/Fuzzer/FuzzerLoop.cpp
index ab4a25d..f2e0f24 100644
--- a/llvm/lib/Fuzzer/FuzzerLoop.cpp
+++ b/llvm/lib/Fuzzer/FuzzerLoop.cpp
@@ -79,8 +79,6 @@
bool Fuzzer::RecordMaxCoverage(Fuzzer::Coverage *C) {
bool Res = false;
- TPC.FinalizeTrace();
-
uint64_t NewBlockCoverage = EF->__sanitizer_get_total_unique_coverage();
if (NewBlockCoverage > C->BlockCoverage) {
Res = true;
@@ -107,12 +105,6 @@
}
}
- if (TPC.UpdateCounterMap(&C->TPCMap))
- Res = true;
-
- if (TPC.UpdateValueProfileMap(&C->VPMap))
- Res = true;
-
return Res;
}
@@ -353,6 +345,16 @@
this->MaxMutationLen = MaxMutationLen;
}
+void Fuzzer::CheckExitOnItem() {
+ 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::CheckExitOnSrcPos() {
if (!Options.ExitOnSrcPos.empty()) {
uintptr_t *PCIDs;
@@ -422,7 +424,22 @@
TotalNumberOfRuns++;
ExecuteCallback(Data, Size);
- bool Res = RecordMaxCoverage(&MaxCoverage);
+ bool Res = false;
+
+ if (TPC.FinalizeTrace(Size))
+ if (Options.Shrink)
+ Res = true;
+
+ if (!Res) {
+ if (TPC.UpdateCounterMap(&MaxCoverage.TPCMap))
+ Res = true;
+
+ if (TPC.UpdateValueProfileMap(&MaxCoverage.VPMap))
+ Res = true;
+ }
+
+ if (RecordMaxCoverage(&MaxCoverage))
+ Res = true;
CheckExitOnSrcPos();
auto TimeOfUnit =
@@ -667,6 +684,7 @@
if (RunOne(CurrentUnitData, Size)) {
Corpus.AddToCorpus({CurrentUnitData, CurrentUnitData + Size});
ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size});
+ CheckExitOnItem();
}
StopTraceRecording();
TryDetectingAMemoryLeak(CurrentUnitData, Size,
diff --git a/llvm/lib/Fuzzer/FuzzerOptions.h b/llvm/lib/Fuzzer/FuzzerOptions.h
index 09b2cdec..04a44d8 100644
--- a/llvm/lib/Fuzzer/FuzzerOptions.h
+++ b/llvm/lib/Fuzzer/FuzzerOptions.h
@@ -31,6 +31,7 @@
bool UseMemcmp = true;
bool UseMemmem = true;
bool UseValueProfile = false;
+ bool Shrink = false;
bool Reload = true;
bool ShuffleAtStartUp = true;
bool PreferSmall = true;
@@ -41,6 +42,7 @@
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 OutputCSV = false;
diff --git a/llvm/lib/Fuzzer/FuzzerTracePC.cpp b/llvm/lib/Fuzzer/FuzzerTracePC.cpp
index f97da96..f02b71d 100644
--- a/llvm/lib/Fuzzer/FuzzerTracePC.cpp
+++ b/llvm/lib/Fuzzer/FuzzerTracePC.cpp
@@ -68,7 +68,8 @@
assert(N == NumGuards);
}
-void TracePC::FinalizeTrace() {
+bool TracePC::FinalizeTrace(size_t InputSize) {
+ bool Res = false;
if (TotalPCCoverage) {
const size_t Step = 8;
assert(reinterpret_cast<uintptr_t>(Counters) % Step == 0);
@@ -89,10 +90,17 @@
else if (Counter >= 4) Bit = 3;
else if (Counter >= 3) Bit = 2;
else if (Counter >= 2) Bit = 1;
- CounterMap.AddValue(i * 8 + Bit);
+ size_t Feature = i * 8 + Bit;
+ CounterMap.AddValue(Feature);
+ uint32_t *SizePtr = &InputSizesPerFeature[Feature];
+ if (!*SizePtr || *SizePtr > InputSize) {
+ *SizePtr = InputSize;
+ Res = true;
+ }
}
}
}
+ return Res;
}
void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
diff --git a/llvm/lib/Fuzzer/FuzzerTracePC.h b/llvm/lib/Fuzzer/FuzzerTracePC.h
index 1eb4a30..79ec7fb 100644
--- a/llvm/lib/Fuzzer/FuzzerTracePC.h
+++ b/llvm/lib/Fuzzer/FuzzerTracePC.h
@@ -35,7 +35,7 @@
bool UpdateValueProfileMap(ValueBitMap *MaxValueProfileMap) {
return UseValueProfile && MaxValueProfileMap->MergeFrom(ValueProfileMap);
}
- void FinalizeTrace();
+ bool FinalizeTrace(size_t InputSize);
size_t GetNewPCIDs(uintptr_t **NewPCIDsPtr) {
*NewPCIDsPtr = NewPCIDs;
@@ -90,6 +90,7 @@
ValueBitMap CounterMap;
ValueBitMap ValueProfileMap;
+ uint32_t InputSizesPerFeature[kFeatureSetSize];
};
extern TracePC TPC;