[libFuzzer] add an experimental flag -focus_function: libFuzzer will try to focus on inputs that trigger that function
llvm-svn: 332554
GitOrigin-RevId: e9c6f06cce2c69e91c7dcffbef3bcacb05bdea71
diff --git a/FuzzerCorpus.h b/FuzzerCorpus.h
index 2da9298..05d527b 100644
--- a/FuzzerCorpus.h
+++ b/FuzzerCorpus.h
@@ -35,6 +35,7 @@
size_t NumSuccessfullMutations = 0;
bool MayDeleteFile = false;
bool Reduced = false;
+ bool HasFocusFunction = false;
Vector<uint32_t> UniqFeatureSet;
float FeatureFrequencyScore = 1.0;
};
@@ -70,10 +71,17 @@
Res = std::max(Res, II->U.size());
return Res;
}
+
+ size_t NumInputsThatTouchFocusFunction() {
+ return std::count_if(Inputs.begin(), Inputs.end(), [](const InputInfo *II) {
+ return II->HasFocusFunction;
+ });
+ }
+
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,
- const Vector<uint32_t> &FeatureSet) {
+ bool HasFocusFunction, const Vector<uint32_t> &FeatureSet) {
assert(!U.empty());
if (FeatureDebug)
Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures);
@@ -83,6 +91,7 @@
II.NumFeatures = NumFeatures;
II.MayDeleteFile = MayDeleteFile;
II.UniqFeatureSet = FeatureSet;
+ II.HasFocusFunction = HasFocusFunction;
std::sort(II.UniqFeatureSet.begin(), II.UniqFeatureSet.end());
ComputeSHA1(U.data(), U.size(), II.Sha1);
Hashes.insert(Sha1ToString(II.Sha1));
@@ -265,6 +274,7 @@
for (size_t i = 0; i < N; i++)
Weights[i] = Inputs[i]->NumFeatures
? (i + 1) * Inputs[i]->FeatureFrequencyScore
+ * (Inputs[i]->HasFocusFunction ? 1000 : 1)
: 0.;
if (FeatureDebug) {
for (size_t i = 0; i < N; i++)
diff --git a/FuzzerDriver.cpp b/FuzzerDriver.cpp
index 4f14373..26e5548 100644
--- a/FuzzerDriver.cpp
+++ b/FuzzerDriver.cpp
@@ -620,6 +620,8 @@
Options.ExitOnSrcPos = Flags.exit_on_src_pos;
if (Flags.exit_on_item)
Options.ExitOnItem = Flags.exit_on_item;
+ if (Flags.focus_function)
+ Options.FocusFunction = Flags.focus_function;
unsigned Seed = Flags.seed;
// Initialize Seed.
diff --git a/FuzzerFlags.def b/FuzzerFlags.def
index 64bd362..1ff3fd9 100644
--- a/FuzzerFlags.def
+++ b/FuzzerFlags.def
@@ -143,6 +143,8 @@
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(focus_function, "Experimental. "
+ "Fuzzing will focus on inputs that trigger calls to this function")
FUZZER_DEPRECATED_FLAG(run_equivalence_server)
FUZZER_DEPRECATED_FLAG(use_equivalence_server)
diff --git a/FuzzerLoop.cpp b/FuzzerLoop.cpp
index dfa6cf3..4bf5c78 100644
--- a/FuzzerLoop.cpp
+++ b/FuzzerLoop.cpp
@@ -159,6 +159,7 @@
AllocateCurrentUnitData();
CurrentUnitSize = 0;
memset(BaseSha1, 0, sizeof(BaseSha1));
+ TPC.SetFocusFunction(Options.FocusFunction);
}
Fuzzer::~Fuzzer() {}
@@ -333,6 +334,8 @@
else
Printf("/%zdMb", N >> 20);
}
+ if (size_t FF = Corpus.NumInputsThatTouchFocusFunction())
+ Printf(" focus: %zd", FF);
}
if (TmpMaxMutationLen)
Printf(" lim: %zd", TmpMaxMutationLen);
@@ -464,6 +467,7 @@
if (NumNewFeatures) {
TPC.UpdateObservedPCs();
Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile,
+ TPC.ObservedFocusFunction(),
UniqFeatureSetTmp);
return true;
}
@@ -733,6 +737,10 @@
}
PrintStats("INITED");
+ if (!Options.FocusFunction.empty())
+ Printf("INFO: %zd/%zd inputs touch the focus function\n",
+ Corpus.NumInputsThatTouchFocusFunction(), Corpus.size());
+
if (Corpus.empty()) {
Printf("ERROR: no interesting inputs were found. "
"Is the code instrumented for coverage? Exiting.\n");
diff --git a/FuzzerOptions.h b/FuzzerOptions.h
index 4fd4e8d..0c51d9e 100644
--- a/FuzzerOptions.h
+++ b/FuzzerOptions.h
@@ -45,6 +45,7 @@
std::string ExactArtifactPath;
std::string ExitOnSrcPos;
std::string ExitOnItem;
+ std::string FocusFunction;
bool SaveArtifacts = true;
bool PrintNEW = true; // Print a status line when new units are found;
bool PrintNewCovPcs = false;
diff --git a/FuzzerTracePC.cpp b/FuzzerTracePC.cpp
index 20230d4..ed62cdc 100644
--- a/FuzzerTracePC.cpp
+++ b/FuzzerTracePC.cpp
@@ -229,6 +229,39 @@
}
}
+void TracePC::SetFocusFunction(const std::string &FuncName) {
+ // This function should be called once.
+ assert(FocusFunction.first > NumModulesWithInline8bitCounters);
+ if (FuncName.empty())
+ return;
+ for (size_t M = 0; M < NumModulesWithInline8bitCounters; M++) {
+ auto &PCTE = ModulePCTable[M];
+ size_t N = PCTE.Stop - PCTE.Start;
+ for (size_t I = 0; I < N; I++) {
+ if (!(PCTE.Start[I].PCFlags & 1)) continue; // not a function entry.
+ auto Name = DescribePC("%F", GetNextInstructionPc(PCTE.Start[I].PC));
+ if (Name[0] == 'i' && Name[1] == 'n' && Name[2] == ' ')
+ Name = Name.substr(3, std::string::npos);
+ if (FuncName != Name) continue;
+ Printf("INFO: Focus function is set to '%s'\n", Name.c_str());
+ FocusFunction = {M, I};
+ return;
+ }
+ }
+}
+
+bool TracePC::ObservedFocusFunction() {
+ size_t I = FocusFunction.first;
+ size_t J = FocusFunction.second;
+ if (I >= NumModulesWithInline8bitCounters)
+ return false;
+ auto &MC = ModuleCounters[I];
+ size_t Size = MC.Stop - MC.Start;
+ if (J >= Size)
+ return false;
+ return MC.Start[J] != 0;
+}
+
void TracePC::PrintCoverage() {
if (!EF->__sanitizer_symbolize_pc ||
!EF->__sanitizer_get_module_and_offset_for_pc) {
diff --git a/FuzzerTracePC.h b/FuzzerTracePC.h
index d68da76..e1db512 100644
--- a/FuzzerTracePC.h
+++ b/FuzzerTracePC.h
@@ -131,6 +131,9 @@
CB(PC);
}
+ void SetFocusFunction(const std::string &FuncName);
+ bool ObservedFocusFunction();
+
private:
bool UseCounters = false;
bool UseValueProfile = false;
@@ -163,6 +166,9 @@
Set<uintptr_t> ObservedPCs;
Set<uintptr_t> ObservedFuncs;
+ std::pair<size_t, size_t> FocusFunction = {-1, -1}; // Module and PC IDs.
+
+
ValueBitMap ValueProfileMap;
uintptr_t InitialStack;
};
diff --git a/tests/FuzzerUnittest.cpp b/tests/FuzzerUnittest.cpp
index c795edd..a38a453 100644
--- a/tests/FuzzerUnittest.cpp
+++ b/tests/FuzzerUnittest.cpp
@@ -579,7 +579,7 @@
size_t N = 10;
size_t TriesPerUnit = 1<<16;
for (size_t i = 0; i < N; i++)
- C->AddToCorpus(Unit{ static_cast<uint8_t>(i) }, 1, false, {});
+ C->AddToCorpus(Unit{ static_cast<uint8_t>(i) }, 1, false, false, {});
Vector<size_t> Hist(N);
for (size_t i = 0; i < N * TriesPerUnit; i++) {