diff --git a/llvm/lib/Fuzzer/FuzzerInternal.h b/llvm/lib/Fuzzer/FuzzerInternal.h index d9331c662de6..e6bef799f13f 100644 --- a/llvm/lib/Fuzzer/FuzzerInternal.h +++ b/llvm/lib/Fuzzer/FuzzerInternal.h @@ -402,6 +402,13 @@ public: // Public for tests. void ResetCoverage(); + bool InFuzzingThread() const { return IsMyThread; } + size_t GetCurrentUnitInFuzzingThead(const uint8_t **Data) const { + assert(InFuzzingThread()); + *Data = CurrentUnitData; + return CurrentUnitSize; + } + private: void AlarmCallback(); void CrashCallback(); @@ -463,6 +470,9 @@ private: // Maximum recorded coverage. Coverage MaxCoverage; + + // Need to know our own thread. + static thread_local bool IsMyThread; }; }; // namespace fuzzer diff --git a/llvm/lib/Fuzzer/FuzzerLoop.cpp b/llvm/lib/Fuzzer/FuzzerLoop.cpp index d924e5d8fb00..e38a29ab1fca 100644 --- a/llvm/lib/Fuzzer/FuzzerLoop.cpp +++ b/llvm/lib/Fuzzer/FuzzerLoop.cpp @@ -61,6 +61,8 @@ namespace fuzzer { static const size_t kMaxUnitSizeToPrint = 256; static const size_t TruncateMaxRuns = 1000; +thread_local bool Fuzzer::IsMyThread; + static void MissingWeakApiFunction(const char *FnName) { Printf("ERROR: %s is not defined. Exiting.\n" "Did you use -fsanitize-coverage=... to build your code?\n", @@ -154,6 +156,7 @@ Fuzzer::Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options) assert(!F); F = this; ResetCoverage(); + IsMyThread = true; } void Fuzzer::SetDeathCallback() { diff --git a/llvm/lib/Fuzzer/FuzzerTraceState.cpp b/llvm/lib/Fuzzer/FuzzerTraceState.cpp index d994481ff384..9426fb9d1ca2 100644 --- a/llvm/lib/Fuzzer/FuzzerTraceState.cpp +++ b/llvm/lib/Fuzzer/FuzzerTraceState.cpp @@ -174,15 +174,9 @@ static bool RecordingMemcmp = false; class TraceState { public: - TraceState(MutationDispatcher &MD, const Fuzzer::FuzzingOptions &Options, - const uint8_t **CurrentUnitData, size_t *CurrentUnitSize) - : MD(MD), Options(Options), CurrentUnitData(CurrentUnitData), - CurrentUnitSize(CurrentUnitSize) { - // Current trace collection is not thread-friendly and it probably - // does not have to be such, but at least we should not crash in presence - // of threads. So, just ignore all traces coming from all threads but one. - IsMyThread = true; - } + TraceState(MutationDispatcher &MD, const Fuzzer::FuzzingOptions &Options, + const Fuzzer::Fuzzer *F) + : MD(MD), Options(Options), F(F) {} LabelRange GetLabelRange(dfsan_label L); void DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, @@ -201,12 +195,13 @@ class TraceState { void TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits, uint64_t Val, size_t NumCases, uint64_t *Cases); int TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData, - size_t DataSize); + size_t DataSize); int TryToAddDesiredData(const uint8_t *PresentData, const uint8_t *DesiredData, size_t DataSize); void StartTraceRecording() { - if (!Options.UseTraces && !Options.UseMemcmp) return; + if (!Options.UseTraces && !Options.UseMemcmp) + return; RecordingTraces = Options.UseTraces; RecordingMemcmp = Options.UseMemcmp; NumMutations = 0; @@ -293,14 +288,11 @@ class TraceState { size_t LastDfsanLabel = 0; MutationDispatcher &MD; const Fuzzer::FuzzingOptions &Options; - const uint8_t **CurrentUnitData; - size_t *CurrentUnitSize; + const Fuzzer *F; std::map AutoDictUnitCounts; size_t AutoDictAdds = 0; - static thread_local bool IsMyThread; }; -thread_local bool TraceState::IsMyThread; LabelRange TraceState::GetLabelRange(dfsan_label L) { LabelRange &LR = LabelRanges[L]; @@ -316,7 +308,7 @@ void TraceState::DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, uint64_t Arg1, uint64_t Arg2, dfsan_label L1, dfsan_label L2) { assert(ReallyHaveDFSan()); - if (!RecordingTraces || !IsMyThread) return; + if (!RecordingTraces || !F->InFuzzingThread()) return; if (L1 == 0 && L2 == 0) return; // Not actionable. if (L1 != 0 && L2 != 0) @@ -346,7 +338,7 @@ void TraceState::DFSanMemcmpCallback(size_t CmpSize, const uint8_t *Data1, dfsan_label L2) { assert(ReallyHaveDFSan()); - if (!RecordingMemcmp || !IsMyThread) return; + if (!RecordingMemcmp || !F->InFuzzingThread()) return; if (L1 == 0 && L2 == 0) return; // Not actionable. if (L1 != 0 && L2 != 0) @@ -365,7 +357,7 @@ void TraceState::DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits, uint64_t Val, size_t NumCases, uint64_t *Cases, dfsan_label L) { assert(ReallyHaveDFSan()); - if (!RecordingTraces || !IsMyThread) return; + if (!RecordingTraces || !F->InFuzzingThread()) return; if (!L) return; // Not actionable. LabelRange LR = GetLabelRange(L); size_t ValSize = ValSizeInBits / 8; @@ -391,15 +383,17 @@ void TraceState::DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits, int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData, size_t DataSize) { if (NumMutations >= kMaxMutations || !WantToHandleOneMoreMutation()) return 0; + const uint8_t *UnitData; + auto UnitSize = F->GetCurrentUnitInFuzzingThead(&UnitData); int Res = 0; - const uint8_t *Beg = *CurrentUnitData; - const uint8_t *End = Beg + *CurrentUnitSize; + const uint8_t *Beg = UnitData; + const uint8_t *End = Beg + UnitSize; for (const uint8_t *Cur = Beg; Cur < End; Cur++) { Cur = (uint8_t *)memmem(Cur, End - Cur, &PresentData, DataSize); if (!Cur) break; size_t Pos = Cur - Beg; - assert(Pos < *CurrentUnitSize); + assert(Pos < UnitSize); AddMutation(Pos, DataSize, DesiredData); AddMutation(Pos, DataSize, DesiredData + 1); AddMutation(Pos, DataSize, DesiredData - 1); @@ -412,15 +406,17 @@ int TraceState::TryToAddDesiredData(const uint8_t *PresentData, const uint8_t *DesiredData, size_t DataSize) { if (NumMutations >= kMaxMutations || !WantToHandleOneMoreMutation()) return 0; + const uint8_t *UnitData; + auto UnitSize = F->GetCurrentUnitInFuzzingThead(&UnitData); int Res = 0; - const uint8_t *Beg = *CurrentUnitData; - const uint8_t *End = Beg + *CurrentUnitSize; + const uint8_t *Beg = UnitData; + const uint8_t *End = Beg + UnitSize; for (const uint8_t *Cur = Beg; Cur < End; Cur++) { Cur = (uint8_t *)memmem(Cur, End - Cur, PresentData, DataSize); if (!Cur) break; size_t Pos = Cur - Beg; - assert(Pos < *CurrentUnitSize); + assert(Pos < UnitSize); AddMutation(Pos, DataSize, DesiredData); Res++; } @@ -429,7 +425,7 @@ int TraceState::TryToAddDesiredData(const uint8_t *PresentData, void TraceState::TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, uint64_t Arg1, uint64_t Arg2) { - if (!RecordingTraces || !IsMyThread) return; + if (!RecordingTraces || !F->InFuzzingThread()) return; if ((CmpType == ICMP_EQ || CmpType == ICMP_NE) && Arg1 == Arg2) return; // No reason to mutate. int Added = 0; @@ -445,7 +441,7 @@ void TraceState::TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, void TraceState::TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1, const uint8_t *Data2) { - if (!RecordingMemcmp || !IsMyThread) return; + if (!RecordingMemcmp || !F->InFuzzingThread()) return; CmpSize = std::min(CmpSize, Word::GetMaxSize()); int Added2 = TryToAddDesiredData(Data1, Data2, CmpSize); int Added1 = TryToAddDesiredData(Data2, Data1, CmpSize); @@ -460,7 +456,7 @@ void TraceState::TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1, void TraceState::TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits, uint64_t Val, size_t NumCases, uint64_t *Cases) { - if (!RecordingTraces || !IsMyThread) return; + if (!RecordingTraces || !F->InFuzzingThread()) return; size_t ValSize = ValSizeInBits / 8; bool TryShort = IsTwoByteData(Val); for (size_t i = 0; i < NumCases; i++) @@ -499,7 +495,7 @@ void Fuzzer::AssignTaintLabels(uint8_t *Data, size_t Size) { void Fuzzer::InitializeTraceState() { if (!Options.UseTraces && !Options.UseMemcmp) return; - TS = new TraceState(MD, Options, &CurrentUnitData, &CurrentUnitSize); + TS = new TraceState(MD, Options, this); } static size_t InternalStrnlen(const char *S, size_t MaxLen) {