[llvm] r284273 - [libFuzzer] add -trace_cmp=1 (guiding mutations based on the observed CMP instructions). This is a reincarnation of the previously deleted -use_traces, but using a different approach for collecting traces. Still a toy, but at least it scales well. Also fix -merge in trace-pc-guard mode
Kostya Serebryany via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 14 13:20:33 PDT 2016
Author: kcc
Date: Fri Oct 14 15:20:33 2016
New Revision: 284273
URL: http://llvm.org/viewvc/llvm-project?rev=284273&view=rev
Log:
[libFuzzer] add -trace_cmp=1 (guiding mutations based on the observed CMP instructions). This is a reincarnation of the previously deleted -use_traces, but using a different approach for collecting traces. Still a toy, but at least it scales well. Also fix -merge in trace-pc-guard mode
Modified:
llvm/trunk/lib/Fuzzer/FuzzerCorpus.h
llvm/trunk/lib/Fuzzer/FuzzerDefs.h
llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp
llvm/trunk/lib/Fuzzer/FuzzerFlags.def
llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp
llvm/trunk/lib/Fuzzer/FuzzerMutate.cpp
llvm/trunk/lib/Fuzzer/FuzzerMutate.h
llvm/trunk/lib/Fuzzer/FuzzerOptions.h
llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp
llvm/trunk/lib/Fuzzer/FuzzerTracePC.h
llvm/trunk/lib/Fuzzer/FuzzerTraceState.cpp
llvm/trunk/lib/Fuzzer/test/trace-malloc.test
Modified: llvm/trunk/lib/Fuzzer/FuzzerCorpus.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerCorpus.h?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerCorpus.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerCorpus.h Fri Oct 14 15:20:33 2016
@@ -153,6 +153,12 @@ class InputCorpus {
return Res;
}
+ void ResetFeatureSet() {
+ assert(Inputs.empty());
+ memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature));
+ memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature));
+ }
+
private:
static const bool FeatureDebug = false;
Modified: llvm/trunk/lib/Fuzzer/FuzzerDefs.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerDefs.h?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerDefs.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerDefs.h Fri Oct 14 15:20:33 2016
@@ -111,5 +111,11 @@ int NumberOfCpuCores();
int GetPid();
void SleepSeconds(int Seconds);
+
+struct ScopedDoingMyOwnMemmem {
+ ScopedDoingMyOwnMemmem();
+ ~ScopedDoingMyOwnMemmem();
+};
+
} // namespace fuzzer
#endif // LLVM_FUZZER_DEFS_H
Modified: llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp Fri Oct 14 15:20:33 2016
@@ -397,6 +397,7 @@ int FuzzerDriver(int *argc, char ***argv
Options.UseIndirCalls = Flags.use_indir_calls;
Options.UseMemcmp = Flags.use_memcmp;
Options.UseMemmem = Flags.use_memmem;
+ Options.UseCmp = Flags.use_cmp;
Options.UseValueProfile = Flags.use_value_profile;
Options.Shrink = Flags.shrink;
Options.ShuffleAtStartUp = Flags.shuffle;
Modified: llvm/trunk/lib/Fuzzer/FuzzerFlags.def
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerFlags.def?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerFlags.def (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerFlags.def Fri Oct 14 15:20:33 2016
@@ -49,6 +49,7 @@ FUZZER_FLAG_INT(use_memmem, 1,
"Use hints from intercepting memmem, strstr, etc")
FUZZER_FLAG_INT(use_value_profile, 0,
"Experimental. Use value profile to guide fuzzing.")
+FUZZER_FLAG_INT(use_cmp, 0, "Experimenta. Use CMP traces to guide mutations")
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"
@@ -92,7 +93,7 @@ FUZZER_FLAG_INT(close_fd_mask, 0, "If 1,
FUZZER_FLAG_INT(detect_leaks, 1, "If 1, and if LeakSanitizer is enabled "
"try to detect memory leaks during fuzzing (i.e. not only at shut down).")
FUZZER_FLAG_INT(trace_malloc, 0, "If >= 1 will print all mallocs/frees. "
- "If >= 2 will also print stack traces.")
+ "If >= 2 will also print stack traces.")
FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon"
"reaching this limit of RSS memory usage.")
FUZZER_FLAG_STRING(exit_on_src_pos, "Exit if a newly found PC originates"
Modified: llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp Fri Oct 14 15:20:33 2016
@@ -479,6 +479,9 @@ size_t Fuzzer::RunOne(const uint8_t *Dat
Res = 1;
}
+ if (Res && Options.UseCmp)
+ TPC.ProcessTORC(MD.GetTraceCmpDictionary(), CurrentUnitData, Size);
+
CheckExitOnSrcPos();
auto TimeOfUnit =
duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
@@ -513,6 +516,8 @@ void Fuzzer::ExecuteCallback(const uint8
UnitStartTime = system_clock::now();
ResetCounters(); // Reset coverage right before the callback.
TPC.ResetMaps();
+ if (Options.UseCmp)
+ TPC.ResetTORC();
if (Options.UseCounters)
TPC.ResetGuards();
int Res = CB(DataCopy, Size);
@@ -594,15 +599,22 @@ UnitVector Fuzzer::FindExtraUnits(const
ShuffleCorpus(&Res);
TPC.ResetMaps();
TPC.ResetGuards();
+ Corpus.ResetFeatureSet();
ResetCoverage();
- for (auto &U : Initial)
+ for (auto &U : Initial) {
+ TPC.ResetMaps();
+ TPC.ResetGuards();
RunOne(U);
+ }
Tmp.clear();
- for (auto &U : Res)
+ for (auto &U : Res) {
+ TPC.ResetMaps();
+ TPC.ResetGuards();
if (RunOne(U))
Tmp.push_back(U);
+ }
char Stat[7] = "MIN ";
Stat[3] = '0' + Iter;
Modified: llvm/trunk/lib/Fuzzer/FuzzerMutate.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerMutate.cpp?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerMutate.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerMutate.cpp Fri Oct 14 15:20:33 2016
@@ -43,12 +43,16 @@ MutationDispatcher::MutationDispatcher(R
{&MutationDispatcher::Mutate_CopyPart, "CopyPart"},
{&MutationDispatcher::Mutate_CrossOver, "CrossOver"},
{&MutationDispatcher::Mutate_AddWordFromManualDictionary,
- "AddFromManualDict"},
+ "ManualDict"},
{&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary,
- "AddFromTempAutoDict"},
+ "TempAutoDict"},
{&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
- "AddFromPersAutoDict"},
+ "PersAutoDict"},
});
+ if(Options.UseCmp)
+ DefaultMutators.push_back(
+ {&MutationDispatcher::Mutate_AddWordFromTraceCmpDictionary,
+ "TraceCmpDict"});
if (EF->LLVMFuzzerCustomMutator)
Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
@@ -171,6 +175,11 @@ size_t MutationDispatcher::Mutate_AddWor
return AddWordFromDictionary(TempAutoDictionary, Data, Size, MaxSize);
}
+size_t MutationDispatcher::Mutate_AddWordFromTraceCmpDictionary(
+ uint8_t *Data, size_t Size, size_t MaxSize) {
+ return AddWordFromDictionary(TraceCmpDictionary, Data, Size, MaxSize);
+}
+
size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary(
uint8_t *Data, size_t Size, size_t MaxSize) {
return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize);
Modified: llvm/trunk/lib/Fuzzer/FuzzerMutate.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerMutate.h?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerMutate.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerMutate.h Fri Oct 14 15:20:33 2016
@@ -55,6 +55,10 @@ public:
size_t Mutate_AddWordFromTemporaryAutoDictionary(uint8_t *Data, size_t Size,
size_t MaxSize);
+ /// Mutates data by adding a word from the trace-cmp dictionary.
+ size_t Mutate_AddWordFromTraceCmpDictionary(uint8_t *Data, size_t Size,
+ size_t MaxSize);
+
/// Mutates data by adding a word from the persistent automatic dictionary.
size_t Mutate_AddWordFromPersistentAutoDictionary(uint8_t *Data, size_t Size,
size_t MaxSize);
@@ -88,6 +92,8 @@ public:
Random &GetRand() { return Rand; }
+ Dictionary *GetTraceCmpDictionary() { return &TraceCmpDictionary; }
+
private:
struct Mutator {
@@ -116,6 +122,10 @@ private:
// Persistent dictionary modified by the fuzzer, consists of
// entries that led to successfull discoveries in the past mutations.
Dictionary PersistentAutoDictionary;
+
+ // Dictionary from tracing CMP instructions.
+ Dictionary TraceCmpDictionary;
+
std::vector<Mutator> CurrentMutatorSequence;
std::vector<DictionaryEntry *> CurrentDictionaryEntrySequence;
const InputCorpus *Corpus = nullptr;
Modified: llvm/trunk/lib/Fuzzer/FuzzerOptions.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerOptions.h?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerOptions.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerOptions.h Fri Oct 14 15:20:33 2016
@@ -30,6 +30,7 @@ struct FuzzingOptions {
bool UseIndirCalls = true;
bool UseMemcmp = true;
bool UseMemmem = true;
+ bool UseCmp = false;
bool UseValueProfile = false;
bool Shrink = false;
int ReloadIntervalSec = 1;
Modified: llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp Fri Oct 14 15:20:33 2016
@@ -14,6 +14,7 @@
#include "FuzzerCorpus.h"
#include "FuzzerDefs.h"
+#include "FuzzerDictionary.h"
#include "FuzzerTracePC.h"
#include "FuzzerValueBitMap.h"
@@ -170,11 +171,62 @@ __attribute__((always_inline))
#endif // __clang__
void TracePC::HandleCmp(void *PC, T Arg1, T Arg2) {
uintptr_t PCuint = reinterpret_cast<uintptr_t>(PC);
- uint64_t ArgDistance = __builtin_popcountl(Arg1 ^ Arg2) + 1; // [1,65]
+ uint64_t ArgXor = Arg1 ^ Arg2;
+ uint64_t ArgDistance = __builtin_popcountl(ArgXor) + 1; // [1,65]
uintptr_t Idx = ((PCuint & 4095) + 1) * ArgDistance;
+ TORCInsert(ArgXor, Arg1, Arg2);
HandleValueProfile(Idx);
}
+void TracePC::ProcessTORC(Dictionary *Dict, const uint8_t *Data, size_t Size) {
+ TORCToDict(TORC8, Dict, Data, Size);
+ TORCToDict(TORC4, Dict, Data, Size);
+}
+
+template <class T>
+void TracePC::TORCToDict(const TableOfRecentCompares<T, kTORCSize> &TORC,
+ Dictionary *Dict, const uint8_t *Data, size_t Size) {
+ ScopedDoingMyOwnMemmem scoped_doing_my_own_memmem;
+ for (size_t i = 0; i < TORC.kSize; i++) {
+ T A[2] = {TORC.Table[i][0], TORC.Table[i][1]};
+ if (!A[0] && !A[1]) continue;
+ for (int j = 0; j < 2; j++)
+ TORCToDict(Dict, A[j], A[!j], Data, Size);
+ }
+}
+
+template <class T>
+void TracePC::TORCToDict(Dictionary *Dict, T FindInData, T Substitute,
+ const uint8_t *Data, size_t Size) {
+ if (FindInData == Substitute) return;
+ if (sizeof(T) == 4) {
+ uint16_t HigherBytes = Substitute >> sizeof(T) * 4;
+ if (HigherBytes == 0 || HigherBytes == 0xffff)
+ TORCToDict(Dict, static_cast<uint16_t>(FindInData),
+ static_cast<uint16_t>(Substitute), Data, Size);
+ }
+ const size_t DataSize = sizeof(T);
+ const uint8_t *End = Data + Size;
+ int Attempts = 3;
+ // TODO: also swap bytes in FindInData.
+ for (const uint8_t *Cur = Data; Cur < End && Attempts--; Cur++) {
+ Cur = (uint8_t *)memmem(Cur, End - Cur, &FindInData, DataSize);
+ if (!Cur)
+ break;
+ size_t Pos = Cur - Data;
+ for (int Offset = 0; Offset <= 0; Offset++) {
+ T Tmp = Substitute + Offset;
+ Word W(reinterpret_cast<uint8_t *>(&Tmp), sizeof(Tmp));
+ DictionaryEntry DE(W, Pos);
+ // TODO: evict all entries from Dic if it's full.
+ Dict->push_back(DE);
+ // Printf("Dict[%zd] TORC%zd %llx => %llx pos %zd\n", Dict->size(),
+ // sizeof(T),
+ // (uint64_t)FindInData, (uint64_t)Tmp, Pos);
+ }
+ }
+}
+
} // namespace fuzzer
extern "C" {
Modified: llvm/trunk/lib/Fuzzer/FuzzerTracePC.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerTracePC.h?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerTracePC.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerTracePC.h Fri Oct 14 15:20:33 2016
@@ -17,6 +17,25 @@
namespace fuzzer {
+// TableOfRecentCompares (TORC) remembers the most recently performed
+// comparisons of type T.
+// We record the arguments of CMP instructions in this table unconditionally
+// because it seems cheaper this way than to compute some expensive
+// conditions inside __sanitizer_cov_trace_cmp*.
+// After the unit has been executed we may decide to use the contents of
+// this table to populate a Dictionary.
+template<class T, size_t kSizeT>
+struct TableOfRecentCompares {
+ static const size_t kSize = kSizeT;
+ void Insert(size_t Idx, T Arg1, T Arg2) {
+ Idx = Idx % kSize;
+ Table[Idx][0] = Arg1;
+ Table[Idx][1] = Arg2;
+ }
+ void Clear() { memset(Table, 0, sizeof(Table)); }
+ T Table[kSize][2];
+};
+
class TracePC {
public:
static const size_t kFeatureSetSize = ValueBitMap::kNumberOfItems;
@@ -48,6 +67,11 @@ class TracePC {
memset(Counters, 0, sizeof(Counters));
}
+ void ResetTORC() {
+ TORC4.Clear();
+ TORC8.Clear();
+ }
+
void UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize);
void PrintFeatureSet();
@@ -64,6 +88,8 @@ class TracePC {
bool UsingTracePcGuard() const {return NumModules; }
+ void ProcessTORC(Dictionary *Dict, const uint8_t *Data, size_t Size);
+
private:
bool UseCounters = false;
bool UseValueProfile = false;
@@ -87,6 +113,29 @@ private:
static const size_t kNumCounters = 1 << 14;
alignas(8) uint8_t Counters[kNumCounters];
+ static const size_t kTORCSize = 1 << 12;
+ TableOfRecentCompares<uint32_t, kTORCSize> TORC4;
+ TableOfRecentCompares<uint64_t, kTORCSize> TORC8;
+ void TORCInsert(size_t Idx, uint8_t Arg1, uint8_t Arg2) {
+ // Do nothing, too small to be interesting.
+ }
+ void TORCInsert(size_t Idx, uint16_t Arg1, uint16_t Arg2) {
+ // Do nothing, these don't usually hapen.
+ }
+ void TORCInsert(size_t Idx, uint32_t Arg1, uint32_t Arg2) {
+ TORC4.Insert(Idx, Arg1, Arg2);
+ }
+ void TORCInsert(size_t Idx, uint64_t Arg1, uint64_t Arg2) {
+ TORC8.Insert(Idx, Arg1, Arg2);
+ }
+
+ template <class T>
+ void TORCToDict(const TableOfRecentCompares<T, kTORCSize> &TORC,
+ Dictionary *Dict, const uint8_t *Data, size_t Size);
+ template <class T>
+ void TORCToDict(Dictionary *Dict, T FindInData, T Substitute,
+ const uint8_t *Data, size_t Size);
+
static const size_t kNumPCs = 1 << 24;
uintptr_t PCs[kNumPCs];
Modified: llvm/trunk/lib/Fuzzer/FuzzerTraceState.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerTraceState.cpp?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerTraceState.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerTraceState.cpp Fri Oct 14 15:20:33 2016
@@ -34,10 +34,8 @@ static bool RecordingMemcmp = false;
static bool RecordingMemmem = false;
static bool DoingMyOwnMemmem = false;
-struct ScopedDoingMyOwnMemmem {
- ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = true; }
- ~ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = false; }
-};
+ScopedDoingMyOwnMemmem::ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = true; }
+ScopedDoingMyOwnMemmem::~ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = false; }
class TraceState {
public:
Modified: llvm/trunk/lib/Fuzzer/test/trace-malloc.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/trace-malloc.test?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/trace-malloc.test (original)
+++ llvm/trunk/lib/Fuzzer/test/trace-malloc.test Fri Oct 14 15:20:33 2016
@@ -1,4 +1,4 @@
-RUN: LLVMFuzzer-TraceMallocTest -seed=1 -trace_malloc=1 -runs=1000 2>&1 | FileCheck %s
+RUN: LLVMFuzzer-TraceMallocTest -seed=1 -trace_malloc=1 -runs=10000 2>&1 | FileCheck %s
CHECK-DAG: MallocFreeTracer: STOP 0 0 (same)
CHECK-DAG: MallocFreeTracer: STOP 0 1 (DIFFERENT)
CHECK-DAG: MallocFreeTracer: STOP 1 0 (DIFFERENT)
More information about the llvm-commits
mailing list