Source code

Revision control

Copy as Markdown

Other Tools

# HG changeset patch
# User Christian Holler <choller@mozilla.com>
# Date 1596126448 -7200
# Thu Jul 30 18:27:28 2020 +0200
# Node ID ea198a0331a6db043cb5978512226977514104db
# Parent 8a2a26b33d516c43c366b2f24d731d27d9843349
[libFuzzer] Change libFuzzer callback contract to allow positive return values
diff --git a/FuzzerInternal.h b/FuzzerInternal.h
--- a/FuzzerInternal.h
+++ b/FuzzerInternal.h
@@ -60,17 +60,17 @@ public:
static void StaticAlarmCallback();
static void StaticCrashSignalCallback();
static void StaticExitCallback();
static void StaticInterruptCallback();
static void StaticFileSizeExceedCallback();
static void StaticGracefulExitCallback();
- void ExecuteCallback(const uint8_t *Data, size_t Size);
+ int ExecuteCallback(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);
// Merge Corpora[1:] into Corpora[0].
void Merge(const Vector<std::string> &Corpora);
void CrashResistantMergeInternalStep(const std::string &ControlFilePath);
MutationDispatcher &GetMD() { return MD; }
void PrintFinalStats();
diff --git a/FuzzerLoop.cpp b/FuzzerLoop.cpp
--- a/FuzzerLoop.cpp
+++ b/FuzzerLoop.cpp
@@ -463,17 +463,19 @@ static void RenameFeatureSetFile(const s
DirPlusFile(FeaturesDir, NewFile));
}
bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
InputInfo *II, bool *FoundUniqFeatures) {
if (!Size)
return false;
- ExecuteCallback(Data, Size);
+ if (ExecuteCallback(Data, Size) > 0) {
+ return false;
+ }
UniqFeatureSetTmp.clear();
size_t FoundUniqFeaturesOfII = 0;
size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
TPC.CollectFeatures([&](size_t Feature) {
if (Corpus.AddFeature(Feature, Size, Options.Shrink))
UniqFeatureSetTmp.push_back(Feature);
if (Options.Entropic)
@@ -530,48 +532,49 @@ static bool LooseMemeq(const uint8_t *A,
const size_t Limit = 64;
if (Size <= 64)
return !memcmp(A, B, Size);
// Compare first and last Limit/2 bytes.
return !memcmp(A, B, Limit / 2) &&
!memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2);
}
-void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
+int Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
TPC.RecordInitialStack();
TotalNumberOfRuns++;
assert(InFuzzingThread());
// We copy the contents of Unit into a separate heap buffer
// so that we reliably find buffer overflows in it.
uint8_t *DataCopy = new uint8_t[Size];
memcpy(DataCopy, Data, Size);
if (EF->__msan_unpoison)
EF->__msan_unpoison(DataCopy, Size);
if (EF->__msan_unpoison_param)
EF->__msan_unpoison_param(2);
if (CurrentUnitData && CurrentUnitData != Data)
memcpy(CurrentUnitData, Data, Size);
CurrentUnitSize = Size;
+ int Res = 0;
{
ScopedEnableMsanInterceptorChecks S;
AllocTracer.Start(Options.TraceMalloc);
UnitStartTime = system_clock::now();
TPC.ResetMaps();
RunningUserCallback = true;
- int Res = CB(DataCopy, Size);
+ Res = CB(DataCopy, Size);
RunningUserCallback = false;
UnitStopTime = system_clock::now();
- (void)Res;
- assert(Res == 0);
+ assert(Res >= 0);
HasMoreMallocsThanFrees = AllocTracer.Stop();
}
if (!LooseMemeq(DataCopy, Data, Size))
CrashOnOverwrittenData();
CurrentUnitSize = 0;
delete[] DataCopy;
+ return Res;
}
std::string Fuzzer::WriteToOutputCorpus(const Unit &U) {
if (Options.OnlyASCII)
assert(IsASCII(U));
if (Options.OutputCorpus.empty())
return "";
std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
diff --git a/FuzzerMerge.cpp b/FuzzerMerge.cpp
--- a/FuzzerMerge.cpp
+++ b/FuzzerMerge.cpp
@@ -223,17 +223,19 @@ void Fuzzer::CrashResistantMergeInternal
U.shrink_to_fit();
}
// Write the pre-run marker.
OF << "STARTED " << i << " " << U.size() << "\n";
OF.flush(); // Flush is important since Command::Execute may crash.
// Run.
TPC.ResetMaps();
- ExecuteCallback(U.data(), U.size());
+ if (ExecuteCallback(U.data(), U.size()) > 0) {
+ continue;
+ }
// Collect coverage. We are iterating over the files in this order:
// * First, files in the initial corpus ordered by size, smallest first.
// * Then, all other files, smallest first.
// So it makes no sense to record all features for all files, instead we
// only record features that were not seen before.
Set<size_t> UniqFeatures;
TPC.CollectFeatures([&](size_t Feature) {
if (AllFeatures.insert(Feature).second)