aboutsummaryrefslogtreecommitdiff
path: root/lib/Fuzzer/FuzzerTraceState.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Fuzzer/FuzzerTraceState.cpp')
-rw-r--r--lib/Fuzzer/FuzzerTraceState.cpp175
1 files changed, 39 insertions, 136 deletions
diff --git a/lib/Fuzzer/FuzzerTraceState.cpp b/lib/Fuzzer/FuzzerTraceState.cpp
index 2ad9702fab0e..a486223d650c 100644
--- a/lib/Fuzzer/FuzzerTraceState.cpp
+++ b/lib/Fuzzer/FuzzerTraceState.cpp
@@ -13,7 +13,6 @@
#include "FuzzerInternal.h"
#include "FuzzerIO.h"
#include "FuzzerMutate.h"
-#include "FuzzerRandom.h"
#include "FuzzerTracePC.h"
#include <algorithm>
#include <cstring>
@@ -23,19 +22,10 @@
namespace fuzzer {
-// For now, very simple: put Size bytes of Data at position Pos.
-struct TraceBasedMutation {
- uint32_t Pos;
- Word W;
-};
-
// Declared as static globals for faster checks inside the hooks.
-static bool RecordingMemcmp = false;
static bool RecordingMemmem = false;
-static bool DoingMyOwnMemmem = false;
-ScopedDoingMyOwnMemmem::ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = true; }
-ScopedDoingMyOwnMemmem::~ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = false; }
+int ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr;
class TraceState {
public:
@@ -43,64 +33,21 @@ public:
const Fuzzer *F)
: MD(MD), Options(Options), F(F) {}
- void TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
- const uint8_t *Data2);
-
- int TryToAddDesiredData(const uint8_t *PresentData,
- const uint8_t *DesiredData, size_t DataSize);
-
void StartTraceRecording() {
- if (!Options.UseMemcmp)
+ if (!Options.UseMemmem)
return;
- RecordingMemcmp = Options.UseMemcmp;
- RecordingMemmem = Options.UseMemmem;
- NumMutations = 0;
+ RecordingMemmem = true;
InterestingWords.clear();
MD.ClearAutoDictionary();
}
void StopTraceRecording() {
- if (!RecordingMemcmp)
+ if (!RecordingMemmem)
return;
- RecordingMemcmp = false;
- for (size_t i = 0; i < NumMutations; i++) {
- auto &M = Mutations[i];
- if (Options.Verbosity >= 2) {
- AutoDictUnitCounts[M.W]++;
- AutoDictAdds++;
- if ((AutoDictAdds & (AutoDictAdds - 1)) == 0) {
- typedef std::pair<size_t, Word> CU;
- std::vector<CU> CountedUnits;
- for (auto &I : AutoDictUnitCounts)
- CountedUnits.push_back(std::make_pair(I.second, I.first));
- std::sort(CountedUnits.begin(), CountedUnits.end(),
- [](const CU &a, const CU &b) { return a.first > b.first; });
- Printf("AutoDict:\n");
- for (auto &I : CountedUnits) {
- Printf(" %zd ", I.first);
- PrintASCII(I.second.data(), I.second.size());
- Printf("\n");
- }
- }
- }
- MD.AddWordToAutoDictionary({M.W, M.Pos});
- }
for (auto &W : InterestingWords)
MD.AddWordToAutoDictionary({W});
}
- void AddMutation(uint32_t Pos, uint32_t Size, const uint8_t *Data) {
- if (NumMutations >= kMaxMutations) return;
- auto &M = Mutations[NumMutations++];
- M.Pos = Pos;
- M.W.Set(Data, Size);
- }
-
- void AddMutation(uint32_t Pos, uint32_t Size, uint64_t Data) {
- assert(Size <= sizeof(Data));
- AddMutation(Pos, Size, reinterpret_cast<uint8_t*>(&Data));
- }
-
void AddInterestingWord(const uint8_t *Data, size_t Size) {
if (!RecordingMemmem || !F->InFuzzingThread()) return;
if (Size <= 1) return;
@@ -110,75 +57,14 @@ public:
}
private:
- bool IsTwoByteData(uint64_t Data) {
- int64_t Signed = static_cast<int64_t>(Data);
- Signed >>= 16;
- return Signed == 0 || Signed == -1L;
- }
-
- // We don't want to create too many trace-based mutations as it is both
- // expensive and useless. So after some number of mutations is collected,
- // start rejecting some of them. The more there are mutations the more we
- // reject.
- bool WantToHandleOneMoreMutation() {
- const size_t FirstN = 64;
- // Gladly handle first N mutations.
- if (NumMutations <= FirstN) return true;
- size_t Diff = NumMutations - FirstN;
- size_t DiffLog = sizeof(long) * 8 - __builtin_clzl((long)Diff);
- assert(DiffLog > 0 && DiffLog < 64);
- bool WantThisOne = MD.GetRand()(1 << DiffLog) == 0; // 1 out of DiffLog.
- return WantThisOne;
- }
- static const size_t kMaxMutations = 1 << 16;
- size_t NumMutations;
- TraceBasedMutation Mutations[kMaxMutations];
// TODO: std::set is too inefficient, need to have a custom DS here.
std::set<Word> InterestingWords;
MutationDispatcher &MD;
const FuzzingOptions Options;
const Fuzzer *F;
- std::map<Word, size_t> AutoDictUnitCounts;
- size_t AutoDictAdds = 0;
};
-int TraceState::TryToAddDesiredData(const uint8_t *PresentData,
- const uint8_t *DesiredData,
- size_t DataSize) {
- if (NumMutations >= kMaxMutations || !WantToHandleOneMoreMutation()) return 0;
- ScopedDoingMyOwnMemmem scoped_doing_my_own_memmem;
- const uint8_t *UnitData;
- auto UnitSize = F->GetCurrentUnitInFuzzingThead(&UnitData);
- int Res = 0;
- const uint8_t *Beg = UnitData;
- const uint8_t *End = Beg + UnitSize;
- for (const uint8_t *Cur = Beg; Cur < End; Cur++) {
- Cur = (uint8_t *)SearchMemory(Cur, End - Cur, PresentData, DataSize);
- if (!Cur)
- break;
- size_t Pos = Cur - Beg;
- assert(Pos < UnitSize);
- AddMutation(Pos, DataSize, DesiredData);
- Res++;
- }
- return Res;
-}
-
-void TraceState::TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
- const uint8_t *Data2) {
- if (!RecordingMemcmp || !F->InFuzzingThread()) return;
- CmpSize = std::min(CmpSize, Word::GetMaxSize());
- int Added2 = TryToAddDesiredData(Data1, Data2, CmpSize);
- int Added1 = TryToAddDesiredData(Data2, Data1, CmpSize);
- if ((Added1 || Added2) && Options.Verbosity >= 3) {
- Printf("MemCmp Added %d%d: ", Added1, Added2);
- if (Added1) PrintASCII(Data1, CmpSize);
- if (Added2) PrintASCII(Data2, CmpSize);
- Printf("\n");
- }
-}
-
static TraceState *TS;
void Fuzzer::StartTraceRecording() {
@@ -192,7 +78,7 @@ void Fuzzer::StopTraceRecording() {
}
void Fuzzer::InitializeTraceState() {
- if (!Options.UseMemcmp) return;
+ if (!Options.UseMemmem) return;
TS = new TraceState(MD, Options, this);
}
@@ -202,10 +88,17 @@ static size_t InternalStrnlen(const char *S, size_t MaxLen) {
return Len;
}
+// Finds min of (strlen(S1), strlen(S2)).
+// Needed bacause one of these strings may actually be non-zero terminated.
+static size_t InternalStrnlen2(const char *S1, const char *S2) {
+ size_t Len = 0;
+ for (; S1[Len] && S2[Len]; Len++) {}
+ return Len;
+}
+
} // namespace fuzzer
using fuzzer::TS;
-using fuzzer::RecordingMemcmp;
extern "C" {
@@ -215,62 +108,72 @@ extern "C" {
#endif
#if LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
const void *s2, size_t n, int result) {
- fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n);
- if (!RecordingMemcmp) return;
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
if (result == 0) return; // No reason to mutate.
if (n <= 1) return; // Not interesting.
- TS->TraceMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
- reinterpret_cast<const uint8_t *>(s2));
+ fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/false);
}
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
const char *s2, size_t n, int result) {
- fuzzer::TPC.AddValueForStrcmp(caller_pc, s1, s2, n);
- if (!RecordingMemcmp) return;
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
if (result == 0) return; // No reason to mutate.
size_t Len1 = fuzzer::InternalStrnlen(s1, n);
size_t Len2 = fuzzer::InternalStrnlen(s2, n);
n = std::min(n, Len1);
n = std::min(n, Len2);
if (n <= 1) return; // Not interesting.
- TS->TraceMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
- reinterpret_cast<const uint8_t *>(s2));
+ fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/true);
}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
const char *s2, int result) {
- fuzzer::TPC.AddValueForStrcmp(caller_pc, s1, s2, 64);
- if (!RecordingMemcmp) return;
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
if (result == 0) return; // No reason to mutate.
- size_t Len1 = strlen(s1);
- size_t Len2 = strlen(s2);
- size_t N = std::min(Len1, Len2);
+ size_t N = fuzzer::InternalStrnlen2(s1, s2);
if (N <= 1) return; // Not interesting.
- TS->TraceMemcmpCallback(N, reinterpret_cast<const uint8_t *>(s1),
- reinterpret_cast<const uint8_t *>(s2));
+ fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, N, /*StopAtZero*/true);
}
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
const char *s2, size_t n, int result) {
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result);
}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
const char *s2, int result) {
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result);
}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,
const char *s2, char *result) {
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
TS->AddInterestingWord(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,
const char *s2, char *result) {
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
TS->AddInterestingWord(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,
const void *s2, size_t len2, void *result) {
- if (fuzzer::DoingMyOwnMemmem) return;
+ if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return;
TS->AddInterestingWord(reinterpret_cast<const uint8_t *>(s2), len2);
}