From: Kostya Serebryany Date: Tue, 13 Jun 2017 22:31:21 +0000 (+0000) Subject: [libFuzzer] initial support of -fsanitize-coverage=inline-8bit-counters in libFuzzer... X-Git-Tag: submit/tizen/20170717.082441~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2881572accd5adea2a484afbddfbeb55269ec2d0;p=tools%2FlibFuzzer.git [libFuzzer] initial support of -fsanitize-coverage=inline-8bit-counters in libFuzzer. This is not fully functional yet, but simple tests work git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@305331 91177308-0d34-0410-b5e6-96231b3b80d8 Change-Id: I35ec0f5a73a20a1d9650a3384049c25f24bc4be9 --- diff --git a/lib/Fuzzer/FuzzerTracePC.cpp b/lib/Fuzzer/FuzzerTracePC.cpp index ea93468..6f5c7be 100644 --- a/lib/Fuzzer/FuzzerTracePC.cpp +++ b/lib/Fuzzer/FuzzerTracePC.cpp @@ -53,6 +53,17 @@ size_t TracePC::GetTotalPCCoverage() { return Res; } + +void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) { + if (Start == Stop) return; + if (NumModulesWithInline8bitCounters && + ModuleCounters[NumModulesWithInline8bitCounters-1].Start == Start) return; + assert(NumModulesWithInline8bitCounters < + sizeof(ModuleCounters) / sizeof(ModuleCounters[0])); + ModuleCounters[NumModulesWithInline8bitCounters++] = {Start, Stop}; + NumInline8bitCounters += Stop - Start; +} + void TracePC::HandleInit(uint32_t *Start, uint32_t *Stop) { if (Start == Stop || *Start) return; assert(NumModules < sizeof(Modules) / sizeof(Modules[0])); @@ -76,6 +87,13 @@ void TracePC::PrintModuleInfo() { for (size_t i = 0; i < NumModules; i++) Printf("[%p, %p), ", Modules[i].Start, Modules[i].Stop); Printf("\n"); + if (NumModulesWithInline8bitCounters) { + Printf("INFO: Loaded %zd modules with %zd inline 8-bit counters\n", + NumModulesWithInline8bitCounters, NumInline8bitCounters); + for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) + Printf("[%p, %p), ", ModuleCounters[i].Start, ModuleCounters[i].Stop); + Printf("\n"); + } } ATTRIBUTE_NO_SANITIZE_ALL @@ -303,6 +321,11 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) { fuzzer::TPC.HandleInit(Start, Stop); } +ATTRIBUTE_INTERFACE +void __sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop) { + fuzzer::TPC.HandleInline8bitCountersInit(Start, Stop); +} + ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) { diff --git a/lib/Fuzzer/FuzzerTracePC.h b/lib/Fuzzer/FuzzerTracePC.h index 6523fa0..5ec8c59 100644 --- a/lib/Fuzzer/FuzzerTracePC.h +++ b/lib/Fuzzer/FuzzerTracePC.h @@ -51,7 +51,8 @@ class TracePC { // How many bits of PC are used from __sanitizer_cov_trace_pc. static const size_t kTracePcBits = 18; - void HandleInit(uint32_t *start, uint32_t *stop); + void HandleInit(uint32_t *Start, uint32_t *Stop); + void HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop); void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee); template void HandleCmp(uintptr_t PC, T Arg1, T Arg2); size_t GetTotalPCCoverage(); @@ -104,6 +105,10 @@ private: size_t NumModules; // linker-initialized. size_t NumGuards; // linker-initialized. + struct { uint8_t *Start, *Stop; } ModuleCounters[4096]; + size_t NumModulesWithInline8bitCounters; // linker-initialized. + size_t NumInline8bitCounters; + uint8_t *Counters() const; uintptr_t *PCs() const; @@ -118,12 +123,24 @@ void ForEachNonZeroByte(const uint8_t *Begin, const uint8_t *End, size_t FirstFeature, Callback Handle8bitCounter) { typedef uintptr_t LargeType; const size_t Step = sizeof(LargeType) / sizeof(uint8_t); - assert(!(reinterpret_cast(Begin) % 64)); - for (auto P = Begin; P < End; P += Step) + const size_t StepMask = Step - 1; + auto P = Begin; + // Iterate by 1 byte until either the alignment boundary or the end. + for (; reinterpret_cast(P) & StepMask && P < End; P++) + if (uint8_t V = *P) + Handle8bitCounter(FirstFeature + P - Begin, V); + + // Iterate by Step bytes at a time. + for (; P < End; P += Step) if (LargeType Bundle = *reinterpret_cast(P)) for (size_t I = 0; I < Step; I++, Bundle >>= 8) if (uint8_t V = Bundle & 0xff) Handle8bitCounter(FirstFeature + P - Begin + I, V); + + // Iterate by 1 byte until the end. + for (; P < End; P++) + if (uint8_t V = *P) + Handle8bitCounter(FirstFeature + P - Begin, V); } template // bool Callback(size_t Feature) @@ -145,8 +162,16 @@ void TracePC::CollectFeatures(Callback HandleFeature) const { HandleFeature(Idx * 8 + Bit); }; - ForEachNonZeroByte(Counters, Counters + N, 0, Handle8bitCounter); - ForEachNonZeroByte(ExtraCountersBegin(), ExtraCountersEnd(), N * 8, + size_t FirstFeature = 0; + ForEachNonZeroByte(Counters, Counters + N, FirstFeature, Handle8bitCounter); + FirstFeature += N * 8; + for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { + ForEachNonZeroByte(ModuleCounters[i].Start, ModuleCounters[i].Stop, + FirstFeature, Handle8bitCounter); + FirstFeature += 8 * (ModuleCounters[i].Stop - ModuleCounters[i].Start); + } + + ForEachNonZeroByte(ExtraCountersBegin(), ExtraCountersEnd(), FirstFeature, Handle8bitCounter); if (UseValueProfile) diff --git a/lib/Fuzzer/test/CMakeLists.txt b/lib/Fuzzer/test/CMakeLists.txt index b39938a..da3f498 100644 --- a/lib/Fuzzer/test/CMakeLists.txt +++ b/lib/Fuzzer/test/CMakeLists.txt @@ -205,6 +205,7 @@ include_directories(..) # add_subdirectory(uninstrumented) add_subdirectory(no-coverage) add_subdirectory(trace-pc) +add_subdirectory(inline-8bit-counters) add_subdirectory(ubsan) add_library(LLVMFuzzer-DSO1 SHARED DSO1.cpp) diff --git a/lib/Fuzzer/test/FuzzerUnittest.cpp b/lib/Fuzzer/test/FuzzerUnittest.cpp index c8beb43..812894f 100644 --- a/lib/Fuzzer/test/FuzzerUnittest.cpp +++ b/lib/Fuzzer/test/FuzzerUnittest.cpp @@ -772,4 +772,16 @@ TEST(Fuzzer, ForEachNonZeroByte) { Expected = {{108, 1}, {109, 2}, {118, 3}, {120, 4}, {135, 5}, {137, 6}, {146, 7}, {163, 8}}; EXPECT_EQ(Res, Expected); + + Res.clear(); + ForEachNonZeroByte(Ar + 9, Ar + N, 109, CB); + Expected = { {109, 2}, {118, 3}, {120, 4}, + {135, 5}, {137, 6}, {146, 7}, {163, 8}}; + EXPECT_EQ(Res, Expected); + + Res.clear(); + ForEachNonZeroByte(Ar + 9, Ar + N - 9, 109, CB); + Expected = { {109, 2}, {118, 3}, {120, 4}, + {135, 5}, {137, 6}, {146, 7}}; + EXPECT_EQ(Res, Expected); } diff --git a/lib/Fuzzer/test/TableLookupTest.cpp b/lib/Fuzzer/test/TableLookupTest.cpp index 8126eea..4d8ab06 100644 --- a/lib/Fuzzer/test/TableLookupTest.cpp +++ b/lib/Fuzzer/test/TableLookupTest.cpp @@ -15,7 +15,6 @@ const size_t N = 1 << 12; // Define an array of counters that will be understood by libFuzzer // as extra coverage signal. The array must be: // * uint8_t -// * aligned by 64 // * in the section named __libfuzzer_extra_counters. // The target code may declare more than one such array. // @@ -23,7 +22,7 @@ const size_t N = 1 << 12; // depending on whether multiple occurrences of the event 'Idx' // is important to distinguish from one occurrence. #ifdef __linux__ -alignas(64) __attribute__((section("__libfuzzer_extra_counters"))) +__attribute__((section("__libfuzzer_extra_counters"))) #endif static uint8_t Counters[N]; diff --git a/lib/Fuzzer/test/inline-8bit-counters.test b/lib/Fuzzer/test/inline-8bit-counters.test new file mode 100644 index 0000000..f34e1de --- /dev/null +++ b/lib/Fuzzer/test/inline-8bit-counters.test @@ -0,0 +1,3 @@ +CHECK: INFO: Loaded 1 modules with {{.*}} inline 8-bit counters +CHECK: BINGO +RUN: LLVMFuzzer-SimpleTest-Inline8bitCounters -runs=100000 -seed=1 2>&1 | FileCheck %s diff --git a/lib/Fuzzer/test/inline-8bit-counters/CMakeLists.txt b/lib/Fuzzer/test/inline-8bit-counters/CMakeLists.txt new file mode 100644 index 0000000..088ab04 --- /dev/null +++ b/lib/Fuzzer/test/inline-8bit-counters/CMakeLists.txt @@ -0,0 +1,12 @@ +# These tests are instrumented with -fsanitize-coverage=inline-8bit-counters + +set(CMAKE_CXX_FLAGS + "${LIBFUZZER_FLAGS_BASE} -fno-sanitize-coverage=trace-pc-guard -fsanitize-coverage=inline-8bit-counters") + +set(Inline8bitCounterTests + SimpleTest + ) + +foreach(Test ${Inline8bitCounterTests}) + add_libfuzzer_test(${Test}-Inline8bitCounters SOURCES ../${Test}.cpp) +endforeach() diff --git a/lib/Fuzzer/test/trace-pc/CMakeLists.txt b/lib/Fuzzer/test/trace-pc/CMakeLists.txt index e800f82..572fcc9 100644 --- a/lib/Fuzzer/test/trace-pc/CMakeLists.txt +++ b/lib/Fuzzer/test/trace-pc/CMakeLists.txt @@ -1,5 +1,4 @@ -# These tests are not instrumented with coverage and don't -# have coverage rt in the binary. +# These tests are instrumented with -fsanitize-coverage=trace-pc set(CMAKE_CXX_FLAGS "${LIBFUZZER_FLAGS_BASE} -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard -fsanitize-coverage=trace-pc")