diff --git a/lib/Fuzzer/FuzzerInternal.h b/lib/Fuzzer/FuzzerInternal.h index eed3a659eb5..9f0641ff46c 100644 --- a/lib/Fuzzer/FuzzerInternal.h +++ b/lib/Fuzzer/FuzzerInternal.h @@ -365,13 +365,27 @@ class TracePC { size_t UpdateCounterMap(ValueBitMap *Map); void FinalizeTrace(); + size_t GetNewPCsAndFlush(uintptr_t **NewPCsPtr = nullptr) { + if (NewPCsPtr) + *NewPCsPtr = NewPCs; + size_t Res = NumNewPCs; + NumNewPCs = 0; + return Res; + } + private: bool UseCounters = false; size_t TotalCoverage = 0; size_t TotalCounterBits = 0; + static const size_t kMaxNewPCs = 64; + uintptr_t NewPCs[kMaxNewPCs]; + size_t NumNewPCs = 0; + void AddNewPC(uintptr_t PC) { NewPCs[(NumNewPCs++) % kMaxNewPCs] = PC; } + uint8_t *Start, *Stop; ValueBitMap CounterMap; + ValueBitMap TotalCoverageMap; }; extern TracePC TPC; @@ -469,6 +483,7 @@ private: void MutateAndTestOne(); void ReportNewCoverage(const Unit &U); void PrintNewPCs(); + void PrintOneNewPC(uintptr_t PC); bool RunOne(const Unit &U) { return RunOne(U.data(), U.size()); } void RunOneAndUpdateCorpus(const uint8_t *Data, size_t Size); void WriteToOutputCorpus(const Unit &U); diff --git a/lib/Fuzzer/FuzzerLoop.cpp b/lib/Fuzzer/FuzzerLoop.cpp index 54e748fb796..7cb1d4906a5 100644 --- a/lib/Fuzzer/FuzzerLoop.cpp +++ b/lib/Fuzzer/FuzzerLoop.cpp @@ -63,6 +63,7 @@ void Fuzzer::ResetCounters() { } if (EF->__sanitizer_get_coverage_pc_buffer_pos) PcBufferPos = EF->__sanitizer_get_coverage_pc_buffer_pos(); + TPC.GetNewPCsAndFlush(); } void Fuzzer::PrepareCounters(Fuzzer::Coverage *C) { @@ -556,22 +557,31 @@ void Fuzzer::PrintStatusForNewUnit(const Unit &U) { } } +void Fuzzer::PrintOneNewPC(uintptr_t PC) { + if (EF->__sanitizer_symbolize_pc) { + char PcDescr[1024]; + EF->__sanitizer_symbolize_pc(reinterpret_cast(PC), + "%p %F %L", PcDescr, sizeof(PcDescr)); + PcDescr[sizeof(PcDescr) - 1] = 0; // Just in case. + Printf("\tNEW_PC: %s\n", PcDescr); + } else { + Printf("\tNEW_PC: %p\n", PC); + } +} + void Fuzzer::PrintNewPCs() { - if (Options.PrintNewCovPcs && PrevPcBufferPos != PcBufferPos) { + if (!Options.PrintNewCovPcs) return; + if (PrevPcBufferPos != PcBufferPos) { int NumPrinted = 0; for (size_t I = PrevPcBufferPos; I < PcBufferPos; ++I) { if (NumPrinted++ > 30) break; // Don't print too many new PCs. - if (EF->__sanitizer_symbolize_pc) { - char PcDescr[1024]; - EF->__sanitizer_symbolize_pc(reinterpret_cast(PcBuffer[I]), - "%p %F %L", PcDescr, sizeof(PcDescr)); - PcDescr[sizeof(PcDescr) - 1] = 0; // Just in case. - Printf("\tNEW_PC: %s\n", PcDescr); - } else { - Printf("\tNEW_PC: %p\n", PcBuffer[I]); - } + PrintOneNewPC(PcBuffer[I]); } } + uintptr_t *PCs; + if (size_t NumNewPCs = TPC.GetNewPCsAndFlush(&PCs)) + for (size_t i = 0; i < NumNewPCs; i++) + PrintOneNewPC(PCs[i]); } void Fuzzer::ReportNewCoverage(const Unit &U) { diff --git a/lib/Fuzzer/FuzzerTracePC.cpp b/lib/Fuzzer/FuzzerTracePC.cpp index 2822725f555..b01769203e2 100644 --- a/lib/Fuzzer/FuzzerTracePC.cpp +++ b/lib/Fuzzer/FuzzerTracePC.cpp @@ -21,14 +21,20 @@ TracePC TPC; void TracePC::HandleTrace(uint8_t *Guard, uintptr_t PC) { if (UseCounters) { uintptr_t GV = *Guard; - if (GV == 0) - TotalCoverage++; + if (GV == 0) { + size_t Idx = Guard - Start; + if (TotalCoverageMap.AddValue(Idx)) { + TotalCoverage++; + AddNewPC(PC); + } + } if (GV < 255) GV++; *Guard = GV; } else { *Guard = 0xff; TotalCoverage++; + AddNewPC(PC); } } @@ -43,12 +49,18 @@ void TracePC::FinalizeTrace() { for (uint8_t *X = Start; X < Stop; X++) { uint8_t Value = *X; size_t Idx = X - Start; - if (Value >= 2) { - unsigned Bit = 31 - __builtin_clz(Value); - assert(Bit < 8); + if (Value >= 1) { + unsigned Bit = 0; + /**/ if (Value >= 128) Bit = 7; + else if (Value >= 32) Bit = 6; + else if (Value >= 16) Bit = 5; + else if (Value >= 8) Bit = 4; + else if (Value >= 4) Bit = 3; + else if (Value >= 3) Bit = 2; + else if (Value >= 2) Bit = 1; CounterMap.AddValue(Idx * 8 + Bit); } - *X = 1; + *X = 0; } } } diff --git a/lib/Fuzzer/FuzzerValueBitMap.h b/lib/Fuzzer/FuzzerValueBitMap.h index 2a917333e21..6f6ca116473 100644 --- a/lib/Fuzzer/FuzzerValueBitMap.h +++ b/lib/Fuzzer/FuzzerValueBitMap.h @@ -24,12 +24,16 @@ struct ValueBitMap { // Clears all bits. void Reset() { memset(Map, 0, sizeof(Map)); } - // Computed a hash function of Value and sets the corresponding bit. - inline void AddValue(uintptr_t Value) { + // Computes a hash function of Value and sets the corresponding bit. + // Returns true if the bit was changed from 0 to 1. + inline bool AddValue(uintptr_t Value) { uintptr_t Idx = Value < kMapSizeInBits ? Value : Value % kMapSizeInBits; uintptr_t WordIdx = Idx / kBitsInWord; uintptr_t BitIdx = Idx % kBitsInWord; - Map[WordIdx] |= 1UL << BitIdx; + uintptr_t Old = Map[WordIdx]; + uintptr_t New = Old | (1UL << BitIdx); + Map[WordIdx] = New; + return New != Old; } // Merges 'Other' into 'this', clears 'Other', diff --git a/lib/Fuzzer/test/fuzzer-printcovpcs.test b/lib/Fuzzer/test/fuzzer-printcovpcs.test index a1ef2b7c848..257c9f61597 100644 --- a/lib/Fuzzer/test/fuzzer-printcovpcs.test +++ b/lib/Fuzzer/test/fuzzer-printcovpcs.test @@ -1,7 +1,14 @@ -RUN: LLVMFuzzer-SimpleTest -print_pcs=1 2>&1 | FileCheck %s --check-prefix=PCS +RUN: LLVMFuzzer-SimpleTest -print_pcs=1 2>&1 | FileCheck %s --check-prefix=PCS +RUN: LLVMFuzzer-SimpleTest-TracePC -print_pcs=1 2>&1 | FileCheck %s --check-prefix=PCS PCS-NOT: NEW_PC PCS:INITED PCS:NEW_PC: {{0x[a-f0-9]+}} +PCS:NEW_PC: {{0x[a-f0-9]+}} PCS:NEW PCS:BINGO +RUN: LLVMFuzzer-CounterTest-TracePC -use_counters=0 -print_pcs=1 -runs=10000 2>&1 | FileCheck %s --check-prefix=C_PCS +RUN: LLVMFuzzer-CounterTest-TracePC -use_counters=1 -print_pcs=1 -runs=10000 2>&1 | FileCheck %s --check-prefix=C_PCS + +C_PCS: NEW_PC: {{.*}} in LLVMFuzzerTestOneInput {{.*}}CounterTest.cpp:11 +C_PCS: NEW_PC: {{.*}} in LLVMFuzzerTestOneInput {{.*}}CounterTest.cpp:12