From b9cc2c457f3e24a755d2e0220240f61f1431dc6d Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Sat, 17 Sep 2016 05:04:47 +0000 Subject: [PATCH] [libFuzzer] change trace-pc to use 8-byte guards git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@281810 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Fuzzer/FuzzerInternal.h | 23 ++++++++-- lib/Fuzzer/FuzzerLoop.cpp | 3 ++ lib/Fuzzer/FuzzerTracePC.cpp | 74 ++++++++++++++++++++------------- lib/Fuzzer/test/DSO1.cpp | 11 +++++ lib/Fuzzer/test/DSO2.cpp | 11 +++++ lib/Fuzzer/test/DSOTestExtra.cpp | 11 +++++ lib/Fuzzer/test/DSOTestMain.cpp | 27 ++++++++++++ lib/Fuzzer/test/fuzzer-jobs.test | 2 +- lib/Fuzzer/test/fuzzer.test | 4 ++ lib/Fuzzer/test/trace-pc/CMakeLists.txt | 22 ++++++++++ 10 files changed, 156 insertions(+), 32 deletions(-) create mode 100644 lib/Fuzzer/test/DSO1.cpp create mode 100644 lib/Fuzzer/test/DSO2.cpp create mode 100644 lib/Fuzzer/test/DSOTestExtra.cpp create mode 100644 lib/Fuzzer/test/DSOTestMain.cpp diff --git a/lib/Fuzzer/FuzzerInternal.h b/lib/Fuzzer/FuzzerInternal.h index 1ee1b8f718f..69b38abc26f 100644 --- a/lib/Fuzzer/FuzzerInternal.h +++ b/lib/Fuzzer/FuzzerInternal.h @@ -358,8 +358,8 @@ private: // See TracePC.cpp class TracePC { public: - void HandleTrace(uint8_t *guard, uintptr_t PC); - void HandleInit(uint8_t *start, uint8_t *stop); + void HandleTrace(uint64_t *guard, uintptr_t PC); + void HandleInit(uint64_t *start, uint64_t *stop); void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee); size_t GetTotalCoverage() { return TotalCoverage; } void SetUseCounters(bool UC) { UseCounters = UC; } @@ -374,6 +374,16 @@ class TracePC { return Res; } + void Reset() { + TotalCoverage = 0; + TotalCounterBits = 0; + NumNewPCs = 0; + CounterMap.Reset(); + TotalCoverageMap.Reset(); + } + + void PrintModuleInfo(); + private: bool UseCounters = false; size_t TotalCoverage = 0; @@ -384,7 +394,14 @@ private: size_t NumNewPCs = 0; void AddNewPC(uintptr_t PC) { NewPCs[(NumNewPCs++) % kMaxNewPCs] = PC; } - uint8_t *Start, *Stop; + struct Module { + uint64_t *Start, *Stop; + }; + + Module Modules[4096]; + size_t NumModules = 0; + size_t NumGuards = 0; + ValueBitMap CounterMap; ValueBitMap TotalCoverageMap; }; diff --git a/lib/Fuzzer/FuzzerLoop.cpp b/lib/Fuzzer/FuzzerLoop.cpp index 7cb1d4906a5..348e7573773 100644 --- a/lib/Fuzzer/FuzzerLoop.cpp +++ b/lib/Fuzzer/FuzzerLoop.cpp @@ -170,6 +170,8 @@ Fuzzer::Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options) PcBuffer = new uintptr_t[PcBufferLen]; EF->__sanitizer_set_coverage_pc_buffer(PcBuffer, PcBufferLen); } + if (Options.Verbosity) + TPC.PrintModuleInfo(); } Fuzzer::~Fuzzer() { } @@ -735,6 +737,7 @@ size_t Fuzzer::ChooseUnitIdxToMutate() { void Fuzzer::ResetCoverage() { ResetEdgeCoverage(); MaxCoverage.Reset(); + TPC.Reset(); PrepareCounters(&MaxCoverage); } diff --git a/lib/Fuzzer/FuzzerTracePC.cpp b/lib/Fuzzer/FuzzerTracePC.cpp index f729a5e6878..8fa9257c23b 100644 --- a/lib/Fuzzer/FuzzerTracePC.cpp +++ b/lib/Fuzzer/FuzzerTracePC.cpp @@ -18,49 +18,67 @@ namespace fuzzer { TracePC TPC; -void TracePC::HandleTrace(uint8_t *Guard, uintptr_t PC) { +void TracePC::HandleTrace(uint64_t *Guard, uintptr_t PC) { + const uint64_t kBit63 = 1ULL << 63; + uint64_t Value = *Guard; + if (Value & kBit63) return; + // Printf(" >> %16zx %p\n", Value, Guard); if (UseCounters) { - uintptr_t GV = *Guard; - if (GV == 0) { - size_t Idx = Guard - Start; + uint64_t Counter = Value & 0xff; + if (Counter == 0) { + size_t Idx = Value >> 32; if (TotalCoverageMap.AddValue(Idx)) { TotalCoverage++; AddNewPC(PC); } } - if (GV < 255) - GV++; - *Guard = GV; + if (Counter < 255) + Value++; } else { - *Guard = 0xff; + Value |= kBit63; TotalCoverage++; AddNewPC(PC); } + // Printf(" << %16zx\n", Value); + *Guard = Value; } -void TracePC::HandleInit(uint8_t *Start, uint8_t *Stop) { - // TODO: this handles only one DSO/binary. - this->Start = Start; - this->Stop = Stop; +void TracePC::HandleInit(uint64_t *Start, uint64_t *Stop) { + if (Start == Stop || *Start) return; + assert(NumModules < sizeof(Modules) / sizeof(Modules[0])); + for (uint64_t *P = Start; P < Stop; P++) + *P = (++NumGuards) << 32; + Modules[NumModules].Start = Start; + Modules[NumModules].Stop = Stop; + NumModules++; +} + +void TracePC::PrintModuleInfo() { + Printf("INFO: Loaded %zd modules (%zd guards): ", NumModules, NumGuards); + for (size_t i = 0; i < NumModules; i++) + Printf("[%p, %p), ", Modules[i].Start, Modules[i].Stop); + Printf("\n"); } 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 >= 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); + for (size_t M = 0; M < NumModules; M++) { + for (uint64_t *X = Modules[M].Start; X < Modules[M].Stop; X++) { + uint64_t Value = *X & 0xff; + uint64_t Idx = *X >> 32; + 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 = Idx << 32; } - *X = 0; } } } @@ -83,13 +101,13 @@ void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) { extern "C" { __attribute__((visibility("default"))) -void __sanitizer_cov_trace_pc_guard(uint8_t *Guard) { +void __sanitizer_cov_trace_pc_guard(uint64_t *Guard) { uintptr_t PC = (uintptr_t)__builtin_return_address(0); 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(uint64_t *Start, uint64_t *Stop) { fuzzer::TPC.HandleInit(Start, Stop); } diff --git a/lib/Fuzzer/test/DSO1.cpp b/lib/Fuzzer/test/DSO1.cpp new file mode 100644 index 00000000000..c362593f779 --- /dev/null +++ b/lib/Fuzzer/test/DSO1.cpp @@ -0,0 +1,11 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Source code for a simple DSO. + +int DSO1(int a) { + if (a < 123456) + return 0; + return 1; +} + diff --git a/lib/Fuzzer/test/DSO2.cpp b/lib/Fuzzer/test/DSO2.cpp new file mode 100644 index 00000000000..46c80e4b6fe --- /dev/null +++ b/lib/Fuzzer/test/DSO2.cpp @@ -0,0 +1,11 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Source code for a simple DSO. + +int DSO2(int a) { + if (a < 3598235) + return 0; + return 1; +} + diff --git a/lib/Fuzzer/test/DSOTestExtra.cpp b/lib/Fuzzer/test/DSOTestExtra.cpp new file mode 100644 index 00000000000..a2274d070eb --- /dev/null +++ b/lib/Fuzzer/test/DSOTestExtra.cpp @@ -0,0 +1,11 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Source code for a simple DSO. + +int DSOTestExtra(int a) { + if (a < 452345) + return 0; + return 1; +} + diff --git a/lib/Fuzzer/test/DSOTestMain.cpp b/lib/Fuzzer/test/DSOTestMain.cpp new file mode 100644 index 00000000000..49cd185e97d --- /dev/null +++ b/lib/Fuzzer/test/DSOTestMain.cpp @@ -0,0 +1,27 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Source code for a simple DSO. + +#include +#include +#include +#include +extern int DSO1(int a); +extern int DSO2(int a); +extern int DSOTestExtra(int a); + + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < sizeof(int) * 3) return 0; + int x, y, z; + memcpy(&x, Data + 0 * sizeof(int), sizeof(int)); + memcpy(&y, Data + 1 * sizeof(int), sizeof(int)); + memcpy(&z, Data + 2 * sizeof(int), sizeof(int)); + int sum = DSO1(x) + DSO2(y) + DSOTestExtra(z); + if (sum == 3) { + fprintf(stderr, "BINGO %d %d %d\n", x, y, z); + exit(1); + } + return 0; +} diff --git a/lib/Fuzzer/test/fuzzer-jobs.test b/lib/Fuzzer/test/fuzzer-jobs.test index cd71bc07972..5bf8cfadfb7 100644 --- a/lib/Fuzzer/test/fuzzer-jobs.test +++ b/lib/Fuzzer/test/fuzzer-jobs.test @@ -9,7 +9,7 @@ RUN: rm -f fuzz-{0,1}.log RUN: LLVMFuzzer-EmptyTest -max_total_time=4 -jobs=2 -workers=2 FuzzerJobsTestCORPUS > %t-fuzzer-jobs-test.log 2>&1 & export FUZZER_PID=$! # Wait a short while to give time for the child processes # to start fuzzing -RUN: sleep 1 +RUN: sleep 2 # If the instances are running in parallel they should have created their log # files by now. RUN: ls fuzz-0.log diff --git a/lib/Fuzzer/test/fuzzer.test b/lib/Fuzzer/test/fuzzer.test index 0e7b26ec726..ce207855e52 100644 --- a/lib/Fuzzer/test/fuzzer.test +++ b/lib/Fuzzer/test/fuzzer.test @@ -49,3 +49,7 @@ OOB: is located 0 bytes to the right of 3-byte region RUN: not LLVMFuzzer-InitializeTest 2>&1 | FileCheck %s +RUN: not LLVMFuzzer-DSOTest 2>&1 | FileCheck %s --check-prefix=DSO +DSO: INFO: Loaded 3 modules +DSO: BINGO + diff --git a/lib/Fuzzer/test/trace-pc/CMakeLists.txt b/lib/Fuzzer/test/trace-pc/CMakeLists.txt index 4ecf80163a0..c4e4e9c29d4 100644 --- a/lib/Fuzzer/test/trace-pc/CMakeLists.txt +++ b/lib/Fuzzer/test/trace-pc/CMakeLists.txt @@ -15,3 +15,25 @@ endforeach() # Propagate value into parent directory set(TestBinaries ${TestBinaries} PARENT_SCOPE) + +add_library(LLVMFuzzer-DSO1 SHARED ../DSO1.cpp) +add_library(LLVMFuzzer-DSO2 SHARED ../DSO2.cpp) + +add_executable(LLVMFuzzer-DSOTest + ../DSOTestMain.cpp + ../DSOTestExtra.cpp) + +target_link_libraries(LLVMFuzzer-DSOTest + LLVMFuzzer-DSO1 + LLVMFuzzer-DSO2 + LLVMFuzzer + ) + +set_target_properties(LLVMFuzzer-DSOTest PROPERTIES RUNTIME_OUTPUT_DIRECTORY + "${CMAKE_BINARY_DIR}/lib/Fuzzer/test") +set_target_properties(LLVMFuzzer-DSO1 PROPERTIES LIBRARY_OUTPUT_DIRECTORY + "${CMAKE_BINARY_DIR}/lib/Fuzzer/lib") +set_target_properties(LLVMFuzzer-DSO2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY + "${CMAKE_BINARY_DIR}/lib/Fuzzer/lib") + +set(TestBinaries ${TestBinaries} LLVMFuzzer-DSOTest) -- 2.11.0