[libFuzzer] initial implementation of path coverage based on -fsanitize-coverage=trace-pc. This does not scale well yet, but already cracks FullCoverageSetTest in seconds

llvm-svn: 262073
This commit is contained in:
Kostya Serebryany 2016-02-26 21:33:56 +00:00
parent 297ce4ece9
commit da63c1d09a
7 changed files with 103 additions and 0 deletions

View File

@ -12,6 +12,7 @@ if( LLVM_USE_SANITIZE_COVERAGE )
FuzzerMutate.cpp
FuzzerSanitizerOptions.cpp
FuzzerSHA1.cpp
FuzzerTracePC.cpp
FuzzerUtil.cpp
)
add_library(LLVMFuzzerNoMain STATIC

View File

@ -99,6 +99,13 @@ bool IsASCII(const Unit &U);
int NumberOfCpuCores();
int GetPid();
// Clears the current PC Map.
void PcMapResetCurrent();
// Merges the current PC Map into the combined one, and clears the former.
void PcMapMergeCurrentToCombined();
// Returns the size of the combined PC Map.
size_t PcMapCombinedSize();
class Random {
public:
Random(unsigned int seed) : R(seed) {}
@ -390,6 +397,7 @@ private:
long TimeOfLongestUnitInSeconds = 0;
long EpochOfLastReadOfOutputCorpus = 0;
size_t LastRecordedBlockCoverage = 0;
size_t LastRecordedPcMapSize = 0;
size_t LastRecordedCallerCalleeCoverage = 0;
size_t LastCoveragePcBufferLen = 0;
};

View File

@ -151,6 +151,8 @@ void Fuzzer::PrintStats(const char *Where, const char *End) {
Printf("#%zd\t%s", TotalNumberOfRuns, Where);
if (LastRecordedBlockCoverage)
Printf(" cov: %zd", LastRecordedBlockCoverage);
if (LastRecordedPcMapSize)
Printf(" path: %zd", LastRecordedPcMapSize);
if (auto TB = TotalBits())
Printf(" bits: %zd", TB);
if (LastRecordedCallerCalleeCoverage)
@ -316,6 +318,12 @@ bool Fuzzer::CheckCoverageAfterRun() {
size_t OldCallerCalleeCoverage = LastRecordedCallerCalleeCoverage;
size_t NewCallerCalleeCoverage = RecordCallerCalleeCoverage();
size_t NumNewBits = 0;
size_t OldPcMapSize = LastRecordedPcMapSize;
PcMapMergeCurrentToCombined();
size_t NewPcMapSize = PcMapCombinedSize();
LastRecordedPcMapSize = NewPcMapSize;
if (NewPcMapSize > OldPcMapSize)
return true;
if (Options.UseCounters)
NumNewBits = __sanitizer_update_counter_bitset_and_clear_counters(
CounterBitmap.data());

View File

@ -0,0 +1,59 @@
//===- FuzzerTracePC.cpp - PC tracing--------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Trace PCs.
// This module implements __sanitizer_cov_trace_pc, a callback required
// for -fsanitize-coverage=trace-pc instrumentation.
//
// Experimental and not yet tuned for performance.
//===----------------------------------------------------------------------===//
#include "FuzzerInternal.h"
namespace fuzzer {
static const size_t kMapSize = 65371; // Prime.
static uint8_t CurMap[kMapSize];
static uint8_t CombinedMap[kMapSize];
static size_t CombinedMapSize;
static thread_local uintptr_t Prev;
void PcMapResetCurrent() {
if (Prev) {
Prev = 0;
memset(CurMap, 0, sizeof(CurMap));
}
}
// TODO: speed this up.
void PcMapMergeCurrentToCombined() {
if (!Prev) return;
uintptr_t Res = 0;
for (size_t i = 0; i < kMapSize; i++) {
uint8_t p = (CombinedMap[i] |= CurMap[i]);
CurMap[i] = 0;
Res += p != 0;
}
CombinedMapSize = Res;
}
size_t PcMapCombinedSize() { return CombinedMapSize; }
static void HandlePC(uintptr_t PC) {
// We take 12 bits of PC and mix it with the previous PCs.
uintptr_t Idx = (Prev << 5) ^ (PC & 4095);
CurMap[Idx % kMapSize] = 1;
Prev = Idx;
}
} // namespace fuzzer
extern "C" void __sanitizer_cov_trace_pc() {
fuzzer::HandlePC(reinterpret_cast<uintptr_t>(__builtin_return_address(0)));
}
//uintptr_t __sanitizer_get_total_unique_coverage() { return 0; }
//uintptr_t __sanitizer_get_number_of_counters() { return 0; }

View File

@ -47,6 +47,11 @@ set(TraceBBTests
SimpleTest
)
set(TracePCTests
FourIndependentBranchesTest
FullCoverageSetTest
)
set(TestBinaries)
foreach(Test ${Tests})
@ -113,6 +118,12 @@ foreach(Test ${TraceBBTests})
set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test}-TraceBB)
endforeach()
add_subdirectory(trace-pc)
foreach(Test ${TracePCTests})
set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test}-TracePC)
endforeach()
set_target_properties(${TestBinaries}
PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)

View File

@ -0,0 +1,2 @@
CHECK: BINGO
RUN: not LLVMFuzzer-FourIndependentBranchesTest-TracePC -seed=1 -runs=1000000 2>&1 | FileCheck %s

View File

@ -0,0 +1,14 @@
# These tests are not instrumented with coverage.
set(CMAKE_CXX_FLAGS_RELEASE
"${LIBFUZZER_FLAGS_BASE} -O0 -fno-sanitize-coverage=8bit-counters -fsanitize-coverage=trace-pc")
foreach(Test ${TracePCTests})
add_executable(LLVMFuzzer-${Test}-TracePC
../${Test}.cpp
)
target_link_libraries(LLVMFuzzer-${Test}-TracePC
LLVMFuzzer
)
endforeach()