From 56992074d35059afd55dada77907e9b6fa469c58 Mon Sep 17 00:00:00 2001 From: Mike Aizatsky Date: Tue, 17 Jan 2017 23:11:32 +0000 Subject: [PATCH] [libfuzzer] fixing collected pc addresses for coverage Summary: The causes google/ossfuzz#84 Reviewers: kcc Subscribers: mgorny Differential Revision: https://reviews.llvm.org/D28827 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@292289 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Fuzzer/FuzzerDefs.h | 4 ++- lib/Fuzzer/FuzzerTracePC.cpp | 43 ++++++++++++++++++------------ lib/Fuzzer/FuzzerTracePC.h | 2 +- lib/Fuzzer/test/CMakeLists.txt | 3 +-- lib/Fuzzer/test/dump_coverage.test | 2 ++ 5 files changed, 33 insertions(+), 21 deletions(-) diff --git a/lib/Fuzzer/FuzzerDefs.h b/lib/Fuzzer/FuzzerDefs.h index 0f5b8a7cf21..ef990e1937f 100644 --- a/lib/Fuzzer/FuzzerDefs.h +++ b/lib/Fuzzer/FuzzerDefs.h @@ -47,9 +47,11 @@ #ifdef __clang__ // avoid gcc warning. # define ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory"))) +# define ALWAYS_INLINE __attribute__((always_inline)) #else # define ATTRIBUTE_NO_SANITIZE_MEMORY -#endif +# define ALWAYS_INLINE +#endif // __clang__ namespace fuzzer { diff --git a/lib/Fuzzer/FuzzerTracePC.cpp b/lib/Fuzzer/FuzzerTracePC.cpp index e9101fbb786..6b31808c843 100644 --- a/lib/Fuzzer/FuzzerTracePC.cpp +++ b/lib/Fuzzer/FuzzerTracePC.cpp @@ -236,15 +236,11 @@ void TracePC::AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2, } template -ATTRIBUTE_TARGET_POPCNT -#ifdef __clang__ // g++ can't handle this __attribute__ here :( -__attribute__((always_inline)) -#endif // __clang__ -void TracePC::HandleCmp(void *PC, T Arg1, T Arg2) { - uintptr_t PCuint = reinterpret_cast(PC); +ATTRIBUTE_TARGET_POPCNT ALWAYS_INLINE +void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) { uint64_t ArgXor = Arg1 ^ Arg2; uint64_t ArgDistance = __builtin_popcountl(ArgXor) + 1; // [1,65] - uintptr_t Idx = ((PCuint & 4095) + 1) * ArgDistance; + uintptr_t Idx = ((PC & 4095) + 1) * ArgDistance; if (sizeof(T) == 4) TORC4.Insert(ArgXor, Arg1, Arg2); else if (sizeof(T) == 8) @@ -252,12 +248,18 @@ void TracePC::HandleCmp(void *PC, T Arg1, T Arg2) { HandleValueProfile(Idx); } +inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(void* pc) { + // TODO: this implementation is x86 only. + // see sanitizer_common GetPreviousInstructionPc for full implementation. + return reinterpret_cast(pc) - 1; +} + } // namespace fuzzer extern "C" { __attribute__((visibility("default"))) void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) { - uintptr_t PC = (uintptr_t)__builtin_return_address(0); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); fuzzer::TPC.HandleTrace(Guard, PC); } @@ -268,25 +270,29 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) { __attribute__((visibility("default"))) void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) { - uintptr_t PC = (uintptr_t)__builtin_return_address(0); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); fuzzer::TPC.HandleCallerCallee(PC, Callee); } __attribute__((visibility("default"))) void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) { - fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } __attribute__((visibility("default"))) void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) { - fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } __attribute__((visibility("default"))) void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) { - fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } __attribute__((visibility("default"))) void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) { - fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } __attribute__((visibility("default"))) @@ -297,7 +303,7 @@ void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) { // Skip the most common and the most boring case. if (Vals[N - 1] < 256 && Val < 256) return; - char *PC = (char*)__builtin_return_address(0); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); size_t i; uint64_t Token = 0; for (i = 0; i < N; i++) { @@ -316,15 +322,18 @@ void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) { __attribute__((visibility("default"))) void __sanitizer_cov_trace_div4(uint32_t Val) { - fuzzer::TPC.HandleCmp(__builtin_return_address(0), Val, (uint32_t)0); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Val, (uint32_t)0); } __attribute__((visibility("default"))) void __sanitizer_cov_trace_div8(uint64_t Val) { - fuzzer::TPC.HandleCmp(__builtin_return_address(0), Val, (uint64_t)0); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Val, (uint64_t)0); } __attribute__((visibility("default"))) void __sanitizer_cov_trace_gep(uintptr_t Idx) { - fuzzer::TPC.HandleCmp(__builtin_return_address(0), Idx, (uintptr_t)0); + uintptr_t PC = fuzzer::GetPreviousInstructionPc(__builtin_return_address(0)); + fuzzer::TPC.HandleCmp(PC, Idx, (uintptr_t)0); } } // extern "C" diff --git a/lib/Fuzzer/FuzzerTracePC.h b/lib/Fuzzer/FuzzerTracePC.h index 3f9dced2558..d26e459b303 100644 --- a/lib/Fuzzer/FuzzerTracePC.h +++ b/lib/Fuzzer/FuzzerTracePC.h @@ -52,7 +52,7 @@ class TracePC { void HandleInit(uint32_t *start, uint32_t *stop); void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee); void HandleValueProfile(size_t Value) { ValueProfileMap.AddValue(Value); } - template void HandleCmp(void *PC, T Arg1, T Arg2); + template void HandleCmp(uintptr_t PC, T Arg1, T Arg2); size_t GetTotalPCCoverage(); void SetUseCounters(bool UC) { UseCounters = UC; } void SetUseValueProfile(bool VP) { UseValueProfile = VP; } diff --git a/lib/Fuzzer/test/CMakeLists.txt b/lib/Fuzzer/test/CMakeLists.txt index c0457746a0e..a95b5e7fc55 100644 --- a/lib/Fuzzer/test/CMakeLists.txt +++ b/lib/Fuzzer/test/CMakeLists.txt @@ -126,7 +126,6 @@ foreach(Test ${Tests}) add_libfuzzer_test(${Test} SOURCES ${Test}.cpp) endforeach() - ############################################################################### # Unit tests ############################################################################### @@ -213,5 +212,5 @@ configure_lit_site_cfg( add_lit_testsuite(check-fuzzer "Running Fuzzer tests" ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${TestBinaries} FileCheck not + DEPENDS ${TestBinaries} FileCheck sancov not ) diff --git a/lib/Fuzzer/test/dump_coverage.test b/lib/Fuzzer/test/dump_coverage.test index 9bd98daa361..a168b5b0eb0 100644 --- a/lib/Fuzzer/test/dump_coverage.test +++ b/lib/Fuzzer/test/dump_coverage.test @@ -2,12 +2,14 @@ RUN: DIR=%t_workdir RUN: BUILD_DIR=$(pwd) RUN: rm -rf $DIR && mkdir -p $DIR && cd $DIR RUN: not $BUILD_DIR/LLVMFuzzer-NullDerefTest -dump_coverage=1 2>&1 | FileCheck %s +RUN: sancov -covered-functions *.sancov $BUILD_DIR/LLVMFuzzer-NullDerefTest | FileCheck %s --check-prefix=SANCOV RUN: $BUILD_DIR/LLVMFuzzer-DSOTest -dump_coverage=1 -runs=0 2>&1 | FileCheck %s --check-prefix=DSO RUN: not $BUILD_DIR/LLVMFuzzer-NullDerefTest -dump_coverage=0 2>&1 | FileCheck %s --check-prefix=NOCOV RUN: rm -rf $DIR CHECK: SanitizerCoverage: ./LLVMFuzzer-NullDerefTest.{{.*}}.sancov {{.*}} PCs written +SANCOV: LLVMFuzzerTestOneInput DSO: SanitizerCoverage: ./LLVMFuzzer-DSOTest.{{.*}}.sancov {{.*}} PCs written DSO-DAG: SanitizerCoverage: ./libLLVMFuzzer-DSO1.{{.*}}.sancov {{.*}} PCs written