From 2e3622bddded96d6e6479619b4011ac9b3698381 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Fri, 20 Feb 2015 03:02:37 +0000 Subject: [PATCH] [fuzzer] one more experimental search mode: -use_coverage_pairs=1 llvm-svn: 229957 --- llvm/lib/Fuzzer/FuzzerDriver.cpp | 1 + llvm/lib/Fuzzer/FuzzerFlags.def | 4 +++- llvm/lib/Fuzzer/FuzzerInternal.h | 3 +++ llvm/lib/Fuzzer/FuzzerLoop.cpp | 25 ++++++++++++++++++++++ llvm/lib/Fuzzer/test/CMakeLists.txt | 1 + .../Fuzzer/test/FourIndependentBranchesTest.cpp | 18 ++++++++++++++++ llvm/lib/Fuzzer/test/fuzzer.test | 5 ++++- 7 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 llvm/lib/Fuzzer/test/FourIndependentBranchesTest.cpp diff --git a/llvm/lib/Fuzzer/FuzzerDriver.cpp b/llvm/lib/Fuzzer/FuzzerDriver.cpp index 8a8659e..1746afd 100644 --- a/llvm/lib/Fuzzer/FuzzerDriver.cpp +++ b/llvm/lib/Fuzzer/FuzzerDriver.cpp @@ -159,6 +159,7 @@ int FuzzerDriver(int argc, char **argv, UserCallback Callback) { Options.MutateDepth = Flags.mutate_depth; Options.ExitOnFirst = Flags.exit_on_first; Options.UseFullCoverageSet = Flags.use_full_coverage_set; + Options.UseCoveragePairs = Flags.use_coverage_pairs; Options.PreferSmallDuringInitialShuffle = Flags.prefer_small_during_initial_shuffle; if (Flags.runs >= 0) diff --git a/llvm/lib/Fuzzer/FuzzerFlags.def b/llvm/lib/Fuzzer/FuzzerFlags.def index 754d02e..068f245 100644 --- a/llvm/lib/Fuzzer/FuzzerFlags.def +++ b/llvm/lib/Fuzzer/FuzzerFlags.def @@ -33,9 +33,11 @@ FUZZER_FLAG( int, save_minimized_corpus, 0, "If 1, the minimized corpus is saved into the first input directory") FUZZER_FLAG(int, use_full_coverage_set, 0, - "Maximize the number of different full" + "Experimental: Maximize the number of different full" " coverage sets as opposed to maximizing the total coverage." " This is potentially MUCH slower, but may discover more paths.") +FUZZER_FLAG(int, use_coverage_pairs, 0, + "Experimental: Maximize the number of different coverage pairs.") FUZZER_FLAG(int, jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn" " this number of jobs in separate worker processes" " with stdout/stderr redirected to fuzz-JOB.log.") diff --git a/llvm/lib/Fuzzer/FuzzerInternal.h b/llvm/lib/Fuzzer/FuzzerInternal.h index bc18c55..980b00e 100644 --- a/llvm/lib/Fuzzer/FuzzerInternal.h +++ b/llvm/lib/Fuzzer/FuzzerInternal.h @@ -49,6 +49,7 @@ class Fuzzer { int MutateDepth = 5; bool ExitOnFirst = false; bool UseFullCoverageSet = false; + bool UseCoveragePairs = false; int PreferSmallDuringInitialShuffle = -1; size_t MaxNumberOfRuns = ULONG_MAX; std::string OutputCorpus; @@ -81,6 +82,7 @@ class Fuzzer { size_t RunOne(const Unit &U); size_t RunOneMaximizeTotalCoverage(const Unit &U); size_t RunOneMaximizeFullCoverageSet(const Unit &U); + size_t RunOneMaximizeCoveragePairs(const Unit &U); void WriteToOutputCorpus(const Unit &U); static void WriteToCrash(const Unit &U, const char *Prefix); @@ -92,6 +94,7 @@ class Fuzzer { std::vector Corpus; std::unordered_set FullCoverageSets; + std::unordered_set CoveragePairs; UserCallback Callback; FuzzingOptions Options; system_clock::time_point ProcessStartTime = system_clock::now(); diff --git a/llvm/lib/Fuzzer/FuzzerLoop.cpp b/llvm/lib/Fuzzer/FuzzerLoop.cpp index 1529d06..70b63eb 100644 --- a/llvm/lib/Fuzzer/FuzzerLoop.cpp +++ b/llvm/lib/Fuzzer/FuzzerLoop.cpp @@ -86,6 +86,8 @@ size_t Fuzzer::RunOne(const Unit &U) { TotalNumberOfRuns++; if (Options.UseFullCoverageSet) return RunOneMaximizeFullCoverageSet(U); + if (Options.UseCoveragePairs) + return RunOneMaximizeCoveragePairs(U); return RunOneMaximizeTotalCoverage(U); } @@ -97,6 +99,29 @@ static uintptr_t HashOfArrayOfPCs(uintptr_t *PCs, uintptr_t NumPCs) { return Res; } +// Experimental. Does not yet scale. +// Fuly reset the current coverage state, run a single unit, +// collect all coverage pairs and return non-zero if a new pair is observed. +size_t Fuzzer::RunOneMaximizeCoveragePairs(const Unit &U) { + __sanitizer_reset_coverage(); + Callback(U.data(), U.size()); + uintptr_t *PCs; + uintptr_t NumPCs = __sanitizer_get_coverage_guards(&PCs); + bool HasNewPairs = false; + for (uintptr_t i = 0; i < NumPCs; i++) { + if (!PCs[i]) continue; + for (uintptr_t j = 0; j < NumPCs; j++) { + if (!PCs[j]) continue; + uint64_t Pair = (i << 32) | j; + HasNewPairs |= CoveragePairs.insert(Pair).second; + } + } + if (HasNewPairs) + return CoveragePairs.size(); + return 0; +} + +// Experimental. // Fuly reset the current coverage state, run a single unit, // compute a hash function from the full coverage set, // return non-zero if the hash value is new. diff --git a/llvm/lib/Fuzzer/test/CMakeLists.txt b/llvm/lib/Fuzzer/test/CMakeLists.txt index eb3c1ee..bed9cd8 100644 --- a/llvm/lib/Fuzzer/test/CMakeLists.txt +++ b/llvm/lib/Fuzzer/test/CMakeLists.txt @@ -5,6 +5,7 @@ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O0 -fsanitize-coverage=4") set(Tests + FourIndependentBranchesTest FullCoverageSetTest InfiniteTest NullDerefTest diff --git a/llvm/lib/Fuzzer/test/FourIndependentBranchesTest.cpp b/llvm/lib/Fuzzer/test/FourIndependentBranchesTest.cpp new file mode 100644 index 0000000..171668b --- /dev/null +++ b/llvm/lib/Fuzzer/test/FourIndependentBranchesTest.cpp @@ -0,0 +1,18 @@ +// Simple test for a fuzzer. The fuzzer must find the string "FUZZ". +#include +#include +#include +#include + +extern "C" void TestOneInput(const uint8_t *Data, size_t Size) { + int bits = 0; + if (Size > 0 && Data[0] == 'F') bits |= 1; + if (Size > 1 && Data[1] == 'U') bits |= 2; + if (Size > 2 && Data[2] == 'Z') bits |= 4; + if (Size > 3 && Data[3] == 'Z') bits |= 8; + if (bits == 15) { + std::cerr << "BINGO!\n"; + exit(1); + } +} + diff --git a/llvm/lib/Fuzzer/test/fuzzer.test b/llvm/lib/Fuzzer/test/fuzzer.test index 51b42d6..1e42e72 100644 --- a/llvm/lib/Fuzzer/test/fuzzer.test +++ b/llvm/lib/Fuzzer/test/fuzzer.test @@ -12,5 +12,8 @@ TimeoutTest: CRASHED; file written to timeout RUN: not ./LLVMFuzzer-NullDerefTest 2>&1 | FileCheck %s --check-prefix=NullDerefTest NullDerefTest: CRASHED; file written to crash- -RUN: not ./LLVMFuzzer-FullCoverageSetTest -timeout=15 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s --check-prefix=FullCoverageSetTest +RUN: not ./LLVMFuzzer-FullCoverageSetTest -timeout=15 -seed=1 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s --check-prefix=FullCoverageSetTest FullCoverageSetTest: BINGO + +RUN: not ./LLVMFuzzer-FourIndependentBranchesTest -timeout=15 -seed=1 -use_coverage_pairs=1 2>&1 | FileCheck %s --check-prefix=FourIndependentBranchesTest +FourIndependentBranchesTest: BINGO -- 2.7.4