aboutsummaryrefslogtreecommitdiff
path: root/lib/Fuzzer/FuzzerLoop.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Fuzzer/FuzzerLoop.cpp')
-rw-r--r--lib/Fuzzer/FuzzerLoop.cpp243
1 files changed, 50 insertions, 193 deletions
diff --git a/lib/Fuzzer/FuzzerLoop.cpp b/lib/Fuzzer/FuzzerLoop.cpp
index 9f49d1557990..704092896eb6 100644
--- a/lib/Fuzzer/FuzzerLoop.cpp
+++ b/lib/Fuzzer/FuzzerLoop.cpp
@@ -14,6 +14,7 @@
#include "FuzzerIO.h"
#include "FuzzerMutate.h"
#include "FuzzerRandom.h"
+#include "FuzzerShmem.h"
#include "FuzzerTracePC.h"
#include <algorithm>
#include <cstring>
@@ -42,73 +43,11 @@ static const size_t kMaxUnitSizeToPrint = 256;
thread_local bool Fuzzer::IsMyThread;
-static void MissingExternalApiFunction(const char *FnName) {
- Printf("ERROR: %s is not defined. Exiting.\n"
- "Did you use -fsanitize-coverage=... to build your code?\n",
- FnName);
- exit(1);
-}
-
-#define CHECK_EXTERNAL_FUNCTION(fn) \
- do { \
- if (!(EF->fn)) \
- MissingExternalApiFunction(#fn); \
- } while (false)
+SharedMemoryRegion SMR;
// Only one Fuzzer per process.
static Fuzzer *F;
-void Fuzzer::ResetEdgeCoverage() {
- CHECK_EXTERNAL_FUNCTION(__sanitizer_reset_coverage);
- EF->__sanitizer_reset_coverage();
-}
-
-void Fuzzer::ResetCounters() {
- if (Options.UseCounters)
- EF->__sanitizer_update_counter_bitset_and_clear_counters(0);
-}
-
-void Fuzzer::PrepareCounters(Fuzzer::Coverage *C) {
- if (Options.UseCounters) {
- size_t NumCounters = EF->__sanitizer_get_number_of_counters();
- C->CounterBitmap.resize(NumCounters);
- }
-}
-
-// Records data to a maximum coverage tracker. Returns true if additional
-// coverage was discovered.
-bool Fuzzer::RecordMaxCoverage(Fuzzer::Coverage *C) {
- bool Res = false;
-
- uint64_t NewBlockCoverage = EF->__sanitizer_get_total_unique_coverage();
- if (NewBlockCoverage > C->BlockCoverage) {
- Res = true;
- C->BlockCoverage = NewBlockCoverage;
- }
-
- if (Options.UseIndirCalls &&
- EF->__sanitizer_get_total_unique_caller_callee_pairs) {
- uint64_t NewCallerCalleeCoverage =
- EF->__sanitizer_get_total_unique_caller_callee_pairs();
- if (NewCallerCalleeCoverage > C->CallerCalleeCoverage) {
- Res = true;
- C->CallerCalleeCoverage = NewCallerCalleeCoverage;
- }
- }
-
- if (Options.UseCounters) {
- uint64_t CounterDelta =
- EF->__sanitizer_update_counter_bitset_and_clear_counters(
- C->CounterBitmap.data());
- if (CounterDelta > 0) {
- Res = true;
- C->CounterBitmapBits += CounterDelta;
- }
- }
-
- return Res;
-}
-
// Leak detection is expensive, so we first check if there were more mallocs
// than frees (using the sanitizer malloc hooks) and only then try to call lsan.
struct MallocFreeTracer {
@@ -176,12 +115,12 @@ void Fuzzer::HandleMalloc(size_t Size) {
Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
FuzzingOptions Options)
: CB(CB), Corpus(Corpus), MD(MD), Options(Options) {
- SetDeathCallback();
+ if (EF->__sanitizer_set_death_callback)
+ EF->__sanitizer_set_death_callback(StaticDeathCallback);
InitializeTraceState();
assert(!F);
F = this;
TPC.ResetMaps();
- ResetCoverage();
IsMyThread = true;
if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks)
EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);
@@ -206,33 +145,12 @@ void Fuzzer::AllocateCurrentUnitData() {
CurrentUnitData = new uint8_t[MaxInputLen];
}
-void Fuzzer::SetDeathCallback() {
- CHECK_EXTERNAL_FUNCTION(__sanitizer_set_death_callback);
- EF->__sanitizer_set_death_callback(StaticDeathCallback);
-}
-
void Fuzzer::StaticDeathCallback() {
assert(F);
F->DeathCallback();
}
-static void WarnOnUnsuccessfullMerge(bool DoWarn) {
- if (!DoWarn) return;
- Printf(
- "***\n"
- "***\n"
- "***\n"
- "*** NOTE: merge did not succeed due to a failure on one of the inputs.\n"
- "*** You will need to filter out crashes from the corpus, e.g. like this:\n"
- "*** for f in WITH_CRASHES/*; do ./fuzzer $f && cp $f NO_CRASHES; done\n"
- "*** Future versions may have crash-resistant merge, stay tuned.\n"
- "***\n"
- "***\n"
- "***\n");
-}
-
void Fuzzer::DumpCurrentUnit(const char *Prefix) {
- WarnOnUnsuccessfullMerge(InMergeMode);
if (!CurrentUnitData) return; // Happens when running individual inputs.
MD.PrintMutationSequence();
Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str());
@@ -293,7 +211,10 @@ void Fuzzer::InterruptCallback() {
NO_SANITIZE_MEMORY
void Fuzzer::AlarmCallback() {
assert(Options.UnitTimeoutSec > 0);
+ // In Windows Alarm callback is executed by a different thread.
+#if !LIBFUZZER_WINDOWS
if (!InFuzzingThread()) return;
+#endif
if (!RunningCB)
return; // We have not started running units yet.
size_t Seconds =
@@ -323,7 +244,7 @@ void Fuzzer::RssLimitCallback() {
GetPid(), GetPeakRSSMb(), Options.RssLimitMb);
Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
if (EF->__sanitizer_print_memory_profile)
- EF->__sanitizer_print_memory_profile(95);
+ EF->__sanitizer_print_memory_profile(95, 8);
DumpCurrentUnit("oom-");
Printf("SUMMARY: libFuzzer: out-of-memory\n");
PrintFinalStats();
@@ -338,26 +259,18 @@ void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) {
csvHeaderPrinted = true;
Printf("runs,block_cov,bits,cc_cov,corpus,execs_per_sec,tbms,reason\n");
}
- Printf("%zd,%zd,%zd,%zd,%zd,%zd,%s\n", TotalNumberOfRuns,
- MaxCoverage.BlockCoverage, MaxCoverage.CounterBitmapBits,
- MaxCoverage.CallerCalleeCoverage, Corpus.size(), ExecPerSec, Where);
+ Printf("%zd,%zd,%zd,%zd,%s\n", TotalNumberOfRuns,
+ TPC.GetTotalPCCoverage(),
+ Corpus.size(), ExecPerSec, Where);
}
if (!Options.Verbosity)
return;
Printf("#%zd\t%s", TotalNumberOfRuns, Where);
- if (MaxCoverage.BlockCoverage)
- Printf(" cov: %zd", MaxCoverage.BlockCoverage);
- if (size_t N = MaxCoverage.VPMap.GetNumBitsSinceLastMerge())
- Printf(" vp: %zd", N);
if (size_t N = TPC.GetTotalPCCoverage())
Printf(" cov: %zd", N);
- if (auto TB = MaxCoverage.CounterBitmapBits)
- Printf(" bits: %zd", TB);
if (size_t N = Corpus.NumFeatures())
Printf( " ft: %zd", N);
- if (MaxCoverage.CallerCalleeCoverage)
- Printf(" indir: %zd", MaxCoverage.CallerCalleeCoverage);
if (!Corpus.empty()) {
Printf(" corp: %zd", Corpus.NumActiveUnits());
if (size_t N = Corpus.SizeInBytes()) {
@@ -456,7 +369,7 @@ void Fuzzer::RereadOutputCorpus(size_t MaxSize) {
}
void Fuzzer::ShuffleCorpus(UnitVector *V) {
- std::random_shuffle(V->begin(), V->end(), MD.GetRand());
+ std::shuffle(V->begin(), V->end(), MD.GetRand());
if (Options.PreferSmall)
std::stable_sort(V->begin(), V->end(), [](const Unit &A, const Unit &B) {
return A.size() < B.size();
@@ -476,8 +389,6 @@ void Fuzzer::ShuffleAndMinimize(UnitVector *InitialCorpus) {
if (size_t NumFeatures = RunOne(U)) {
CheckExitOnSrcPosOrItem();
Corpus.AddToCorpus(U, NumFeatures);
- if (Options.Verbosity >= 2)
- Printf("NEW0: %zd L %zd\n", MaxCoverage.BlockCoverage, U.size());
}
TryDetectingAMemoryLeak(U.data(), U.size(),
/*DuringInitialCorpusExecution*/ true);
@@ -496,18 +407,11 @@ size_t Fuzzer::RunOne(const uint8_t *Data, size_t Size) {
ExecuteCallback(Data, Size);
- size_t Res = 0;
- if (size_t NumFeatures = TPC.CollectFeatures([&](size_t Feature) -> bool {
- return Corpus.AddFeature(Feature, Size, Options.Shrink);
- }))
- Res = NumFeatures;
-
- if (!TPC.UsingTracePcGuard()) {
- if (TPC.UpdateValueProfileMap(&MaxCoverage.VPMap))
- Res = 1;
- if (!Res && RecordMaxCoverage(&MaxCoverage))
- Res = 1;
- }
+ size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
+ TPC.CollectFeatures([&](size_t Feature) {
+ Corpus.AddFeature(Feature, Size, Options.Shrink);
+ });
+ size_t NumUpdatesAfter = Corpus.NumFeatureUpdates();
auto TimeOfUnit =
duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
@@ -520,7 +424,7 @@ size_t Fuzzer::RunOne(const uint8_t *Data, size_t Size) {
Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds);
WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-");
}
- return Res;
+ return NumUpdatesAfter - NumUpdatesBefore;
}
size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
@@ -531,6 +435,8 @@ size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
assert(InFuzzingThread());
+ if (SMR.IsClient())
+ SMR.WriteByteArray(Data, Size);
// 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];
@@ -540,7 +446,6 @@ void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
CurrentUnitSize = Size;
AllocTracer.Start(Options.TraceMalloc);
UnitStartTime = system_clock::now();
- ResetCounters(); // Reset coverage right before the callback.
TPC.ResetMaps();
RunningCB = true;
int Res = CB(DataCopy, Size);
@@ -597,77 +502,6 @@ void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) {
TPC.PrintNewPCs();
}
-// Finds minimal number of units in 'Extra' that add coverage to 'Initial'.
-// We do it by actually executing the units, sometimes more than once,
-// because we may be using different coverage-like signals and the only
-// common thing between them is that we can say "this unit found new stuff".
-UnitVector Fuzzer::FindExtraUnits(const UnitVector &Initial,
- const UnitVector &Extra) {
- UnitVector Res = Extra;
- UnitVector Tmp;
- size_t OldSize = Res.size();
- for (int Iter = 0; Iter < 10; Iter++) {
- ShuffleCorpus(&Res);
- TPC.ResetMaps();
- Corpus.ResetFeatureSet();
- ResetCoverage();
-
- for (auto &U : Initial) {
- TPC.ResetMaps();
- RunOne(U);
- }
-
- Tmp.clear();
- for (auto &U : Res) {
- TPC.ResetMaps();
- if (RunOne(U))
- Tmp.push_back(U);
- }
-
- char Stat[7] = "MIN ";
- Stat[3] = '0' + Iter;
- PrintStats(Stat, "\n", Tmp.size());
-
- size_t NewSize = Tmp.size();
- assert(NewSize <= OldSize);
- Res.swap(Tmp);
-
- if (NewSize + 5 >= OldSize)
- break;
- OldSize = NewSize;
- }
- return Res;
-}
-
-void Fuzzer::Merge(const std::vector<std::string> &Corpora) {
- if (Corpora.size() <= 1) {
- Printf("Merge requires two or more corpus dirs\n");
- return;
- }
- InMergeMode = true;
- std::vector<std::string> ExtraCorpora(Corpora.begin() + 1, Corpora.end());
-
- assert(MaxInputLen > 0);
- UnitVector Initial, Extra;
- ReadDirToVectorOfUnits(Corpora[0].c_str(), &Initial, nullptr, MaxInputLen,
- true);
- for (auto &C : ExtraCorpora)
- ReadDirToVectorOfUnits(C.c_str(), &Extra, nullptr, MaxInputLen, true);
-
- if (!Initial.empty()) {
- Printf("=== Minimizing the initial corpus of %zd units\n", Initial.size());
- Initial = FindExtraUnits({}, Initial);
- }
-
- Printf("=== Merging extra %zd units\n", Extra.size());
- auto Res = FindExtraUnits(Initial, Extra);
-
- for (auto &U: Res)
- WriteToOutputCorpus(U);
-
- Printf("=== Merge: written %zd units\n", Res.size());
-}
-
// Tries detecting a memory leak on the particular input that we have just
// executed before calling this function.
void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
@@ -762,12 +596,6 @@ void Fuzzer::MutateAndTestOne() {
}
}
-void Fuzzer::ResetCoverage() {
- ResetEdgeCoverage();
- MaxCoverage.Reset();
- PrepareCounters(&MaxCoverage);
-}
-
void Fuzzer::Loop() {
TPC.InitializePrintNewPCs();
system_clock::time_point LastCorpusReload = system_clock::now();
@@ -792,7 +620,7 @@ void Fuzzer::Loop() {
}
void Fuzzer::MinimizeCrashLoop(const Unit &U) {
- if (U.size() <= 2) return;
+ if (U.size() <= 1) return;
while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) {
MD.StartMutationSequence();
memcpy(CurrentUnitData, U.data(), U.size());
@@ -806,6 +634,29 @@ void Fuzzer::MinimizeCrashLoop(const Unit &U) {
}
}
+void Fuzzer::AnnounceOutput(const uint8_t *Data, size_t Size) {
+ if (SMR.IsServer()) {
+ SMR.WriteByteArray(Data, Size);
+ } else if (SMR.IsClient()) {
+ SMR.PostClient();
+ SMR.WaitServer();
+ size_t OtherSize = SMR.ReadByteArraySize();
+ uint8_t *OtherData = SMR.GetByteArray();
+ if (Size != OtherSize || memcmp(Data, OtherData, Size) != 0) {
+ size_t i = 0;
+ for (i = 0; i < Min(Size, OtherSize); i++)
+ if (Data[i] != OtherData[i])
+ break;
+ Printf("==%lu== ERROR: libFuzzer: equivalence-mismatch. Sizes: %zd %zd; "
+ "offset %zd\n", GetPid(), Size, OtherSize, i);
+ DumpCurrentUnit("mismatch-");
+ Printf("SUMMARY: libFuzzer: equivalence-mismatch\n");
+ PrintFinalStats();
+ _Exit(Options.ErrorExitCode);
+ }
+ }
+}
+
} // namespace fuzzer
extern "C" {
@@ -814,4 +665,10 @@ size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
assert(fuzzer::F);
return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize);
}
+
+// Experimental
+void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) {
+ assert(fuzzer::F);
+ fuzzer::F->AnnounceOutput(Data, Size);
+}
} // extern "C"