From a5277d59d086ed8950847af5363ea1759d395557 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 15 Sep 2016 01:30:18 +0000 Subject: [PATCH] [libFuzzer] add 8-bit counters to trace-pc-guard handler llvm-svn: 281568 --- llvm/lib/Fuzzer/FuzzerInternal.h | 15 ++++++-- llvm/lib/Fuzzer/FuzzerLoop.cpp | 7 +++- llvm/lib/Fuzzer/FuzzerTracePC.cpp | 53 +++++++++++++++++++++++----- llvm/lib/Fuzzer/test/fuzzer.test | 8 ++++- llvm/lib/Fuzzer/test/trace-pc/CMakeLists.txt | 1 + 5 files changed, 71 insertions(+), 13 deletions(-) diff --git a/llvm/lib/Fuzzer/FuzzerInternal.h b/llvm/lib/Fuzzer/FuzzerInternal.h index 47001ba..eed3a65 100644 --- a/llvm/lib/Fuzzer/FuzzerInternal.h +++ b/llvm/lib/Fuzzer/FuzzerInternal.h @@ -360,9 +360,18 @@ class TracePC { public: void HandleTrace(uint8_t *guard, uintptr_t PC); void HandleInit(uint8_t *start, uint8_t *stop); - size_t GetTotalCoverage(); - private: + size_t GetTotalCoverage() { return TotalCoverage; } + void SetUseCounters(bool UC) { UseCounters = UC; } + size_t UpdateCounterMap(ValueBitMap *Map); + void FinalizeTrace(); + +private: + bool UseCounters = false; size_t TotalCoverage = 0; + size_t TotalCounterBits = 0; + + uint8_t *Start, *Stop; + ValueBitMap CounterMap; }; extern TracePC TPC; @@ -380,6 +389,7 @@ public: CounterBitmapBits = 0; CounterBitmap.clear(); VPMap.Reset(); + TPCMap.Reset(); VPMapBits = 0; } @@ -390,6 +400,7 @@ public: // Precalculated number of bits in CounterBitmap. size_t CounterBitmapBits; std::vector CounterBitmap; + ValueBitMap TPCMap; ValueBitMap VPMap; size_t VPMapBits; }; diff --git a/llvm/lib/Fuzzer/FuzzerLoop.cpp b/llvm/lib/Fuzzer/FuzzerLoop.cpp index f5852cb..54e748f 100644 --- a/llvm/lib/Fuzzer/FuzzerLoop.cpp +++ b/llvm/lib/Fuzzer/FuzzerLoop.cpp @@ -77,6 +77,8 @@ void Fuzzer::PrepareCounters(Fuzzer::Coverage *C) { bool Fuzzer::RecordMaxCoverage(Fuzzer::Coverage *C) { bool Res = false; + TPC.FinalizeTrace(); + uint64_t NewBlockCoverage = EF->__sanitizer_get_total_unique_coverage() + TPC.GetTotalCoverage(); if (NewBlockCoverage > C->BlockCoverage) { @@ -97,11 +99,13 @@ bool Fuzzer::RecordMaxCoverage(Fuzzer::Coverage *C) { if (Options.UseCounters) { uint64_t CounterDelta = EF->__sanitizer_update_counter_bitset_and_clear_counters( - C->CounterBitmap.data()); + C->CounterBitmap.data()) + + TPC.UpdateCounterMap(&C->TPCMap); if (CounterDelta > 0) { Res = true; C->CounterBitmapBits += CounterDelta; } + } size_t NewVPMapBits = VPMapMergeFromCurrent(C->VPMap); @@ -158,6 +162,7 @@ Fuzzer::Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options) IsMyThread = true; if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks) EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook); + TPC.SetUseCounters(Options.UseCounters); if (Options.PrintNewCovPcs) { PcBufferLen = 1 << 24; diff --git a/llvm/lib/Fuzzer/FuzzerTracePC.cpp b/llvm/lib/Fuzzer/FuzzerTracePC.cpp index 1ce1200..2822725 100644 --- a/llvm/lib/Fuzzer/FuzzerTracePC.cpp +++ b/llvm/lib/Fuzzer/FuzzerTracePC.cpp @@ -18,25 +18,60 @@ namespace fuzzer { TracePC TPC; -void TracePC::HandleTrace(uint8_t *guard, uintptr_t PC) { - *guard = 0xff; - TotalCoverage++; +void TracePC::HandleTrace(uint8_t *Guard, uintptr_t PC) { + if (UseCounters) { + uintptr_t GV = *Guard; + if (GV == 0) + TotalCoverage++; + if (GV < 255) + GV++; + *Guard = GV; + } else { + *Guard = 0xff; + TotalCoverage++; + } } -void TracePC::HandleInit(uint8_t *start, uint8_t *stop) { - Printf("INFO: guards: [%p,%p)\n", start, stop); + +void TracePC::HandleInit(uint8_t *Start, uint8_t *Stop) { + // TODO: this handles only one DSO/binary. + this->Start = Start; + this->Stop = Stop; +} + +void TracePC::FinalizeTrace() { + if (UseCounters && TotalCoverage) { + 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); + CounterMap.AddValue(Idx * 8 + Bit); + } + *X = 1; + } + } +} + +size_t TracePC::UpdateCounterMap(ValueBitMap *Map) { + if (!TotalCoverage) return 0; + size_t NewTotalCounterBits = Map->MergeFrom(CounterMap); + size_t Delta = NewTotalCounterBits - TotalCounterBits; + TotalCounterBits = NewTotalCounterBits; + return Delta; } -size_t TracePC::GetTotalCoverage() { return TotalCoverage; } } // namespace fuzzer extern "C" { __attribute__((visibility("default"))) -void __sanitizer_cov_trace_pc_guard(uint8_t *guard) { +void __sanitizer_cov_trace_pc_guard(uint8_t *Guard) { uintptr_t PC = (uintptr_t)__builtin_return_address(0); - fuzzer::TPC.HandleTrace(guard, PC); + fuzzer::TPC.HandleTrace(Guard, PC); } __attribute__((visibility("default"))) -void __sanitizer_cov_trace_pc_guard_init(uint8_t *start, uint8_t *stop) { +void __sanitizer_cov_trace_pc_guard_init(uint8_t *Start, uint8_t *Stop) { + fuzzer::TPC.HandleInit(Start, Stop); } } diff --git a/llvm/lib/Fuzzer/test/fuzzer.test b/llvm/lib/Fuzzer/test/fuzzer.test index bd82f42..432d7e0 100644 --- a/llvm/lib/Fuzzer/test/fuzzer.test +++ b/llvm/lib/Fuzzer/test/fuzzer.test @@ -24,7 +24,13 @@ NULL_DEREF_ON_EMPTY: stat::number_of_executed_units: #not LLVMFuzzer-FullCoverageSetTest -timeout=15 -seed=1 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s -RUN: not LLVMFuzzer-CounterTest -use_counters=1 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s +RUN: not LLVMFuzzer-CounterTest -use_counters=1 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s --check-prefix=COUNTERS +RUN: not LLVMFuzzer-CounterTest-TracePC -use_counters=1 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s --check-prefix=COUNTERS + +COUNTERS: INITED {{.*}} bits: +COUNTERS: NEW {{.*}} bits: {{[1-9]*}} +COUNTERS: NEW {{.*}} bits: {{[1-9]*}} +COUNTERS: BINGO RUN: not LLVMFuzzer-CallerCalleeTest -cross_over=0 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s # This one is flaky, may actually find the goal even w/o use_indir_calls. diff --git a/llvm/lib/Fuzzer/test/trace-pc/CMakeLists.txt b/llvm/lib/Fuzzer/test/trace-pc/CMakeLists.txt index 1b8812e..a25dbc6 100644 --- a/llvm/lib/Fuzzer/test/trace-pc/CMakeLists.txt +++ b/llvm/lib/Fuzzer/test/trace-pc/CMakeLists.txt @@ -5,6 +5,7 @@ set(CMAKE_CXX_FLAGS set(TracePCTests SimpleTest + CounterTest ) foreach(Test ${TracePCTests}) -- 2.7.4