diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2016-01-06 20:01:02 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2016-01-06 20:01:02 +0000 |
commit | 8a6c1c25bce0267ee4072bd7b786b921e8a66a35 (patch) | |
tree | ea70b740d40cffe568a990c7aecd1acb5f83f786 /lib/Fuzzer | |
parent | 84fe440ded1bfc237d720c49408b36798d67ceff (diff) |
Diffstat (limited to 'lib/Fuzzer')
-rw-r--r-- | lib/Fuzzer/FuzzerDriver.cpp | 1 | ||||
-rw-r--r-- | lib/Fuzzer/FuzzerFlags.def | 2 | ||||
-rw-r--r-- | lib/Fuzzer/FuzzerInternal.h | 2 | ||||
-rw-r--r-- | lib/Fuzzer/FuzzerLoop.cpp | 18 | ||||
-rw-r--r-- | lib/Fuzzer/FuzzerMutate.cpp | 17 | ||||
-rw-r--r-- | lib/Fuzzer/FuzzerTraceState.cpp | 21 | ||||
-rw-r--r-- | lib/Fuzzer/test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Fuzzer/test/ThreadedTest.cpp | 23 | ||||
-rw-r--r-- | lib/Fuzzer/test/fuzzer-threaded.test | 7 | ||||
-rw-r--r-- | lib/Fuzzer/test/fuzzer.test | 6 |
10 files changed, 86 insertions, 12 deletions
diff --git a/lib/Fuzzer/FuzzerDriver.cpp b/lib/Fuzzer/FuzzerDriver.cpp index dc5f8babbfe6..e8c117ef6087 100644 --- a/lib/Fuzzer/FuzzerDriver.cpp +++ b/lib/Fuzzer/FuzzerDriver.cpp @@ -281,6 +281,7 @@ int FuzzerDriver(const std::vector<std::string> &Args, if (Flags.verbosity > 0 && !Dictionary.empty()) Printf("Dictionary: %zd entries\n", Dictionary.size()); Options.SaveArtifacts = !Flags.test_single_input; + Options.PrintNewCovPcs = Flags.print_new_cov_pcs; Fuzzer F(USF, Options); diff --git a/lib/Fuzzer/FuzzerFlags.def b/lib/Fuzzer/FuzzerFlags.def index c2b506c3c8aa..6d98f66ef9c1 100644 --- a/lib/Fuzzer/FuzzerFlags.def +++ b/lib/Fuzzer/FuzzerFlags.def @@ -72,3 +72,5 @@ FUZZER_FLAG_STRING(exact_artifact_path, FUZZER_FLAG_INT(drill, 0, "Experimental: fuzz using a single unit as the seed " "corpus, then merge with the initial corpus") FUZZER_FLAG_INT(output_csv, 0, "Enable pulse output in CSV format.") +FUZZER_FLAG_INT(print_new_cov_pcs, 0, "If 1, print out new covered pcs.") + diff --git a/lib/Fuzzer/FuzzerInternal.h b/lib/Fuzzer/FuzzerInternal.h index e96a4bc35fe2..17a2cae94a58 100644 --- a/lib/Fuzzer/FuzzerInternal.h +++ b/lib/Fuzzer/FuzzerInternal.h @@ -97,6 +97,7 @@ class Fuzzer { bool SaveArtifacts = true; bool PrintNEW = true; // Print a status line when new units are found; bool OutputCSV = false; + bool PrintNewCovPcs = false; }; Fuzzer(UserSuppliedFuzzer &USF, FuzzingOptions Options); void AddToCorpus(const Unit &U) { Corpus.push_back(U); } @@ -188,6 +189,7 @@ class Fuzzer { long EpochOfLastReadOfOutputCorpus = 0; size_t LastRecordedBlockCoverage = 0; size_t LastRecordedCallerCalleeCoverage = 0; + size_t LastCoveragePcBufferLen = 0; }; class SimpleUserSuppliedFuzzer: public UserSuppliedFuzzer { diff --git a/lib/Fuzzer/FuzzerLoop.cpp b/lib/Fuzzer/FuzzerLoop.cpp index 7ea82f4f15dd..0b1d9d9686a2 100644 --- a/lib/Fuzzer/FuzzerLoop.cpp +++ b/lib/Fuzzer/FuzzerLoop.cpp @@ -31,6 +31,8 @@ void __sanitizer_set_death_callback(void (*callback)(void)); __attribute__((weak)) size_t __sanitizer_get_number_of_counters(); __attribute__((weak)) uintptr_t __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset); +__attribute__((weak)) uintptr_t +__sanitizer_get_coverage_pc_buffer(uintptr_t **data); } namespace fuzzer { @@ -249,7 +251,21 @@ void Fuzzer::ExecuteCallback(const Unit &U) { size_t Fuzzer::RecordBlockCoverage() { CHECK_WEAK_API_FUNCTION(__sanitizer_get_total_unique_coverage); - return LastRecordedBlockCoverage = __sanitizer_get_total_unique_coverage(); + uintptr_t PrevCoverage = LastRecordedBlockCoverage; + LastRecordedBlockCoverage = __sanitizer_get_total_unique_coverage(); + + if (PrevCoverage == LastRecordedBlockCoverage || !Options.PrintNewCovPcs) + return LastRecordedBlockCoverage; + + uintptr_t PrevBufferLen = LastCoveragePcBufferLen; + uintptr_t *CoverageBuf; + LastCoveragePcBufferLen = __sanitizer_get_coverage_pc_buffer(&CoverageBuf); + assert(CoverageBuf); + for (size_t i = PrevBufferLen; i < LastCoveragePcBufferLen; ++i) { + Printf("0x%x\n", CoverageBuf[i]); + } + + return LastRecordedBlockCoverage; } size_t Fuzzer::RecordCallerCalleeCoverage() { diff --git a/lib/Fuzzer/FuzzerMutate.cpp b/lib/Fuzzer/FuzzerMutate.cpp index c3fa37a435d6..84ee18e69fb0 100644 --- a/lib/Fuzzer/FuzzerMutate.cpp +++ b/lib/Fuzzer/FuzzerMutate.cpp @@ -117,11 +117,18 @@ size_t MutationDispatcher::Mutate_AddWordFromDictionary(uint8_t *Data, assert(!D.empty()); if (D.empty()) return 0; const Unit &Word = D[Rand(D.size())]; - if (Size + Word.size() > MaxSize) return 0; - size_t Idx = Rand(Size + 1); - memmove(Data + Idx + Word.size(), Data + Idx, Size - Idx); - memcpy(Data + Idx, Word.data(), Word.size()); - return Size + Word.size(); + if (Rand.RandBool()) { // Insert Word. + if (Size + Word.size() > MaxSize) return 0; + size_t Idx = Rand(Size + 1); + memmove(Data + Idx + Word.size(), Data + Idx, Size - Idx); + memcpy(Data + Idx, Word.data(), Word.size()); + return Size + Word.size(); + } else { // Overwrite some bytes with Word. + if (Word.size() > Size) return 0; + size_t Idx = Rand(Size - Word.size()); + memcpy(Data + Idx, Word.data(), Word.size()); + return Size; + } } size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, diff --git a/lib/Fuzzer/FuzzerTraceState.cpp b/lib/Fuzzer/FuzzerTraceState.cpp index 8204a2ddc7c8..241c2f0ce590 100644 --- a/lib/Fuzzer/FuzzerTraceState.cpp +++ b/lib/Fuzzer/FuzzerTraceState.cpp @@ -77,6 +77,7 @@ #include <algorithm> #include <cstring> +#include <thread> #include <unordered_map> #if !LLVM_FUZZER_SUPPORTS_DFSAN @@ -172,8 +173,13 @@ struct TraceBasedMutation { class TraceState { public: - TraceState(const Fuzzer::FuzzingOptions &Options, const Unit &CurrentUnit) - : Options(Options), CurrentUnit(CurrentUnit) {} + TraceState(const Fuzzer::FuzzingOptions &Options, const Unit &CurrentUnit) + : Options(Options), CurrentUnit(CurrentUnit) { + // Current trace collection is not thread-friendly and it probably + // does not have to be such, but at least we should not crash in presence + // of threads. So, just ignore all traces coming from all threads but one. + IsMyThread = true; + } LabelRange GetLabelRange(dfsan_label L); void DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, @@ -213,8 +219,11 @@ class TraceState { LabelRange LabelRanges[1 << (sizeof(dfsan_label) * 8)]; const Fuzzer::FuzzingOptions &Options; const Unit &CurrentUnit; + static thread_local bool IsMyThread; }; +thread_local bool TraceState::IsMyThread; + LabelRange TraceState::GetLabelRange(dfsan_label L) { LabelRange &LR = LabelRanges[L]; if (LR.Beg < LR.End || L == 0) @@ -238,7 +247,7 @@ void TraceState::DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, uint64_t Arg1, uint64_t Arg2, dfsan_label L1, dfsan_label L2) { assert(ReallyHaveDFSan()); - if (!RecordingTraces) return; + if (!RecordingTraces || !IsMyThread) return; if (L1 == 0 && L2 == 0) return; // Not actionable. if (L1 != 0 && L2 != 0) @@ -267,7 +276,7 @@ void TraceState::DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits, uint64_t Val, size_t NumCases, uint64_t *Cases, dfsan_label L) { assert(ReallyHaveDFSan()); - if (!RecordingTraces) return; + if (!RecordingTraces || !IsMyThread) return; if (!L) return; // Not actionable. LabelRange LR = GetLabelRange(L); size_t ValSize = ValSizeInBits / 8; @@ -312,7 +321,7 @@ int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData, void TraceState::TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, uint64_t Arg1, uint64_t Arg2) { - if (!RecordingTraces) return; + if (!RecordingTraces || !IsMyThread) return; int Added = 0; if (Options.Verbosity >= 3) Printf("TraceCmp %zd/%zd: %p %zd %zd\n", CmpSize, CmpType, PC, Arg1, Arg2); @@ -327,7 +336,7 @@ void TraceState::TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, void TraceState::TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits, uint64_t Val, size_t NumCases, uint64_t *Cases) { - if (!RecordingTraces) return; + if (!RecordingTraces || !IsMyThread) return; size_t ValSize = ValSizeInBits / 8; bool TryShort = IsTwoByteData(Val); for (size_t i = 0; i < NumCases; i++) diff --git a/lib/Fuzzer/test/CMakeLists.txt b/lib/Fuzzer/test/CMakeLists.txt index 674fcc3c9f8c..cd0b167eb388 100644 --- a/lib/Fuzzer/test/CMakeLists.txt +++ b/lib/Fuzzer/test/CMakeLists.txt @@ -26,6 +26,7 @@ set(Tests StrcmpTest StrncmpTest SwitchTest + ThreadedTest TimeoutTest ) diff --git a/lib/Fuzzer/test/ThreadedTest.cpp b/lib/Fuzzer/test/ThreadedTest.cpp new file mode 100644 index 000000000000..7aa114a41f36 --- /dev/null +++ b/lib/Fuzzer/test/ThreadedTest.cpp @@ -0,0 +1,23 @@ +// Threaded test for a fuzzer. The fuzzer should not crash. +#include <assert.h> +#include <cstdint> +#include <cstddef> +#include <cstring> +#include <thread> + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 8) return 0; + assert(Data); + auto C = [&] { + size_t Res = 0; + for (size_t i = 0; i < Size / 2; i++) + Res += memcmp(Data, Data + Size / 2, 4); + return Res; + }; + std::thread T[] = {std::thread(C), std::thread(C), std::thread(C), + std::thread(C), std::thread(C), std::thread(C)}; + for (auto &X : T) + X.join(); + return 0; +} + diff --git a/lib/Fuzzer/test/fuzzer-threaded.test b/lib/Fuzzer/test/fuzzer-threaded.test new file mode 100644 index 000000000000..c58a33456ccb --- /dev/null +++ b/lib/Fuzzer/test/fuzzer-threaded.test @@ -0,0 +1,7 @@ +CHECK: Done 1000 runs in + +RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s +RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s +RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s +RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s + diff --git a/lib/Fuzzer/test/fuzzer.test b/lib/Fuzzer/test/fuzzer.test index 810410df6fc7..150fc7202b00 100644 --- a/lib/Fuzzer/test/fuzzer.test +++ b/lib/Fuzzer/test/fuzzer.test @@ -30,3 +30,9 @@ RUN: LLVMFuzzer-SimpleDictionaryTest -seed=1 -runs=100000 RUN: not LLVMFuzzer-UninstrumentedTest-Uninstrumented 2>&1 | FileCheck %s --check-prefix=UNINSTRUMENTED UNINSTRUMENTED: ERROR: __sanitizer_set_death_callback is not defined. Exiting. + +RUN: LLVMFuzzer-SimpleTest -print_new_cov_pcs=1 2>&1 | FileCheck %s --check-prefix=PCS +PCS:{{^0x[a-f0-9]+}} +PCS:NEW +PCS:BINGO + |