Index: lib/fuzzer/CMakeLists.txt =================================================================== --- lib/fuzzer/CMakeLists.txt +++ /dev/null @@ -1,77 +0,0 @@ -include(CheckCXXSourceCompiles) - -if( APPLE ) - CHECK_CXX_SOURCE_COMPILES(" - static thread_local int blah; - int main() { - return 0; - } - " HAS_THREAD_LOCAL) - - if( NOT HAS_THREAD_LOCAL ) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Dthread_local=__thread") - endif() -endif() - -if (CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux") - set(LIBFUZZER_ENABLED_CHECK ON) -else() - set(LIBFUZZER_ENABLED_CHECK OFF) -endif() - -# Compile libFuzzer if the compilation is specifically requested, OR -# if the platform is known to be working. -set(LIBFUZZER_ENABLE ${LIBFUZZER_ENABLED_CHECK} CACHE BOOL "Build libFuzzer and its tests") -set(LIBFUZZER_ENABLE_TESTS OFF CACHE BOOL "Build libFuzzer and its tests") - -if (LLVM_USE_SANITIZE_COVERAGE) - set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -fno-sanitize-coverage=trace-pc-guard,edge,trace-cmp,indirect-calls,8bit-counters -Werror") -endif() - -if (LIBFUZZER_ENABLE) - add_library(LLVMFuzzerNoMainObjects OBJECT - FuzzerCrossOver.cpp - FuzzerDriver.cpp - FuzzerExtFunctionsDlsym.cpp - FuzzerExtFunctionsDlsymWin.cpp - FuzzerExtFunctionsWeak.cpp - FuzzerExtraCounters.cpp - FuzzerIO.cpp - FuzzerIOPosix.cpp - FuzzerIOWindows.cpp - FuzzerLoop.cpp - FuzzerMerge.cpp - FuzzerMutate.cpp - FuzzerSHA1.cpp - FuzzerShmemPosix.cpp - FuzzerShmemWindows.cpp - FuzzerTracePC.cpp - FuzzerUtil.cpp - FuzzerUtilDarwin.cpp - FuzzerUtilLinux.cpp - FuzzerUtilPosix.cpp - FuzzerUtilWindows.cpp - ) - add_library(LLVMFuzzerNoMain STATIC - $ - ) - target_link_libraries(LLVMFuzzerNoMain ${LLVM_PTHREAD_LIB}) - add_library(LLVMFuzzer STATIC - FuzzerMain.cpp - $ - ) - target_link_libraries(LLVMFuzzer ${LLVM_PTHREAD_LIB}) -endif() - -if (MSVC) - - # Until bots are reconfigured, check-fuzzer on Windows is a no-OP. - add_custom_target(check-fuzzer) - add_custom_command(TARGET check-fuzzer - COMMAND cmake -E echo "check-fuzzer is disalbed on Windows") -else() - if (LLVM_INCLUDE_TESTS AND LIBFUZZER_ENABLE_TESTS) - add_subdirectory(test) - endif() -endif() Index: lib/fuzzer/FuzzerCorpus.h =================================================================== --- lib/fuzzer/FuzzerCorpus.h +++ /dev/null @@ -1,275 +0,0 @@ -//===- FuzzerCorpus.h - Internal header for the Fuzzer ----------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// fuzzer::InputCorpus -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_CORPUS -#define LLVM_FUZZER_CORPUS - -#include "FuzzerDefs.h" -#include "FuzzerIO.h" -#include "FuzzerRandom.h" -#include "FuzzerSHA1.h" -#include "FuzzerTracePC.h" -#include -#include -#include -#include - -namespace fuzzer { - -struct InputInfo { - Unit U; // The actual input data. - uint8_t Sha1[kSHA1NumBytes]; // Checksum. - // Number of features that this input has and no smaller input has. - size_t NumFeatures = 0; - size_t Tmp = 0; // Used by ValidateFeatureSet. - // Stats. - size_t NumExecutedMutations = 0; - size_t NumSuccessfullMutations = 0; - bool MayDeleteFile = false; - bool Reduced = false; - std::vector UniqFeatureSet; -}; - -class InputCorpus { - static const size_t kFeatureSetSize = 1 << 21; - public: - InputCorpus(const std::string &OutputCorpus) : OutputCorpus(OutputCorpus) { - memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature)); - memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature)); - } - ~InputCorpus() { - for (auto II : Inputs) - delete II; - } - size_t size() const { return Inputs.size(); } - size_t SizeInBytes() const { - size_t Res = 0; - for (auto II : Inputs) - Res += II->U.size(); - return Res; - } - size_t NumActiveUnits() const { - size_t Res = 0; - for (auto II : Inputs) - Res += !II->U.empty(); - return Res; - } - size_t MaxInputSize() const { - size_t Res = 0; - for (auto II : Inputs) - Res = std::max(Res, II->U.size()); - return Res; - } - bool empty() const { return Inputs.empty(); } - const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; } - void AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile, - const std::vector &FeatureSet) { - assert(!U.empty()); - if (FeatureDebug) - Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures); - Inputs.push_back(new InputInfo()); - InputInfo &II = *Inputs.back(); - II.U = U; - II.NumFeatures = NumFeatures; - II.MayDeleteFile = MayDeleteFile; - II.UniqFeatureSet = FeatureSet; - std::sort(II.UniqFeatureSet.begin(), II.UniqFeatureSet.end()); - ComputeSHA1(U.data(), U.size(), II.Sha1); - Hashes.insert(Sha1ToString(II.Sha1)); - UpdateCorpusDistribution(); - PrintCorpus(); - // ValidateFeatureSet(); - } - - // Debug-only - void PrintUnit(const Unit &U) { - if (!FeatureDebug) return; - for (uint8_t C : U) { - if (C != 'F' && C != 'U' && C != 'Z') - C = '.'; - Printf("%c", C); - } - } - - // Debug-only - void PrintFeatureSet(const std::vector &FeatureSet) { - if (!FeatureDebug) return; - Printf("{"); - for (uint32_t Feature: FeatureSet) - Printf("%u,", Feature); - Printf("}"); - } - - // Debug-only - void PrintCorpus() { - if (!FeatureDebug) return; - Printf("======= CORPUS:\n"); - int i = 0; - for (auto II : Inputs) { - if (std::find(II->U.begin(), II->U.end(), 'F') != II->U.end()) { - Printf("[%2d] ", i); - Printf("%s sz=%zd ", Sha1ToString(II->Sha1).c_str(), II->U.size()); - PrintUnit(II->U); - Printf(" "); - PrintFeatureSet(II->UniqFeatureSet); - Printf("\n"); - } - i++; - } - } - - void Replace(InputInfo *II, const Unit &U) { - assert(II->U.size() > U.size()); - Hashes.erase(Sha1ToString(II->Sha1)); - DeleteFile(*II); - ComputeSHA1(U.data(), U.size(), II->Sha1); - Hashes.insert(Sha1ToString(II->Sha1)); - II->U = U; - II->Reduced = true; - } - - bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); } - bool HasUnit(const std::string &H) { return Hashes.count(H); } - InputInfo &ChooseUnitToMutate(Random &Rand) { - InputInfo &II = *Inputs[ChooseUnitIdxToMutate(Rand)]; - assert(!II.U.empty()); - return II; - }; - - // Returns an index of random unit from the corpus to mutate. - // Hypothesis: units added to the corpus last are more likely to be - // interesting. This function gives more weight to the more recent units. - size_t ChooseUnitIdxToMutate(Random &Rand) { - size_t Idx = static_cast(CorpusDistribution(Rand)); - assert(Idx < Inputs.size()); - return Idx; - } - - void PrintStats() { - for (size_t i = 0; i < Inputs.size(); i++) { - const auto &II = *Inputs[i]; - Printf(" [%zd %s]\tsz: %zd\truns: %zd\tsucc: %zd\n", i, - Sha1ToString(II.Sha1).c_str(), II.U.size(), - II.NumExecutedMutations, II.NumSuccessfullMutations); - } - } - - void PrintFeatureSet() { - for (size_t i = 0; i < kFeatureSetSize; i++) { - if(size_t Sz = GetFeature(i)) - Printf("[%zd: id %zd sz%zd] ", i, SmallestElementPerFeature[i], Sz); - } - Printf("\n\t"); - for (size_t i = 0; i < Inputs.size(); i++) - if (size_t N = Inputs[i]->NumFeatures) - Printf(" %zd=>%zd ", i, N); - Printf("\n"); - } - - void DeleteFile(const InputInfo &II) { - if (!OutputCorpus.empty() && II.MayDeleteFile) - RemoveFile(DirPlusFile(OutputCorpus, Sha1ToString(II.Sha1))); - } - - void DeleteInput(size_t Idx) { - InputInfo &II = *Inputs[Idx]; - DeleteFile(II); - Unit().swap(II.U); - if (FeatureDebug) - Printf("EVICTED %zd\n", Idx); - } - - bool AddFeature(size_t Idx, uint32_t NewSize, bool Shrink) { - assert(NewSize); - Idx = Idx % kFeatureSetSize; - uint32_t OldSize = GetFeature(Idx); - if (OldSize == 0 || (Shrink && OldSize > NewSize)) { - if (OldSize > 0) { - size_t OldIdx = SmallestElementPerFeature[Idx]; - InputInfo &II = *Inputs[OldIdx]; - assert(II.NumFeatures > 0); - II.NumFeatures--; - if (II.NumFeatures == 0) - DeleteInput(OldIdx); - } else { - NumAddedFeatures++; - } - NumUpdatedFeatures++; - if (FeatureDebug) - Printf("ADD FEATURE %zd sz %d\n", Idx, NewSize); - SmallestElementPerFeature[Idx] = Inputs.size(); - InputSizesPerFeature[Idx] = NewSize; - return true; - } - return false; - } - - size_t NumFeatures() const { return NumAddedFeatures; } - size_t NumFeatureUpdates() const { return NumUpdatedFeatures; } - - void ResetFeatureSet() { - assert(Inputs.empty()); - memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature)); - memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature)); - } - -private: - - static const bool FeatureDebug = false; - - size_t GetFeature(size_t Idx) const { return InputSizesPerFeature[Idx]; } - - void ValidateFeatureSet() { - if (FeatureDebug) - PrintFeatureSet(); - for (size_t Idx = 0; Idx < kFeatureSetSize; Idx++) - if (GetFeature(Idx)) - Inputs[SmallestElementPerFeature[Idx]]->Tmp++; - for (auto II: Inputs) { - if (II->Tmp != II->NumFeatures) - Printf("ZZZ %zd %zd\n", II->Tmp, II->NumFeatures); - assert(II->Tmp == II->NumFeatures); - II->Tmp = 0; - } - } - - // Updates the probability distribution for the units in the corpus. - // Must be called whenever the corpus or unit weights are changed. - void UpdateCorpusDistribution() { - size_t N = Inputs.size(); - assert(N); - Intervals.resize(N + 1); - Weights.resize(N); - std::iota(Intervals.begin(), Intervals.end(), 0); - for (size_t i = 0; i < N; i++) - Weights[i] = Inputs[i]->NumFeatures * (i + 1); - CorpusDistribution = std::piecewise_constant_distribution( - Intervals.begin(), Intervals.end(), Weights.begin()); - } - std::piecewise_constant_distribution CorpusDistribution; - - std::vector Intervals; - std::vector Weights; - - std::unordered_set Hashes; - std::vector Inputs; - - size_t NumAddedFeatures = 0; - size_t NumUpdatedFeatures = 0; - uint32_t InputSizesPerFeature[kFeatureSetSize]; - uint32_t SmallestElementPerFeature[kFeatureSetSize]; - - std::string OutputCorpus; -}; - -} // namespace fuzzer - -#endif // LLVM_FUZZER_CORPUS Index: lib/fuzzer/FuzzerCrossOver.cpp =================================================================== --- lib/fuzzer/FuzzerCrossOver.cpp +++ /dev/null @@ -1,52 +0,0 @@ -//===- FuzzerCrossOver.cpp - Cross over two test inputs -------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Cross over test inputs. -//===----------------------------------------------------------------------===// - -#include "FuzzerDefs.h" -#include "FuzzerMutate.h" -#include "FuzzerRandom.h" -#include - -namespace fuzzer { - -// Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out. -size_t MutationDispatcher::CrossOver(const uint8_t *Data1, size_t Size1, - const uint8_t *Data2, size_t Size2, - uint8_t *Out, size_t MaxOutSize) { - assert(Size1 || Size2); - MaxOutSize = Rand(MaxOutSize) + 1; - size_t OutPos = 0; - size_t Pos1 = 0; - size_t Pos2 = 0; - size_t *InPos = &Pos1; - size_t InSize = Size1; - const uint8_t *Data = Data1; - bool CurrentlyUsingFirstData = true; - while (OutPos < MaxOutSize && (Pos1 < Size1 || Pos2 < Size2)) { - // Merge a part of Data into Out. - size_t OutSizeLeft = MaxOutSize - OutPos; - if (*InPos < InSize) { - size_t InSizeLeft = InSize - *InPos; - size_t MaxExtraSize = std::min(OutSizeLeft, InSizeLeft); - size_t ExtraSize = Rand(MaxExtraSize) + 1; - memcpy(Out + OutPos, Data + *InPos, ExtraSize); - OutPos += ExtraSize; - (*InPos) += ExtraSize; - } - // Use the other input data on the next iteration. - InPos = CurrentlyUsingFirstData ? &Pos2 : &Pos1; - InSize = CurrentlyUsingFirstData ? Size2 : Size1; - Data = CurrentlyUsingFirstData ? Data2 : Data1; - CurrentlyUsingFirstData = !CurrentlyUsingFirstData; - } - return OutPos; -} - -} // namespace fuzzer Index: lib/fuzzer/FuzzerDefs.h =================================================================== --- lib/fuzzer/FuzzerDefs.h +++ /dev/null @@ -1,128 +0,0 @@ -//===- FuzzerDefs.h - Internal header for the Fuzzer ------------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Basic definitions. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_DEFS_H -#define LLVM_FUZZER_DEFS_H - -#include -#include -#include -#include -#include -#include - -// Platform detection. -#ifdef __linux__ -#define LIBFUZZER_APPLE 0 -#define LIBFUZZER_LINUX 1 -#define LIBFUZZER_WINDOWS 0 -#elif __APPLE__ -#define LIBFUZZER_APPLE 1 -#define LIBFUZZER_LINUX 0 -#define LIBFUZZER_WINDOWS 0 -#elif _WIN32 -#define LIBFUZZER_APPLE 0 -#define LIBFUZZER_LINUX 0 -#define LIBFUZZER_WINDOWS 1 -#else -#error "Support for your platform has not been implemented" -#endif - -#ifndef __has_attribute -# define __has_attribute(x) 0 -#endif - -#define LIBFUZZER_POSIX LIBFUZZER_APPLE || LIBFUZZER_LINUX - -#ifdef __x86_64 -# if __has_attribute(target) -# define ATTRIBUTE_TARGET_POPCNT __attribute__((target("popcnt"))) -# else -# define ATTRIBUTE_TARGET_POPCNT -# endif -#else -# define ATTRIBUTE_TARGET_POPCNT -#endif - - -#ifdef __clang__ // avoid gcc warning. -# if __has_attribute(no_sanitize) -# define ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory"))) -# else -# define ATTRIBUTE_NO_SANITIZE_MEMORY -# endif -# define ALWAYS_INLINE __attribute__((always_inline)) -#else -# define ATTRIBUTE_NO_SANITIZE_MEMORY -# define ALWAYS_INLINE -#endif // __clang__ - -#define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) - -#if defined(__has_feature) -# if __has_feature(address_sanitizer) -# define ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_NO_SANITIZE_ADDRESS -# elif __has_feature(memory_sanitizer) -# define ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_NO_SANITIZE_MEMORY -# else -# define ATTRIBUTE_NO_SANITIZE_ALL -# endif -#else -# define ATTRIBUTE_NO_SANITIZE_ALL -#endif - -#if LIBFUZZER_WINDOWS -#define ATTRIBUTE_INTERFACE __declspec(dllexport) -#else -#define ATTRIBUTE_INTERFACE __attribute__((visibility("default"))) -#endif - -namespace fuzzer { - -template T Min(T a, T b) { return a < b ? a : b; } -template T Max(T a, T b) { return a > b ? a : b; } - -class Random; -class Dictionary; -class DictionaryEntry; -class MutationDispatcher; -struct FuzzingOptions; -class InputCorpus; -struct InputInfo; -struct ExternalFunctions; - -// Global interface to functions that may or may not be available. -extern ExternalFunctions *EF; - -typedef std::vector Unit; -typedef std::vector UnitVector; -typedef int (*UserCallback)(const uint8_t *Data, size_t Size); - -int FuzzerDriver(int *argc, char ***argv, UserCallback Callback); - -struct ScopedDoingMyOwnMemOrStr { - ScopedDoingMyOwnMemOrStr() { DoingMyOwnMemOrStr++; } - ~ScopedDoingMyOwnMemOrStr() { DoingMyOwnMemOrStr--; } - static int DoingMyOwnMemOrStr; -}; - -inline uint8_t Bswap(uint8_t x) { return x; } -inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); } -inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); } -inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); } - -uint8_t *ExtraCountersBegin(); -uint8_t *ExtraCountersEnd(); -void ClearExtraCounters(); - -} // namespace fuzzer - -#endif // LLVM_FUZZER_DEFS_H Index: lib/fuzzer/FuzzerDictionary.h =================================================================== --- lib/fuzzer/FuzzerDictionary.h +++ /dev/null @@ -1,127 +0,0 @@ -//===- FuzzerDictionary.h - Internal header for the Fuzzer ------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// fuzzer::Dictionary -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_DICTIONARY_H -#define LLVM_FUZZER_DICTIONARY_H - -#include "FuzzerDefs.h" -#include "FuzzerIO.h" -#include "FuzzerUtil.h" -#include -#include - -namespace fuzzer { -// A simple POD sized array of bytes. -template class FixedWord { -public: - static const size_t kMaxSize = kMaxSizeT; - FixedWord() {} - FixedWord(const uint8_t *B, uint8_t S) { Set(B, S); } - - void Set(const uint8_t *B, uint8_t S) { - assert(S <= kMaxSize); - memcpy(Data, B, S); - Size = S; - } - - bool operator==(const FixedWord &w) const { - ScopedDoingMyOwnMemOrStr scoped_doing_my_own_mem_os_str; - return Size == w.Size && 0 == memcmp(Data, w.Data, Size); - } - - bool operator<(const FixedWord &w) const { - ScopedDoingMyOwnMemOrStr scoped_doing_my_own_mem_os_str; - if (Size != w.Size) - return Size < w.Size; - return memcmp(Data, w.Data, Size) < 0; - } - - static size_t GetMaxSize() { return kMaxSize; } - const uint8_t *data() const { return Data; } - uint8_t size() const { return Size; } - -private: - uint8_t Size = 0; - uint8_t Data[kMaxSize]; -}; - -typedef FixedWord<64> Word; - -class DictionaryEntry { - public: - DictionaryEntry() {} - DictionaryEntry(Word W) : W(W) {} - DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {} - const Word &GetW() const { return W; } - - bool HasPositionHint() const { return PositionHint != std::numeric_limits::max(); } - size_t GetPositionHint() const { - assert(HasPositionHint()); - return PositionHint; - } - void IncUseCount() { UseCount++; } - void IncSuccessCount() { SuccessCount++; } - size_t GetUseCount() const { return UseCount; } - size_t GetSuccessCount() const {return SuccessCount; } - - void Print(const char *PrintAfter = "\n") { - PrintASCII(W.data(), W.size()); - if (HasPositionHint()) - Printf("@%zd", GetPositionHint()); - Printf("%s", PrintAfter); - } - -private: - Word W; - size_t PositionHint = std::numeric_limits::max(); - size_t UseCount = 0; - size_t SuccessCount = 0; -}; - -class Dictionary { - public: - static const size_t kMaxDictSize = 1 << 14; - - bool ContainsWord(const Word &W) const { - return std::any_of(begin(), end(), [&](const DictionaryEntry &DE) { - return DE.GetW() == W; - }); - } - const DictionaryEntry *begin() const { return &DE[0]; } - const DictionaryEntry *end() const { return begin() + Size; } - DictionaryEntry & operator[] (size_t Idx) { - assert(Idx < Size); - return DE[Idx]; - } - void push_back(DictionaryEntry DE) { - if (Size < kMaxDictSize) - this->DE[Size++] = DE; - } - void clear() { Size = 0; } - bool empty() const { return Size == 0; } - size_t size() const { return Size; } - -private: - DictionaryEntry DE[kMaxDictSize]; - size_t Size = 0; -}; - -// Parses one dictionary entry. -// If successfull, write the enty to Unit and returns true, -// otherwise returns false. -bool ParseOneDictionaryEntry(const std::string &Str, Unit *U); -// Parses the dictionary file, fills Units, returns true iff all lines -// were parsed succesfully. -bool ParseDictionaryFile(const std::string &Text, std::vector *Units); - -} // namespace fuzzer - -#endif // LLVM_FUZZER_DICTIONARY_H Index: lib/fuzzer/FuzzerDriver.cpp =================================================================== --- lib/fuzzer/FuzzerDriver.cpp +++ /dev/null @@ -1,764 +0,0 @@ -//===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// FuzzerDriver and flag parsing. -//===----------------------------------------------------------------------===// - -#include "FuzzerCorpus.h" -#include "FuzzerIO.h" -#include "FuzzerInterface.h" -#include "FuzzerInternal.h" -#include "FuzzerMutate.h" -#include "FuzzerRandom.h" -#include "FuzzerShmem.h" -#include "FuzzerTracePC.h" -#include -#include -#include -#include -#include -#include -#include -#include - -// This function should be present in the libFuzzer so that the client -// binary can test for its existence. -extern "C" __attribute__((used)) void __libfuzzer_is_present() {} - -namespace fuzzer { - -// Program arguments. -struct FlagDescription { - const char *Name; - const char *Description; - int Default; - int *IntFlag; - const char **StrFlag; - unsigned int *UIntFlag; -}; - -struct { -#define FUZZER_DEPRECATED_FLAG(Name) -#define FUZZER_FLAG_INT(Name, Default, Description) int Name; -#define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name; -#define FUZZER_FLAG_STRING(Name, Description) const char *Name; -#include "FuzzerFlags.def" -#undef FUZZER_DEPRECATED_FLAG -#undef FUZZER_FLAG_INT -#undef FUZZER_FLAG_UNSIGNED -#undef FUZZER_FLAG_STRING -} Flags; - -static const FlagDescription FlagDescriptions [] { -#define FUZZER_DEPRECATED_FLAG(Name) \ - {#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr}, -#define FUZZER_FLAG_INT(Name, Default, Description) \ - {#Name, Description, Default, &Flags.Name, nullptr, nullptr}, -#define FUZZER_FLAG_UNSIGNED(Name, Default, Description) \ - {#Name, Description, static_cast(Default), \ - nullptr, nullptr, &Flags.Name}, -#define FUZZER_FLAG_STRING(Name, Description) \ - {#Name, Description, 0, nullptr, &Flags.Name, nullptr}, -#include "FuzzerFlags.def" -#undef FUZZER_DEPRECATED_FLAG -#undef FUZZER_FLAG_INT -#undef FUZZER_FLAG_UNSIGNED -#undef FUZZER_FLAG_STRING -}; - -static const size_t kNumFlags = - sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]); - -static std::vector *Inputs; -static std::string *ProgName; - -static void PrintHelp() { - Printf("Usage:\n"); - auto Prog = ProgName->c_str(); - Printf("\nTo run fuzzing pass 0 or more directories.\n"); - Printf("%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog); - - Printf("\nTo run individual tests without fuzzing pass 1 or more files:\n"); - Printf("%s [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n", Prog); - - Printf("\nFlags: (strictly in form -flag=value)\n"); - size_t MaxFlagLen = 0; - for (size_t F = 0; F < kNumFlags; F++) - MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen); - - for (size_t F = 0; F < kNumFlags; F++) { - const auto &D = FlagDescriptions[F]; - if (strstr(D.Description, "internal flag") == D.Description) continue; - Printf(" %s", D.Name); - for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++) - Printf(" "); - Printf("\t"); - Printf("%d\t%s\n", D.Default, D.Description); - } - Printf("\nFlags starting with '--' will be ignored and " - "will be passed verbatim to subprocesses.\n"); -} - -static const char *FlagValue(const char *Param, const char *Name) { - size_t Len = strlen(Name); - if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 && - Param[Len + 1] == '=') - return &Param[Len + 2]; - return nullptr; -} - -// Avoid calling stol as it triggers a bug in clang/glibc build. -static long MyStol(const char *Str) { - long Res = 0; - long Sign = 1; - if (*Str == '-') { - Str++; - Sign = -1; - } - for (size_t i = 0; Str[i]; i++) { - char Ch = Str[i]; - if (Ch < '0' || Ch > '9') - return Res; - Res = Res * 10 + (Ch - '0'); - } - return Res * Sign; -} - -static bool ParseOneFlag(const char *Param) { - if (Param[0] != '-') return false; - if (Param[1] == '-') { - static bool PrintedWarning = false; - if (!PrintedWarning) { - PrintedWarning = true; - Printf("INFO: libFuzzer ignores flags that start with '--'\n"); - } - for (size_t F = 0; F < kNumFlags; F++) - if (FlagValue(Param + 1, FlagDescriptions[F].Name)) - Printf("WARNING: did you mean '%s' (single dash)?\n", Param + 1); - return true; - } - for (size_t F = 0; F < kNumFlags; F++) { - const char *Name = FlagDescriptions[F].Name; - const char *Str = FlagValue(Param, Name); - if (Str) { - if (FlagDescriptions[F].IntFlag) { - int Val = MyStol(Str); - *FlagDescriptions[F].IntFlag = Val; - if (Flags.verbosity >= 2) - Printf("Flag: %s %d\n", Name, Val); - return true; - } else if (FlagDescriptions[F].UIntFlag) { - unsigned int Val = std::stoul(Str); - *FlagDescriptions[F].UIntFlag = Val; - if (Flags.verbosity >= 2) - Printf("Flag: %s %u\n", Name, Val); - return true; - } else if (FlagDescriptions[F].StrFlag) { - *FlagDescriptions[F].StrFlag = Str; - if (Flags.verbosity >= 2) - Printf("Flag: %s %s\n", Name, Str); - return true; - } else { // Deprecated flag. - Printf("Flag: %s: deprecated, don't use\n", Name); - return true; - } - } - } - Printf("\n\nWARNING: unrecognized flag '%s'; " - "use -help=1 to list all flags\n\n", Param); - return true; -} - -// We don't use any library to minimize dependencies. -static void ParseFlags(const std::vector &Args) { - for (size_t F = 0; F < kNumFlags; F++) { - if (FlagDescriptions[F].IntFlag) - *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default; - if (FlagDescriptions[F].UIntFlag) - *FlagDescriptions[F].UIntFlag = - static_cast(FlagDescriptions[F].Default); - if (FlagDescriptions[F].StrFlag) - *FlagDescriptions[F].StrFlag = nullptr; - } - Inputs = new std::vector; - for (size_t A = 1; A < Args.size(); A++) { - if (ParseOneFlag(Args[A].c_str())) { - if (Flags.ignore_remaining_args) - break; - continue; - } - Inputs->push_back(Args[A]); - } -} - -static std::mutex Mu; - -static void PulseThread() { - while (true) { - SleepSeconds(600); - std::lock_guard Lock(Mu); - Printf("pulse...\n"); - } -} - -static void WorkerThread(const std::string &Cmd, std::atomic *Counter, - unsigned NumJobs, std::atomic *HasErrors) { - while (true) { - unsigned C = (*Counter)++; - if (C >= NumJobs) break; - std::string Log = "fuzz-" + std::to_string(C) + ".log"; - std::string ToRun = Cmd + " > " + Log + " 2>&1\n"; - if (Flags.verbosity) - Printf("%s", ToRun.c_str()); - int ExitCode = ExecuteCommand(ToRun); - if (ExitCode != 0) - *HasErrors = true; - std::lock_guard Lock(Mu); - Printf("================== Job %u exited with exit code %d ============\n", - C, ExitCode); - fuzzer::CopyFileToErr(Log); - } -} - -std::string CloneArgsWithoutX(const std::vector &Args, - const char *X1, const char *X2) { - std::string Cmd; - for (auto &S : Args) { - if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2)) - continue; - Cmd += S + " "; - } - return Cmd; -} - -static int RunInMultipleProcesses(const std::vector &Args, - unsigned NumWorkers, unsigned NumJobs) { - std::atomic Counter(0); - std::atomic HasErrors(false); - std::string Cmd = CloneArgsWithoutX(Args, "jobs", "workers"); - std::vector V; - std::thread Pulse(PulseThread); - Pulse.detach(); - for (unsigned i = 0; i < NumWorkers; i++) - V.push_back(std::thread(WorkerThread, Cmd, &Counter, NumJobs, &HasErrors)); - for (auto &T : V) - T.join(); - return HasErrors ? 1 : 0; -} - -static void RssThread(Fuzzer *F, size_t RssLimitMb) { - while (true) { - SleepSeconds(1); - size_t Peak = GetPeakRSSMb(); - if (Peak > RssLimitMb) - F->RssLimitCallback(); - } -} - -static void StartRssThread(Fuzzer *F, size_t RssLimitMb) { - if (!RssLimitMb) return; - std::thread T(RssThread, F, RssLimitMb); - T.detach(); -} - -int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) { - Unit U = FileToVector(InputFilePath); - if (MaxLen && MaxLen < U.size()) - U.resize(MaxLen); - F->ExecuteCallback(U.data(), U.size()); - F->TryDetectingAMemoryLeak(U.data(), U.size(), true); - return 0; -} - -static bool AllInputsAreFiles() { - if (Inputs->empty()) return false; - for (auto &Path : *Inputs) - if (!IsFile(Path)) - return false; - return true; -} - -static std::string GetDedupTokenFromFile(const std::string &Path) { - auto S = FileToString(Path); - auto Beg = S.find("DEDUP_TOKEN:"); - if (Beg == std::string::npos) - return ""; - auto End = S.find('\n', Beg); - if (End == std::string::npos) - return ""; - return S.substr(Beg, End - Beg); -} - -int CleanseCrashInput(const std::vector &Args, - const FuzzingOptions &Options) { - if (Inputs->size() != 1 || !Flags.exact_artifact_path) { - Printf("ERROR: -cleanse_crash should be given one input file and" - " -exact_artifact_path\n"); - exit(1); - } - std::string InputFilePath = Inputs->at(0); - std::string OutputFilePath = Flags.exact_artifact_path; - std::string BaseCmd = - CloneArgsWithoutX(Args, "cleanse_crash", "cleanse_crash"); - - auto InputPos = BaseCmd.find(" " + InputFilePath + " "); - assert(InputPos != std::string::npos); - BaseCmd.erase(InputPos, InputFilePath.size() + 1); - - auto LogFilePath = DirPlusFile( - TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt"); - auto TmpFilePath = DirPlusFile( - TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".repro"); - auto LogFileRedirect = " > " + LogFilePath + " 2>&1 "; - - auto Cmd = BaseCmd + " " + TmpFilePath + LogFileRedirect; - - std::string CurrentFilePath = InputFilePath; - auto U = FileToVector(CurrentFilePath); - size_t Size = U.size(); - - const std::vector ReplacementBytes = {' ', 0xff}; - for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) { - bool Changed = false; - for (size_t Idx = 0; Idx < Size; Idx++) { - Printf("CLEANSE[%d]: Trying to replace byte %zd of %zd\n", NumAttempts, - Idx, Size); - uint8_t OriginalByte = U[Idx]; - if (ReplacementBytes.end() != std::find(ReplacementBytes.begin(), - ReplacementBytes.end(), - OriginalByte)) - continue; - for (auto NewByte : ReplacementBytes) { - U[Idx] = NewByte; - WriteToFile(U, TmpFilePath); - auto ExitCode = ExecuteCommand(Cmd); - RemoveFile(TmpFilePath); - if (!ExitCode) { - U[Idx] = OriginalByte; - } else { - Changed = true; - Printf("CLEANSE: Replaced byte %zd with 0x%x\n", Idx, NewByte); - WriteToFile(U, OutputFilePath); - break; - } - } - } - if (!Changed) break; - } - RemoveFile(LogFilePath); - return 0; -} - -int MinimizeCrashInput(const std::vector &Args, - const FuzzingOptions &Options) { - if (Inputs->size() != 1) { - Printf("ERROR: -minimize_crash should be given one input file\n"); - exit(1); - } - std::string InputFilePath = Inputs->at(0); - auto BaseCmd = SplitBefore( - "-ignore_remaining_args=1", - CloneArgsWithoutX(Args, "minimize_crash", "exact_artifact_path")); - auto InputPos = BaseCmd.first.find(" " + InputFilePath + " "); - assert(InputPos != std::string::npos); - BaseCmd.first.erase(InputPos, InputFilePath.size() + 1); - if (Flags.runs <= 0 && Flags.max_total_time == 0) { - Printf("INFO: you need to specify -runs=N or " - "-max_total_time=N with -minimize_crash=1\n" - "INFO: defaulting to -max_total_time=600\n"); - BaseCmd.first += " -max_total_time=600"; - } - - auto LogFilePath = DirPlusFile( - TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt"); - auto LogFileRedirect = " > " + LogFilePath + " 2>&1 "; - - std::string CurrentFilePath = InputFilePath; - while (true) { - Unit U = FileToVector(CurrentFilePath); - Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n", - CurrentFilePath.c_str(), U.size()); - - auto Cmd = BaseCmd.first + " " + CurrentFilePath + LogFileRedirect + " " + - BaseCmd.second; - - Printf("CRASH_MIN: executing: %s\n", Cmd.c_str()); - int ExitCode = ExecuteCommand(Cmd); - if (ExitCode == 0) { - Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str()); - exit(1); - } - Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize " - "it further\n", - CurrentFilePath.c_str(), U.size()); - auto DedupToken1 = GetDedupTokenFromFile(LogFilePath); - if (!DedupToken1.empty()) - Printf("CRASH_MIN: DedupToken1: %s\n", DedupToken1.c_str()); - - std::string ArtifactPath = - Flags.exact_artifact_path - ? Flags.exact_artifact_path - : Options.ArtifactPrefix + "minimized-from-" + Hash(U); - Cmd += " -minimize_crash_internal_step=1 -exact_artifact_path=" + - ArtifactPath; - Printf("CRASH_MIN: executing: %s\n", Cmd.c_str()); - ExitCode = ExecuteCommand(Cmd); - CopyFileToErr(LogFilePath); - if (ExitCode == 0) { - if (Flags.exact_artifact_path) { - CurrentFilePath = Flags.exact_artifact_path; - WriteToFile(U, CurrentFilePath); - } - Printf("CRASH_MIN: failed to minimize beyond %s (%d bytes), exiting\n", - CurrentFilePath.c_str(), U.size()); - break; - } - auto DedupToken2 = GetDedupTokenFromFile(LogFilePath); - if (!DedupToken2.empty()) - Printf("CRASH_MIN: DedupToken2: %s\n", DedupToken2.c_str()); - - if (DedupToken1 != DedupToken2) { - if (Flags.exact_artifact_path) { - CurrentFilePath = Flags.exact_artifact_path; - WriteToFile(U, CurrentFilePath); - } - Printf("CRASH_MIN: mismatch in dedup tokens" - " (looks like a different bug). Won't minimize further\n"); - break; - } - - CurrentFilePath = ArtifactPath; - Printf("*********************************\n"); - } - RemoveFile(LogFilePath); - return 0; -} - -int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) { - assert(Inputs->size() == 1); - std::string InputFilePath = Inputs->at(0); - Unit U = FileToVector(InputFilePath); - Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size()); - if (U.size() < 2) { - Printf("INFO: The input is small enough, exiting\n"); - exit(0); - } - F->SetMaxInputLen(U.size()); - F->SetMaxMutationLen(U.size() - 1); - F->MinimizeCrashLoop(U); - Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n"); - exit(0); - return 0; -} - -int AnalyzeDictionary(Fuzzer *F, const std::vector& Dict, - UnitVector& Corpus) { - Printf("Started dictionary minimization (up to %d tests)\n", - Dict.size() * Corpus.size() * 2); - - // Scores and usage count for each dictionary unit. - std::vector Scores(Dict.size()); - std::vector Usages(Dict.size()); - - std::vector InitialFeatures; - std::vector ModifiedFeatures; - for (auto &C : Corpus) { - // Get coverage for the testcase without modifications. - F->ExecuteCallback(C.data(), C.size()); - InitialFeatures.clear(); - TPC.CollectFeatures([&](size_t Feature) -> bool { - InitialFeatures.push_back(Feature); - return true; - }); - - for (size_t i = 0; i < Dict.size(); ++i) { - auto Data = C; - auto StartPos = std::search(Data.begin(), Data.end(), - Dict[i].begin(), Dict[i].end()); - // Skip dictionary unit, if the testcase does not contain it. - if (StartPos == Data.end()) - continue; - - ++Usages[i]; - while (StartPos != Data.end()) { - // Replace all occurrences of dictionary unit in the testcase. - auto EndPos = StartPos + Dict[i].size(); - for (auto It = StartPos; It != EndPos; ++It) - *It ^= 0xFF; - - StartPos = std::search(EndPos, Data.end(), - Dict[i].begin(), Dict[i].end()); - } - - // Get coverage for testcase with masked occurrences of dictionary unit. - F->ExecuteCallback(Data.data(), Data.size()); - ModifiedFeatures.clear(); - TPC.CollectFeatures([&](size_t Feature) -> bool { - ModifiedFeatures.push_back(Feature); - return true; - }); - - if (InitialFeatures == ModifiedFeatures) - --Scores[i]; - else - Scores[i] += 2; - } - } - - Printf("###### Useless dictionary elements. ######\n"); - for (size_t i = 0; i < Dict.size(); ++i) { - // Dictionary units with positive score are treated as useful ones. - if (Scores[i] > 0) - continue; - - Printf("\""); - PrintASCII(Dict[i].data(), Dict[i].size(), "\""); - Printf(" # Score: %d, Used: %d\n", Scores[i], Usages[i]); - } - Printf("###### End of useless dictionary elements. ######\n"); - return 0; -} - -int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { - using namespace fuzzer; - assert(argc && argv && "Argument pointers cannot be nullptr"); - std::string Argv0((*argv)[0]); - EF = new ExternalFunctions(); - if (EF->LLVMFuzzerInitialize) - EF->LLVMFuzzerInitialize(argc, argv); - const std::vector Args(*argv, *argv + *argc); - assert(!Args.empty()); - ProgName = new std::string(Args[0]); - if (Argv0 != *ProgName) { - Printf("ERROR: argv[0] has been modified in LLVMFuzzerInitialize\n"); - exit(1); - } - ParseFlags(Args); - if (Flags.help) { - PrintHelp(); - return 0; - } - - if (Flags.close_fd_mask & 2) - DupAndCloseStderr(); - if (Flags.close_fd_mask & 1) - CloseStdout(); - - if (Flags.jobs > 0 && Flags.workers == 0) { - Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs); - if (Flags.workers > 1) - Printf("Running %u workers\n", Flags.workers); - } - - if (Flags.workers > 0 && Flags.jobs > 0) - return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs); - - const size_t kMaxSaneLen = 1 << 20; - const size_t kMinDefaultLen = 4096; - FuzzingOptions Options; - Options.Verbosity = Flags.verbosity; - Options.MaxLen = Flags.max_len; - Options.ExperimentalLenControl = Flags.experimental_len_control; - Options.UnitTimeoutSec = Flags.timeout; - Options.ErrorExitCode = Flags.error_exitcode; - Options.TimeoutExitCode = Flags.timeout_exitcode; - Options.MaxTotalTimeSec = Flags.max_total_time; - Options.DoCrossOver = Flags.cross_over; - Options.MutateDepth = Flags.mutate_depth; - Options.UseCounters = Flags.use_counters; - Options.UseIndirCalls = Flags.use_indir_calls; - Options.UseMemmem = Flags.use_memmem; - Options.UseCmp = Flags.use_cmp; - Options.UseValueProfile = Flags.use_value_profile; - Options.Shrink = Flags.shrink; - Options.ReduceInputs = Flags.reduce_inputs; - Options.ShuffleAtStartUp = Flags.shuffle; - Options.PreferSmall = Flags.prefer_small; - Options.ReloadIntervalSec = Flags.reload; - Options.OnlyASCII = Flags.only_ascii; - Options.DetectLeaks = Flags.detect_leaks; - Options.TraceMalloc = Flags.trace_malloc; - Options.RssLimitMb = Flags.rss_limit_mb; - if (Flags.runs >= 0) - Options.MaxNumberOfRuns = Flags.runs; - if (!Inputs->empty() && !Flags.minimize_crash_internal_step) - Options.OutputCorpus = (*Inputs)[0]; - Options.ReportSlowUnits = Flags.report_slow_units; - if (Flags.artifact_prefix) - Options.ArtifactPrefix = Flags.artifact_prefix; - if (Flags.exact_artifact_path) - Options.ExactArtifactPath = Flags.exact_artifact_path; - std::vector Dictionary; - if (Flags.dict) - if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary)) - return 1; - if (Flags.verbosity > 0 && !Dictionary.empty()) - Printf("Dictionary: %zd entries\n", Dictionary.size()); - bool DoPlainRun = AllInputsAreFiles(); - Options.SaveArtifacts = - !DoPlainRun || Flags.minimize_crash_internal_step; - Options.PrintNewCovPcs = Flags.print_pcs; - Options.PrintFinalStats = Flags.print_final_stats; - Options.PrintCorpusStats = Flags.print_corpus_stats; - Options.PrintCoverage = Flags.print_coverage; - Options.DumpCoverage = Flags.dump_coverage; - if (Flags.exit_on_src_pos) - Options.ExitOnSrcPos = Flags.exit_on_src_pos; - if (Flags.exit_on_item) - Options.ExitOnItem = Flags.exit_on_item; - - unsigned Seed = Flags.seed; - // Initialize Seed. - if (Seed == 0) - Seed = - std::chrono::system_clock::now().time_since_epoch().count() + GetPid(); - if (Flags.verbosity) - Printf("INFO: Seed: %u\n", Seed); - - Random Rand(Seed); - auto *MD = new MutationDispatcher(Rand, Options); - auto *Corpus = new InputCorpus(Options.OutputCorpus); - auto *F = new Fuzzer(Callback, *Corpus, *MD, Options); - - for (auto &U: Dictionary) - if (U.size() <= Word::GetMaxSize()) - MD->AddWordToManualDictionary(Word(U.data(), U.size())); - - StartRssThread(F, Flags.rss_limit_mb); - - Options.HandleAbrt = Flags.handle_abrt; - Options.HandleBus = Flags.handle_bus; - Options.HandleFpe = Flags.handle_fpe; - Options.HandleIll = Flags.handle_ill; - Options.HandleInt = Flags.handle_int; - Options.HandleSegv = Flags.handle_segv; - Options.HandleTerm = Flags.handle_term; - Options.HandleXfsz = Flags.handle_xfsz; - SetSignalHandler(Options); - - std::atexit(Fuzzer::StaticExitCallback); - - if (Flags.minimize_crash) - return MinimizeCrashInput(Args, Options); - - if (Flags.minimize_crash_internal_step) - return MinimizeCrashInputInternalStep(F, Corpus); - - if (Flags.cleanse_crash) - return CleanseCrashInput(Args, Options); - - if (auto Name = Flags.run_equivalence_server) { - SMR.Destroy(Name); - if (!SMR.Create(Name)) { - Printf("ERROR: can't create shared memory region\n"); - return 1; - } - Printf("INFO: EQUIVALENCE SERVER UP\n"); - while (true) { - SMR.WaitClient(); - size_t Size = SMR.ReadByteArraySize(); - SMR.WriteByteArray(nullptr, 0); - const Unit tmp(SMR.GetByteArray(), SMR.GetByteArray() + Size); - F->ExecuteCallback(tmp.data(), tmp.size()); - SMR.PostServer(); - } - return 0; - } - - if (auto Name = Flags.use_equivalence_server) { - if (!SMR.Open(Name)) { - Printf("ERROR: can't open shared memory region\n"); - return 1; - } - Printf("INFO: EQUIVALENCE CLIENT UP\n"); - } - - if (DoPlainRun) { - Options.SaveArtifacts = false; - int Runs = std::max(1, Flags.runs); - Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName->c_str(), - Inputs->size(), Runs); - for (auto &Path : *Inputs) { - auto StartTime = system_clock::now(); - Printf("Running: %s\n", Path.c_str()); - for (int Iter = 0; Iter < Runs; Iter++) - RunOneTest(F, Path.c_str(), Options.MaxLen); - auto StopTime = system_clock::now(); - auto MS = duration_cast(StopTime - StartTime).count(); - Printf("Executed %s in %zd ms\n", Path.c_str(), (long)MS); - } - Printf("***\n" - "*** NOTE: fuzzing was not performed, you have only\n" - "*** executed the target code on a fixed set of inputs.\n" - "***\n"); - F->PrintFinalStats(); - exit(0); - } - - if (Flags.merge) { - if (Options.MaxLen == 0) - F->SetMaxInputLen(kMaxSaneLen); - if (Flags.merge_control_file) - F->CrashResistantMergeInternalStep(Flags.merge_control_file); - else - F->CrashResistantMerge(Args, *Inputs, - Flags.load_coverage_summary, - Flags.save_coverage_summary); - exit(0); - } - - size_t TemporaryMaxLen = Options.MaxLen ? Options.MaxLen : kMaxSaneLen; - - UnitVector InitialCorpus; - for (auto &Inp : *Inputs) { - Printf("Loading corpus dir: %s\n", Inp.c_str()); - ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr, - TemporaryMaxLen, /*ExitOnError=*/false); - } - - if (Flags.analyze_dict) { - if (Dictionary.empty() || Inputs->empty()) { - Printf("ERROR: can't analyze dict without dict and corpus provided\n"); - return 1; - } - if (AnalyzeDictionary(F, Dictionary, InitialCorpus)) { - Printf("Dictionary analysis failed\n"); - exit(1); - } - Printf("Dictionary analysis suceeded\n"); - exit(0); - } - - if (Options.MaxLen == 0) { - size_t MaxLen = 0; - for (auto &U : InitialCorpus) - MaxLen = std::max(U.size(), MaxLen); - F->SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxLen), kMaxSaneLen)); - } - - if (InitialCorpus.empty()) { - InitialCorpus.push_back(Unit({'\n'})); // Valid ASCII input. - if (Options.Verbosity) - Printf("INFO: A corpus is not provided, starting from an empty corpus\n"); - } - F->ShuffleAndMinimize(&InitialCorpus); - InitialCorpus.clear(); // Don't need this memory any more. - F->Loop(); - - if (Flags.verbosity) - Printf("Done %zd runs in %zd second(s)\n", F->getTotalNumberOfRuns(), - F->secondsSinceProcessStartUp()); - F->PrintFinalStats(); - - exit(0); // Don't let F destroy itself. -} - -// Storage for global ExternalFunctions object. -ExternalFunctions *EF = nullptr; - -} // namespace fuzzer Index: lib/fuzzer/FuzzerExtFunctions.h =================================================================== --- lib/fuzzer/FuzzerExtFunctions.h +++ /dev/null @@ -1,35 +0,0 @@ -//===- FuzzerExtFunctions.h - Interface to external functions ---*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Defines an interface to (possibly optional) functions. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_EXT_FUNCTIONS_H -#define LLVM_FUZZER_EXT_FUNCTIONS_H - -#include -#include - -namespace fuzzer { - -struct ExternalFunctions { - // Initialize function pointers. Functions that are not available will be set - // to nullptr. Do not call this constructor before ``main()`` has been - // entered. - ExternalFunctions(); - -#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ - RETURN_TYPE(*NAME) FUNC_SIG = nullptr - -#include "FuzzerExtFunctions.def" - -#undef EXT_FUNC -}; -} // namespace fuzzer - -#endif Index: lib/fuzzer/FuzzerExtFunctions.def =================================================================== --- lib/fuzzer/FuzzerExtFunctions.def +++ /dev/null @@ -1,46 +0,0 @@ -//===- FuzzerExtFunctions.def - External functions --------------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// This defines the external function pointers that -// ``fuzzer::ExternalFunctions`` should contain and try to initialize. The -// EXT_FUNC macro must be defined at the point of inclusion. The signature of -// the macro is: -// -// EXT_FUNC(, , , ) -//===----------------------------------------------------------------------===// - -// Optional user functions -EXT_FUNC(LLVMFuzzerInitialize, int, (int *argc, char ***argv), false); -EXT_FUNC(LLVMFuzzerCustomMutator, size_t, - (uint8_t * Data, size_t Size, size_t MaxSize, unsigned int Seed), - false); -EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t, - (const uint8_t * Data1, size_t Size1, - const uint8_t * Data2, size_t Size2, - uint8_t * Out, size_t MaxOutSize, unsigned int Seed), - false); - -// Sanitizer functions -EXT_FUNC(__lsan_enable, void, (), false); -EXT_FUNC(__lsan_disable, void, (), false); -EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false); -EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int, - (void (*malloc_hook)(const volatile void *, size_t), - void (*free_hook)(const volatile void *)), - false); -EXT_FUNC(__sanitizer_print_memory_profile, int, (size_t, size_t), false); -EXT_FUNC(__sanitizer_print_stack_trace, void, (), true); -EXT_FUNC(__sanitizer_symbolize_pc, void, - (void *, const char *fmt, char *out_buf, size_t out_buf_size), false); -EXT_FUNC(__sanitizer_get_module_and_offset_for_pc, int, - (void *pc, char *module_path, - size_t module_path_len,void **pc_offset), false); -EXT_FUNC(__sanitizer_set_death_callback, void, (void (*)(void)), true); -EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false); -EXT_FUNC(__sanitizer_dump_coverage, void, (const uintptr_t *, uintptr_t), - false); Index: lib/fuzzer/FuzzerExtFunctionsDlsym.cpp =================================================================== --- lib/fuzzer/FuzzerExtFunctionsDlsym.cpp +++ /dev/null @@ -1,52 +0,0 @@ -//===- FuzzerExtFunctionsDlsym.cpp - Interface to external functions ------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Implementation for operating systems that support dlsym(). We only use it on -// Apple platforms for now. We don't use this approach on Linux because it -// requires that clients of LibFuzzer pass ``--export-dynamic`` to the linker. -// That is a complication we don't wish to expose to clients right now. -//===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" -#if LIBFUZZER_APPLE - -#include "FuzzerExtFunctions.h" -#include "FuzzerIO.h" -#include - -using namespace fuzzer; - -template -static T GetFnPtr(const char *FnName, bool WarnIfMissing) { - dlerror(); // Clear any previous errors. - void *Fn = dlsym(RTLD_DEFAULT, FnName); - if (Fn == nullptr) { - if (WarnIfMissing) { - const char *ErrorMsg = dlerror(); - Printf("WARNING: Failed to find function \"%s\".", FnName); - if (ErrorMsg) - Printf(" Reason %s.", ErrorMsg); - Printf("\n"); - } - } - return reinterpret_cast(Fn); -} - -namespace fuzzer { - -ExternalFunctions::ExternalFunctions() { -#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ - this->NAME = GetFnPtr(#NAME, WARN) - -#include "FuzzerExtFunctions.def" - -#undef EXT_FUNC -} - -} // namespace fuzzer - -#endif // LIBFUZZER_APPLE Index: lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp =================================================================== --- lib/fuzzer/FuzzerExtFunctionsDlsymWin.cpp +++ /dev/null @@ -1,62 +0,0 @@ -//===- FuzzerExtFunctionsDlsymWin.cpp - Interface to external functions ---===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Implementation using dynamic loading for Windows. -//===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" -#if LIBFUZZER_WINDOWS - -#include "FuzzerExtFunctions.h" -#include "FuzzerIO.h" -#include "Windows.h" - -// This must be included after Windows.h. -#include "Psapi.h" - -namespace fuzzer { - -ExternalFunctions::ExternalFunctions() { - HMODULE Modules[1024]; - DWORD BytesNeeded; - HANDLE CurrentProcess = GetCurrentProcess(); - - if (!EnumProcessModules(CurrentProcess, Modules, sizeof(Modules), - &BytesNeeded)) { - Printf("EnumProcessModules failed (error: %d).\n", GetLastError()); - exit(1); - } - - if (sizeof(Modules) < BytesNeeded) { - Printf("Error: the array is not big enough to hold all loaded modules.\n"); - exit(1); - } - - for (size_t i = 0; i < (BytesNeeded / sizeof(HMODULE)); i++) - { - FARPROC Fn; -#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ - if (this->NAME == nullptr) { \ - Fn = GetProcAddress(Modules[i], #NAME); \ - if (Fn == nullptr) \ - Fn = GetProcAddress(Modules[i], #NAME "__dll"); \ - this->NAME = (decltype(ExternalFunctions::NAME)) Fn; \ - } -#include "FuzzerExtFunctions.def" -#undef EXT_FUNC - } - -#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ - if (this->NAME == nullptr && WARN) \ - Printf("WARNING: Failed to find function \"%s\".\n", #NAME); -#include "FuzzerExtFunctions.def" -#undef EXT_FUNC -} - -} // namespace fuzzer - -#endif // LIBFUZZER_WINDOWS Index: lib/fuzzer/FuzzerExtFunctionsWeak.cpp =================================================================== --- lib/fuzzer/FuzzerExtFunctionsWeak.cpp +++ /dev/null @@ -1,54 +0,0 @@ -//===- FuzzerExtFunctionsWeak.cpp - Interface to external functions -------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Implementation for Linux. This relies on the linker's support for weak -// symbols. We don't use this approach on Apple platforms because it requires -// clients of LibFuzzer to pass ``-U _`` to the linker to allow -// weak symbols to be undefined. That is a complication we don't want to expose -// to clients right now. -//===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" -#if LIBFUZZER_LINUX - -#include "FuzzerExtFunctions.h" -#include "FuzzerIO.h" - -extern "C" { -// Declare these symbols as weak to allow them to be optionally defined. -#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ - __attribute__((weak)) RETURN_TYPE NAME FUNC_SIG - -#include "FuzzerExtFunctions.def" - -#undef EXT_FUNC -} - -using namespace fuzzer; - -static void CheckFnPtr(void *FnPtr, const char *FnName, bool WarnIfMissing) { - if (FnPtr == nullptr && WarnIfMissing) { - Printf("WARNING: Failed to find function \"%s\".\n", FnName); - } -} - -namespace fuzzer { - -ExternalFunctions::ExternalFunctions() { -#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ - this->NAME = ::NAME; \ - CheckFnPtr(reinterpret_cast(reinterpret_cast(::NAME)), \ - #NAME, WARN); - -#include "FuzzerExtFunctions.def" - -#undef EXT_FUNC -} - -} // namespace fuzzer - -#endif // LIBFUZZER_LINUX Index: lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp =================================================================== --- lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//===- FuzzerExtFunctionsWeakAlias.cpp - Interface to external functions --===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Implementation using weak aliases. Works for Windows. -//===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" -#if LIBFUZZER_WINDOWS - -#include "FuzzerExtFunctions.h" -#include "FuzzerIO.h" - -using namespace fuzzer; - -extern "C" { -// Declare these symbols as weak to allow them to be optionally defined. -#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ - RETURN_TYPE NAME##Def FUNC_SIG { \ - Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \ - exit(1); \ - } \ - RETURN_TYPE NAME FUNC_SIG __attribute__((weak, alias(#NAME "Def"))); - -#include "FuzzerExtFunctions.def" - -#undef EXT_FUNC -} - -template -static T *GetFnPtr(T *Fun, T *FunDef, const char *FnName, bool WarnIfMissing) { - if (Fun == FunDef) { - if (WarnIfMissing) - Printf("WARNING: Failed to find function \"%s\".\n", FnName); - return nullptr; - } - return Fun; -} - -namespace fuzzer { - -ExternalFunctions::ExternalFunctions() { -#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ - this->NAME = GetFnPtr(::NAME, ::NAME##Def, #NAME, WARN); - -#include "FuzzerExtFunctions.def" - -#undef EXT_FUNC -} - -} // namespace fuzzer - -#endif // LIBFUZZER_WINDOWS Index: lib/fuzzer/FuzzerExtraCounters.cpp =================================================================== --- lib/fuzzer/FuzzerExtraCounters.cpp +++ /dev/null @@ -1,41 +0,0 @@ -//===- FuzzerExtraCounters.cpp - Extra coverage counters ------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Extra coverage counters defined by user code. -//===----------------------------------------------------------------------===// - -#include "FuzzerDefs.h" - -#if LIBFUZZER_LINUX -__attribute__((weak)) extern uint8_t __start___libfuzzer_extra_counters; -__attribute__((weak)) extern uint8_t __stop___libfuzzer_extra_counters; - -namespace fuzzer { -uint8_t *ExtraCountersBegin() { return &__start___libfuzzer_extra_counters; } -uint8_t *ExtraCountersEnd() { return &__stop___libfuzzer_extra_counters; } -ATTRIBUTE_NO_SANITIZE_ALL -void ClearExtraCounters() { // hand-written memset, don't asan-ify. - uintptr_t *Beg = reinterpret_cast(ExtraCountersBegin()); - uintptr_t *End = reinterpret_cast(ExtraCountersEnd()); - for (; Beg < End; Beg++) { - *Beg = 0; - __asm__ __volatile__("" : : : "memory"); - } -} - -} // namespace fuzzer - -#else -// TODO: implement for other platforms. -namespace fuzzer { -uint8_t *ExtraCountersBegin() { return nullptr; } -uint8_t *ExtraCountersEnd() { return nullptr; } -void ClearExtraCounters() {} -} // namespace fuzzer - -#endif Index: lib/fuzzer/FuzzerFlags.def =================================================================== --- lib/fuzzer/FuzzerFlags.def +++ /dev/null @@ -1,139 +0,0 @@ -//===- FuzzerFlags.def - Run-time flags -------------------------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Flags. FUZZER_FLAG_INT/FUZZER_FLAG_STRING macros should be defined at the -// point of inclusion. We are not using any flag parsing library for better -// portability and independence. -//===----------------------------------------------------------------------===// -FUZZER_FLAG_INT(verbosity, 1, "Verbosity level.") -FUZZER_FLAG_UNSIGNED(seed, 0, "Random seed. If 0, seed is generated.") -FUZZER_FLAG_INT(runs, -1, - "Number of individual test runs (-1 for infinite runs).") -FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. " - "If 0, libFuzzer tries to guess a good value based on the corpus " - "and reports it. ") -FUZZER_FLAG_INT(experimental_len_control, 0, "experimental flag") -FUZZER_FLAG_INT(cross_over, 1, "If 1, cross over inputs.") -FUZZER_FLAG_INT(mutate_depth, 5, - "Apply this number of consecutive mutations to each input.") -FUZZER_FLAG_INT(shuffle, 1, "Shuffle inputs at startup") -FUZZER_FLAG_INT(prefer_small, 1, - "If 1, always prefer smaller inputs during the corpus shuffle.") -FUZZER_FLAG_INT( - timeout, 1200, - "Timeout in seconds (if positive). " - "If one unit runs more than this number of seconds the process will abort.") -FUZZER_FLAG_INT(error_exitcode, 77, "When libFuzzer itself reports a bug " - "this exit code will be used.") -FUZZER_FLAG_INT(timeout_exitcode, 77, "When libFuzzer reports a timeout " - "this exit code will be used.") -FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total " - "time in seconds to run the fuzzer.") -FUZZER_FLAG_INT(help, 0, "Print help.") -FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be " - "merged into the 1-st corpus. Only interesting units will be taken. " - "This flag can be used to minimize a corpus.") -FUZZER_FLAG_STRING(merge_control_file, "internal flag") -FUZZER_FLAG_STRING(save_coverage_summary, "Experimental:" - " save coverage summary to a given file." - " Used with -merge=1") -FUZZER_FLAG_STRING(load_coverage_summary, "Experimental:" - " load coverage summary from a given file." - " Treat this coverage as belonging to the first corpus. " - " Used with -merge=1") -FUZZER_FLAG_INT(minimize_crash, 0, "If 1, minimizes the provided" - " crash input. Use with -runs=N or -max_total_time=N to limit " - "the number attempts." - " Use with -exact_artifact_path to specify the output." - " Combine with ASAN_OPTIONS=dedup_token_length=3 (or similar) to ensure that" - " the minimized input triggers the same crash." - ) -FUZZER_FLAG_INT(cleanse_crash, 0, "If 1, tries to cleanse the provided" - " crash input to make it contain fewer original bytes." - " Use with -exact_artifact_path to specify the output." - ) -FUZZER_FLAG_INT(minimize_crash_internal_step, 0, "internal flag") -FUZZER_FLAG_INT(use_counters, 1, "Use coverage counters") -FUZZER_FLAG_INT(use_indir_calls, 1, "Use indirect caller-callee counters") -FUZZER_FLAG_INT(use_memmem, 1, - "Use hints from intercepting memmem, strstr, etc") -FUZZER_FLAG_INT(use_value_profile, 0, - "Experimental. Use value profile to guide fuzzing.") -FUZZER_FLAG_INT(use_cmp, 1, "Use CMP traces to guide mutations") -FUZZER_FLAG_INT(shrink, 0, "Experimental. Try to shrink corpus inputs.") -FUZZER_FLAG_INT(reduce_inputs, 1, - "Try to reduce the size of inputs while preserving their full feature sets") -FUZZER_FLAG_UNSIGNED(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.") -FUZZER_FLAG_UNSIGNED(workers, 0, - "Number of simultaneous worker processes to run the jobs." - " If zero, \"min(jobs,NumberOfCpuCores()/2)\" is used.") -FUZZER_FLAG_INT(reload, 1, - "Reload the main corpus every seconds to get new units" - " discovered by other processes. If 0, disabled") -FUZZER_FLAG_INT(report_slow_units, 10, - "Report slowest units if they run for more than this number of seconds.") -FUZZER_FLAG_INT(only_ascii, 0, - "If 1, generate only ASCII (isprint+isspace) inputs.") -FUZZER_FLAG_STRING(dict, "Experimental. Use the dictionary file.") -FUZZER_FLAG_STRING(artifact_prefix, "Write fuzzing artifacts (crash, " - "timeout, or slow inputs) as " - "$(artifact_prefix)file") -FUZZER_FLAG_STRING(exact_artifact_path, - "Write the single artifact on failure (crash, timeout) " - "as $(exact_artifact_path). This overrides -artifact_prefix " - "and will not use checksum in the file name. Do not " - "use the same path for several parallel processes.") -FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.") -FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.") -FUZZER_FLAG_INT(print_corpus_stats, 0, - "If 1, print statistics on corpus elements at exit.") -FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text" - " at exit.") -FUZZER_FLAG_INT(dump_coverage, 0, "If 1, dump coverage information as a" - " .sancov file at exit.") -FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.") -FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGBUS.") -FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.") -FUZZER_FLAG_INT(handle_ill, 1, "If 1, try to intercept SIGILL.") -FUZZER_FLAG_INT(handle_fpe, 1, "If 1, try to intercept SIGFPE.") -FUZZER_FLAG_INT(handle_int, 1, "If 1, try to intercept SIGINT.") -FUZZER_FLAG_INT(handle_term, 1, "If 1, try to intercept SIGTERM.") -FUZZER_FLAG_INT(handle_xfsz, 1, "If 1, try to intercept SIGXFSZ.") -FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; " - "if 2, close stderr; if 3, close both. " - "Be careful, this will also close e.g. asan's stderr/stdout.") -FUZZER_FLAG_INT(detect_leaks, 1, "If 1, and if LeakSanitizer is enabled " - "try to detect memory leaks during fuzzing (i.e. not only at shut down).") -FUZZER_FLAG_INT(trace_malloc, 0, "If >= 1 will print all mallocs/frees. " - "If >= 2 will also print stack traces.") -FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon" - "reaching this limit of RSS memory usage.") -FUZZER_FLAG_STRING(exit_on_src_pos, "Exit if a newly found PC originates" - " from the given source location. Example: -exit_on_src_pos=foo.cc:123. " - "Used primarily for testing libFuzzer itself.") -FUZZER_FLAG_STRING(exit_on_item, "Exit if an item with a given sha1 sum" - " was added to the corpus. " - "Used primarily for testing libFuzzer itself.") -FUZZER_FLAG_INT(ignore_remaining_args, 0, "If 1, ignore all arguments passed " - "after this one. Useful for fuzzers that need to do their own " - "argument parsing.") - -FUZZER_FLAG_STRING(run_equivalence_server, "Experimental") -FUZZER_FLAG_STRING(use_equivalence_server, "Experimental") -FUZZER_FLAG_INT(analyze_dict, 0, "Experimental") - -FUZZER_DEPRECATED_FLAG(exit_on_first) -FUZZER_DEPRECATED_FLAG(save_minimized_corpus) -FUZZER_DEPRECATED_FLAG(sync_command) -FUZZER_DEPRECATED_FLAG(sync_timeout) -FUZZER_DEPRECATED_FLAG(test_single_input) -FUZZER_DEPRECATED_FLAG(drill) -FUZZER_DEPRECATED_FLAG(truncate_units) -FUZZER_DEPRECATED_FLAG(output_csv) Index: lib/fuzzer/FuzzerIO.h =================================================================== --- lib/fuzzer/FuzzerIO.h +++ /dev/null @@ -1,76 +0,0 @@ -//===- FuzzerIO.h - Internal header for IO utils ----------------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// IO interface. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_IO_H -#define LLVM_FUZZER_IO_H - -#include "FuzzerDefs.h" - -namespace fuzzer { - -long GetEpoch(const std::string &Path); - -Unit FileToVector(const std::string &Path, size_t MaxSize = 0, - bool ExitOnError = true); - -std::string FileToString(const std::string &Path); - -void CopyFileToErr(const std::string &Path); - -void WriteToFile(const Unit &U, const std::string &Path); - -void ReadDirToVectorOfUnits(const char *Path, std::vector *V, - long *Epoch, size_t MaxSize, bool ExitOnError); - -// Returns "Dir/FileName" or equivalent for the current OS. -std::string DirPlusFile(const std::string &DirPath, - const std::string &FileName); - -// Returns the name of the dir, similar to the 'dirname' utility. -std::string DirName(const std::string &FileName); - -// Returns path to a TmpDir. -std::string TmpDir(); - -bool IsInterestingCoverageFile(const std::string &FileName); - -void DupAndCloseStderr(); - -void CloseStdout(); - -void Printf(const char *Fmt, ...); - -// Print using raw syscalls, useful when printing at early init stages. -void RawPrint(const char *Str); - -// Platform specific functions: -bool IsFile(const std::string &Path); - -void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, - std::vector *V, bool TopDir); - -char GetSeparator(); - -FILE* OpenFile(int Fd, const char *Mode); - -int CloseFile(int Fd); - -int DuplicateFile(int Fd); - -void RemoveFile(const std::string &Path); - -void DiscardOutput(int Fd); - -intptr_t GetHandleFromFd(int fd); - -} // namespace fuzzer - -#endif // LLVM_FUZZER_IO_H Index: lib/fuzzer/FuzzerIO.cpp =================================================================== --- lib/fuzzer/FuzzerIO.cpp +++ /dev/null @@ -1,120 +0,0 @@ -//===- FuzzerIO.cpp - IO utils. -------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// IO functions. -//===----------------------------------------------------------------------===// - -#include "FuzzerIO.h" -#include "FuzzerDefs.h" -#include "FuzzerExtFunctions.h" -#include -#include -#include -#include -#include -#include - -namespace fuzzer { - -static FILE *OutputFile = stderr; - -long GetEpoch(const std::string &Path) { - struct stat St; - if (stat(Path.c_str(), &St)) - return 0; // Can't stat, be conservative. - return St.st_mtime; -} - -Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) { - std::ifstream T(Path); - if (ExitOnError && !T) { - Printf("No such directory: %s; exiting\n", Path.c_str()); - exit(1); - } - - T.seekg(0, T.end); - auto EndPos = T.tellg(); - if (EndPos < 0) return {}; - size_t FileLen = EndPos; - if (MaxSize) - FileLen = std::min(FileLen, MaxSize); - - T.seekg(0, T.beg); - Unit Res(FileLen); - T.read(reinterpret_cast(Res.data()), FileLen); - return Res; -} - -std::string FileToString(const std::string &Path) { - std::ifstream T(Path); - return std::string((std::istreambuf_iterator(T)), - std::istreambuf_iterator()); -} - -void CopyFileToErr(const std::string &Path) { - Printf("%s", FileToString(Path).c_str()); -} - -void WriteToFile(const Unit &U, const std::string &Path) { - // Use raw C interface because this function may be called from a sig handler. - FILE *Out = fopen(Path.c_str(), "w"); - if (!Out) return; - fwrite(U.data(), sizeof(U[0]), U.size(), Out); - fclose(Out); -} - -void ReadDirToVectorOfUnits(const char *Path, std::vector *V, - long *Epoch, size_t MaxSize, bool ExitOnError) { - long E = Epoch ? *Epoch : 0; - std::vector Files; - ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true); - size_t NumLoaded = 0; - for (size_t i = 0; i < Files.size(); i++) { - auto &X = Files[i]; - if (Epoch && GetEpoch(X) < E) continue; - NumLoaded++; - if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024) - Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path); - auto S = FileToVector(X, MaxSize, ExitOnError); - if (!S.empty()) - V->push_back(S); - } -} - -std::string DirPlusFile(const std::string &DirPath, - const std::string &FileName) { - return DirPath + GetSeparator() + FileName; -} - -void DupAndCloseStderr() { - int OutputFd = DuplicateFile(2); - if (OutputFd > 0) { - FILE *NewOutputFile = OpenFile(OutputFd, "w"); - if (NewOutputFile) { - OutputFile = NewOutputFile; - if (EF->__sanitizer_set_report_fd) - EF->__sanitizer_set_report_fd( - reinterpret_cast(GetHandleFromFd(OutputFd))); - DiscardOutput(2); - } - } -} - -void CloseStdout() { - DiscardOutput(1); -} - -void Printf(const char *Fmt, ...) { - va_list ap; - va_start(ap, Fmt); - vfprintf(OutputFile, Fmt, ap); - va_end(ap); - fflush(OutputFile); -} - -} // namespace fuzzer Index: lib/fuzzer/FuzzerIOPosix.cpp =================================================================== --- lib/fuzzer/FuzzerIOPosix.cpp +++ /dev/null @@ -1,123 +0,0 @@ -//===- FuzzerIOPosix.cpp - IO utils for Posix. ----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// IO functions implementation using Posix API. -//===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" -#if LIBFUZZER_POSIX - -#include "FuzzerExtFunctions.h" -#include "FuzzerIO.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace fuzzer { - -bool IsFile(const std::string &Path) { - struct stat St; - if (stat(Path.c_str(), &St)) - return false; - return S_ISREG(St.st_mode); -} - -void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, - std::vector *V, bool TopDir) { - auto E = GetEpoch(Dir); - if (Epoch) - if (E && *Epoch >= E) return; - - DIR *D = opendir(Dir.c_str()); - if (!D) { - Printf("No such directory: %s; exiting\n", Dir.c_str()); - exit(1); - } - while (auto E = readdir(D)) { - std::string Path = DirPlusFile(Dir, E->d_name); - if (E->d_type == DT_REG || E->d_type == DT_LNK) - V->push_back(Path); - else if (E->d_type == DT_DIR && *E->d_name != '.') - ListFilesInDirRecursive(Path, Epoch, V, false); - } - closedir(D); - if (Epoch && TopDir) - *Epoch = E; -} - -char GetSeparator() { - return '/'; -} - -FILE* OpenFile(int Fd, const char* Mode) { - return fdopen(Fd, Mode); -} - -int CloseFile(int fd) { - return close(fd); -} - -int DuplicateFile(int Fd) { - return dup(Fd); -} - -void RemoveFile(const std::string &Path) { - unlink(Path.c_str()); -} - -void DiscardOutput(int Fd) { - FILE* Temp = fopen("/dev/null", "w"); - if (!Temp) - return; - dup2(fileno(Temp), Fd); - fclose(Temp); -} - -intptr_t GetHandleFromFd(int fd) { - return static_cast(fd); -} - -std::string DirName(const std::string &FileName) { - char *Tmp = new char[FileName.size() + 1]; - memcpy(Tmp, FileName.c_str(), FileName.size() + 1); - std::string Res = dirname(Tmp); - delete [] Tmp; - return Res; -} - -std::string TmpDir() { - if (auto Env = getenv("TMPDIR")) - return Env; - return "/tmp"; -} - -bool IsInterestingCoverageFile(const std::string &FileName) { - if (FileName.find("compiler-rt/lib/") != std::string::npos) - return false; // sanitizer internal. - if (FileName.find("/usr/lib/") != std::string::npos) - return false; - if (FileName.find("/usr/include/") != std::string::npos) - return false; - if (FileName == "") - return false; - return true; -} - - -void RawPrint(const char *Str) { - write(2, Str, strlen(Str)); -} - -} // namespace fuzzer - -#endif // LIBFUZZER_POSIX Index: lib/fuzzer/FuzzerIOWindows.cpp =================================================================== --- lib/fuzzer/FuzzerIOWindows.cpp +++ /dev/null @@ -1,323 +0,0 @@ -//===- FuzzerIOWindows.cpp - IO utils for Windows. ------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// IO functions implementation for Windows. -//===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" -#if LIBFUZZER_WINDOWS - -#include "FuzzerExtFunctions.h" -#include "FuzzerIO.h" -#include -#include -#include -#include -#include -#include -#include -#include - -namespace fuzzer { - -static bool IsFile(const std::string &Path, const DWORD &FileAttributes) { - - if (FileAttributes & FILE_ATTRIBUTE_NORMAL) - return true; - - if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) - return false; - - HANDLE FileHandle( - CreateFileA(Path.c_str(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, 0)); - - if (FileHandle == INVALID_HANDLE_VALUE) { - Printf("CreateFileA() failed for \"%s\" (Error code: %lu).\n", Path.c_str(), - GetLastError()); - return false; - } - - DWORD FileType = GetFileType(FileHandle); - - if (FileType == FILE_TYPE_UNKNOWN) { - Printf("GetFileType() failed for \"%s\" (Error code: %lu).\n", Path.c_str(), - GetLastError()); - CloseHandle(FileHandle); - return false; - } - - if (FileType != FILE_TYPE_DISK) { - CloseHandle(FileHandle); - return false; - } - - CloseHandle(FileHandle); - return true; -} - -bool IsFile(const std::string &Path) { - DWORD Att = GetFileAttributesA(Path.c_str()); - - if (Att == INVALID_FILE_ATTRIBUTES) { - Printf("GetFileAttributesA() failed for \"%s\" (Error code: %lu).\n", - Path.c_str(), GetLastError()); - return false; - } - - return IsFile(Path, Att); -} - -void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, - std::vector *V, bool TopDir) { - auto E = GetEpoch(Dir); - if (Epoch) - if (E && *Epoch >= E) return; - - std::string Path(Dir); - assert(!Path.empty()); - if (Path.back() != '\\') - Path.push_back('\\'); - Path.push_back('*'); - - // Get the first directory entry. - WIN32_FIND_DATAA FindInfo; - HANDLE FindHandle(FindFirstFileA(Path.c_str(), &FindInfo)); - if (FindHandle == INVALID_HANDLE_VALUE) - { - if (GetLastError() == ERROR_FILE_NOT_FOUND) - return; - Printf("No such directory: %s; exiting\n", Dir.c_str()); - exit(1); - } - - do { - std::string FileName = DirPlusFile(Dir, FindInfo.cFileName); - - if (FindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - size_t FilenameLen = strlen(FindInfo.cFileName); - if ((FilenameLen == 1 && FindInfo.cFileName[0] == '.') || - (FilenameLen == 2 && FindInfo.cFileName[0] == '.' && - FindInfo.cFileName[1] == '.')) - continue; - - ListFilesInDirRecursive(FileName, Epoch, V, false); - } - else if (IsFile(FileName, FindInfo.dwFileAttributes)) - V->push_back(FileName); - } while (FindNextFileA(FindHandle, &FindInfo)); - - DWORD LastError = GetLastError(); - if (LastError != ERROR_NO_MORE_FILES) - Printf("FindNextFileA failed (Error code: %lu).\n", LastError); - - FindClose(FindHandle); - - if (Epoch && TopDir) - *Epoch = E; -} - -char GetSeparator() { - return '\\'; -} - -FILE* OpenFile(int Fd, const char* Mode) { - return _fdopen(Fd, Mode); -} - -int CloseFile(int Fd) { - return _close(Fd); -} - -int DuplicateFile(int Fd) { - return _dup(Fd); -} - -void RemoveFile(const std::string &Path) { - _unlink(Path.c_str()); -} - -void DiscardOutput(int Fd) { - FILE* Temp = fopen("nul", "w"); - if (!Temp) - return; - _dup2(_fileno(Temp), Fd); - fclose(Temp); -} - -intptr_t GetHandleFromFd(int fd) { - return _get_osfhandle(fd); -} - -static bool IsSeparator(char C) { - return C == '\\' || C == '/'; -} - -// Parse disk designators, like "C:\". If Relative == true, also accepts: "C:". -// Returns number of characters considered if successful. -static size_t ParseDrive(const std::string &FileName, const size_t Offset, - bool Relative = true) { - if (Offset + 1 >= FileName.size() || FileName[Offset + 1] != ':') - return 0; - if (Offset + 2 >= FileName.size() || !IsSeparator(FileName[Offset + 2])) { - if (!Relative) // Accept relative path? - return 0; - else - return 2; - } - return 3; -} - -// Parse a file name, like: SomeFile.txt -// Returns number of characters considered if successful. -static size_t ParseFileName(const std::string &FileName, const size_t Offset) { - size_t Pos = Offset; - const size_t End = FileName.size(); - for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos) - ; - return Pos - Offset; -} - -// Parse a directory ending in separator, like: `SomeDir\` -// Returns number of characters considered if successful. -static size_t ParseDir(const std::string &FileName, const size_t Offset) { - size_t Pos = Offset; - const size_t End = FileName.size(); - if (Pos >= End || IsSeparator(FileName[Pos])) - return 0; - for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos) - ; - if (Pos >= End) - return 0; - ++Pos; // Include separator. - return Pos - Offset; -} - -// Parse a servername and share, like: `SomeServer\SomeShare\` -// Returns number of characters considered if successful. -static size_t ParseServerAndShare(const std::string &FileName, - const size_t Offset) { - size_t Pos = Offset, Res; - if (!(Res = ParseDir(FileName, Pos))) - return 0; - Pos += Res; - if (!(Res = ParseDir(FileName, Pos))) - return 0; - Pos += Res; - return Pos - Offset; -} - -// Parse the given Ref string from the position Offset, to exactly match the given -// string Patt. -// Returns number of characters considered if successful. -static size_t ParseCustomString(const std::string &Ref, size_t Offset, - const char *Patt) { - size_t Len = strlen(Patt); - if (Offset + Len > Ref.size()) - return 0; - return Ref.compare(Offset, Len, Patt) == 0 ? Len : 0; -} - -// Parse a location, like: -// \\?\UNC\Server\Share\ \\?\C:\ \\Server\Share\ \ C:\ C: -// Returns number of characters considered if successful. -static size_t ParseLocation(const std::string &FileName) { - size_t Pos = 0, Res; - - if ((Res = ParseCustomString(FileName, Pos, R"(\\?\)"))) { - Pos += Res; - if ((Res = ParseCustomString(FileName, Pos, R"(UNC\)"))) { - Pos += Res; - if ((Res = ParseServerAndShare(FileName, Pos))) - return Pos + Res; - return 0; - } - if ((Res = ParseDrive(FileName, Pos, false))) - return Pos + Res; - return 0; - } - - if (Pos < FileName.size() && IsSeparator(FileName[Pos])) { - ++Pos; - if (Pos < FileName.size() && IsSeparator(FileName[Pos])) { - ++Pos; - if ((Res = ParseServerAndShare(FileName, Pos))) - return Pos + Res; - return 0; - } - return Pos; - } - - if ((Res = ParseDrive(FileName, Pos))) - return Pos + Res; - - return Pos; -} - -std::string DirName(const std::string &FileName) { - size_t LocationLen = ParseLocation(FileName); - size_t DirLen = 0, Res; - while ((Res = ParseDir(FileName, LocationLen + DirLen))) - DirLen += Res; - size_t FileLen = ParseFileName(FileName, LocationLen + DirLen); - - if (LocationLen + DirLen + FileLen != FileName.size()) { - Printf("DirName() failed for \"%s\", invalid path.\n", FileName.c_str()); - exit(1); - } - - if (DirLen) { - --DirLen; // Remove trailing separator. - if (!FileLen) { // Path ended in separator. - assert(DirLen); - // Remove file name from Dir. - while (DirLen && !IsSeparator(FileName[LocationLen + DirLen - 1])) - --DirLen; - if (DirLen) // Remove trailing separator. - --DirLen; - } - } - - if (!LocationLen) { // Relative path. - if (!DirLen) - return "."; - return std::string(".\\").append(FileName, 0, DirLen); - } - - return FileName.substr(0, LocationLen + DirLen); -} - -std::string TmpDir() { - std::string Tmp; - Tmp.resize(MAX_PATH + 1); - DWORD Size = GetTempPathA(Tmp.size(), &Tmp[0]); - if (Size == 0) { - Printf("Couldn't get Tmp path.\n"); - exit(1); - } - Tmp.resize(Size); - return Tmp; -} - -bool IsInterestingCoverageFile(const std::string &FileName) { - if (FileName.find("Program Files") != std::string::npos) - return false; - if (FileName.find("compiler-rt\\lib\\") != std::string::npos) - return false; // sanitizer internal. - if (FileName == "") - return false; - return true; -} - -void RawPrint(const char *Str) { - // Not tested, may or may not work. Fix if needed. - Printf("%s", Str); -} - -} // namespace fuzzer - -#endif // LIBFUZZER_WINDOWS Index: lib/fuzzer/FuzzerInterface.h =================================================================== --- lib/fuzzer/FuzzerInterface.h +++ /dev/null @@ -1,67 +0,0 @@ -//===- FuzzerInterface.h - Interface header for the Fuzzer ------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Define the interface between libFuzzer and the library being tested. -//===----------------------------------------------------------------------===// - -// NOTE: the libFuzzer interface is thin and in the majority of cases -// you should not include this file into your target. In 95% of cases -// all you need is to define the following function in your file: -// extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); - -// WARNING: keep the interface in C. - -#ifndef LLVM_FUZZER_INTERFACE_H -#define LLVM_FUZZER_INTERFACE_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -// Mandatory user-provided target function. -// Executes the code under test with [Data, Data+Size) as the input. -// libFuzzer will invoke this function *many* times with different inputs. -// Must return 0. -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); - -// Optional user-provided initialization function. -// If provided, this function will be called by libFuzzer once at startup. -// It may read and modify argc/argv. -// Must return 0. -int LLVMFuzzerInitialize(int *argc, char ***argv); - -// Optional user-provided custom mutator. -// Mutates raw data in [Data, Data+Size) inplace. -// Returns the new size, which is not greater than MaxSize. -// Given the same Seed produces the same mutation. -size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, - unsigned int Seed); - -// Optional user-provided custom cross-over function. -// Combines pieces of Data1 & Data2 together into Out. -// Returns the new size, which is not greater than MaxOutSize. -// Should produce the same mutation given the same Seed. -size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, - const uint8_t *Data2, size_t Size2, - uint8_t *Out, size_t MaxOutSize, - unsigned int Seed); - -// Experimental, may go away in future. -// libFuzzer-provided function to be used inside LLVMFuzzerCustomMutator. -// Mutates raw data in [Data, Data+Size) inplace. -// Returns the new size, which is not greater than MaxSize. -size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif // LLVM_FUZZER_INTERFACE_H Index: lib/fuzzer/FuzzerInternal.h =================================================================== --- lib/fuzzer/FuzzerInternal.h +++ /dev/null @@ -1,150 +0,0 @@ -//===- FuzzerInternal.h - Internal header for the Fuzzer --------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Define the main class fuzzer::Fuzzer and most functions. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_INTERNAL_H -#define LLVM_FUZZER_INTERNAL_H - -#include "FuzzerDefs.h" -#include "FuzzerExtFunctions.h" -#include "FuzzerInterface.h" -#include "FuzzerOptions.h" -#include "FuzzerSHA1.h" -#include "FuzzerValueBitMap.h" -#include -#include -#include -#include -#include -#include - -namespace fuzzer { - -using namespace std::chrono; - -class Fuzzer { -public: - - Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, - FuzzingOptions Options); - ~Fuzzer(); - void Loop(); - void MinimizeCrashLoop(const Unit &U); - void ShuffleAndMinimize(UnitVector *V); - void RereadOutputCorpus(size_t MaxSize); - - size_t secondsSinceProcessStartUp() { - return duration_cast(system_clock::now() - ProcessStartTime) - .count(); - } - - bool TimedOut() { - return Options.MaxTotalTimeSec > 0 && - secondsSinceProcessStartUp() > - static_cast(Options.MaxTotalTimeSec); - } - - size_t execPerSec() { - size_t Seconds = secondsSinceProcessStartUp(); - return Seconds ? TotalNumberOfRuns / Seconds : 0; - } - - size_t getTotalNumberOfRuns() { return TotalNumberOfRuns; } - - static void StaticAlarmCallback(); - static void StaticCrashSignalCallback(); - static void StaticExitCallback(); - static void StaticInterruptCallback(); - static void StaticFileSizeExceedCallback(); - - void ExecuteCallback(const uint8_t *Data, size_t Size); - bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false, - InputInfo *II = nullptr); - - // Merge Corpora[1:] into Corpora[0]. - void Merge(const std::vector &Corpora); - void CrashResistantMerge(const std::vector &Args, - const std::vector &Corpora, - const char *CoverageSummaryInputPathOrNull, - const char *CoverageSummaryOutputPathOrNull); - void CrashResistantMergeInternalStep(const std::string &ControlFilePath); - MutationDispatcher &GetMD() { return MD; } - void PrintFinalStats(); - void SetMaxInputLen(size_t MaxInputLen); - void SetMaxMutationLen(size_t MaxMutationLen); - void RssLimitCallback(); - - bool InFuzzingThread() const { return IsMyThread; } - size_t GetCurrentUnitInFuzzingThead(const uint8_t **Data) const; - void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, - bool DuringInitialCorpusExecution); - - void HandleMalloc(size_t Size); - void AnnounceOutput(const uint8_t *Data, size_t Size); - -private: - void AlarmCallback(); - void CrashCallback(); - void ExitCallback(); - void CrashOnOverwrittenData(); - void InterruptCallback(); - void MutateAndTestOne(); - void ReportNewCoverage(InputInfo *II, const Unit &U); - void PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size); - void WriteToOutputCorpus(const Unit &U); - void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix); - void PrintStats(const char *Where, const char *End = "\n", size_t Units = 0); - void PrintStatusForNewUnit(const Unit &U, const char *Text); - void ShuffleCorpus(UnitVector *V); - void CheckExitOnSrcPosOrItem(); - - static void StaticDeathCallback(); - void DumpCurrentUnit(const char *Prefix); - void DeathCallback(); - - void AllocateCurrentUnitData(); - uint8_t *CurrentUnitData = nullptr; - std::atomic CurrentUnitSize; - uint8_t BaseSha1[kSHA1NumBytes]; // Checksum of the base unit. - bool RunningCB = false; - - size_t TotalNumberOfRuns = 0; - size_t NumberOfNewUnitsAdded = 0; - - size_t LastCorpusUpdateRun = 0; - system_clock::time_point LastCorpusUpdateTime = system_clock::now(); - - - bool HasMoreMallocsThanFrees = false; - size_t NumberOfLeakDetectionAttempts = 0; - - UserCallback CB; - InputCorpus &Corpus; - MutationDispatcher &MD; - FuzzingOptions Options; - - system_clock::time_point ProcessStartTime = system_clock::now(); - system_clock::time_point UnitStartTime, UnitStopTime; - long TimeOfLongestUnitInSeconds = 0; - long EpochOfLastReadOfOutputCorpus = 0; - - size_t MaxInputLen = 0; - size_t MaxMutationLen = 0; - size_t TmpMaxMutationLen = 0; - - std::vector UniqFeatureSetTmp; - - // Need to know our own thread. - static thread_local bool IsMyThread; -}; - -} // namespace fuzzer - -#endif // LLVM_FUZZER_INTERNAL_H Index: lib/fuzzer/FuzzerLoop.cpp =================================================================== --- lib/fuzzer/FuzzerLoop.cpp +++ /dev/null @@ -1,721 +0,0 @@ -//===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Fuzzer's main loop. -//===----------------------------------------------------------------------===// - -#include "FuzzerCorpus.h" -#include "FuzzerIO.h" -#include "FuzzerInternal.h" -#include "FuzzerMutate.h" -#include "FuzzerRandom.h" -#include "FuzzerShmem.h" -#include "FuzzerTracePC.h" -#include -#include -#include -#include - -#if defined(__has_include) -#if __has_include() -#include -#endif -#endif - -#define NO_SANITIZE_MEMORY -#if defined(__has_feature) -#if __has_feature(memory_sanitizer) -#undef NO_SANITIZE_MEMORY -#define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory)) -#endif -#endif - -namespace fuzzer { -static const size_t kMaxUnitSizeToPrint = 256; - -thread_local bool Fuzzer::IsMyThread; - -SharedMemoryRegion SMR; - -// Only one Fuzzer per process. -static Fuzzer *F; - -// Leak detection is expensive, so we first check if there were more mallocs -// than frees (using the sanitizer malloc hooks) and only then try to call lsan. -struct MallocFreeTracer { - void Start(int TraceLevel) { - this->TraceLevel = TraceLevel; - if (TraceLevel) - Printf("MallocFreeTracer: START\n"); - Mallocs = 0; - Frees = 0; - } - // Returns true if there were more mallocs than frees. - bool Stop() { - if (TraceLevel) - Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs.load(), - Frees.load(), Mallocs == Frees ? "same" : "DIFFERENT"); - bool Result = Mallocs > Frees; - Mallocs = 0; - Frees = 0; - TraceLevel = 0; - return Result; - } - std::atomic Mallocs; - std::atomic Frees; - int TraceLevel = 0; -}; - -static MallocFreeTracer AllocTracer; - -ATTRIBUTE_NO_SANITIZE_MEMORY -void MallocHook(const volatile void *ptr, size_t size) { - size_t N = AllocTracer.Mallocs++; - F->HandleMalloc(size); - if (int TraceLevel = AllocTracer.TraceLevel) { - Printf("MALLOC[%zd] %p %zd\n", N, ptr, size); - if (TraceLevel >= 2 && EF) - EF->__sanitizer_print_stack_trace(); - } -} - -ATTRIBUTE_NO_SANITIZE_MEMORY -void FreeHook(const volatile void *ptr) { - size_t N = AllocTracer.Frees++; - if (int TraceLevel = AllocTracer.TraceLevel) { - Printf("FREE[%zd] %p\n", N, ptr); - if (TraceLevel >= 2 && EF) - EF->__sanitizer_print_stack_trace(); - } -} - -// Crash on a single malloc that exceeds the rss limit. -void Fuzzer::HandleMalloc(size_t Size) { - if (!Options.RssLimitMb || (Size >> 20) < (size_t)Options.RssLimitMb) - return; - Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(), - Size); - Printf(" To change the out-of-memory limit use -rss_limit_mb=\n\n"); - if (EF->__sanitizer_print_stack_trace) - EF->__sanitizer_print_stack_trace(); - DumpCurrentUnit("oom-"); - Printf("SUMMARY: libFuzzer: out-of-memory\n"); - PrintFinalStats(); - _Exit(Options.ErrorExitCode); // Stop right now. -} - -Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, - FuzzingOptions Options) - : CB(CB), Corpus(Corpus), MD(MD), Options(Options) { - if (EF->__sanitizer_set_death_callback) - EF->__sanitizer_set_death_callback(StaticDeathCallback); - assert(!F); - F = this; - TPC.ResetMaps(); - IsMyThread = true; - if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks) - EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook); - TPC.SetUseCounters(Options.UseCounters); - TPC.SetUseValueProfile(Options.UseValueProfile); - - if (Options.Verbosity) - TPC.PrintModuleInfo(); - if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec) - EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus); - MaxInputLen = MaxMutationLen = Options.MaxLen; - TmpMaxMutationLen = Max(size_t(4), Corpus.MaxInputSize()); - AllocateCurrentUnitData(); - CurrentUnitSize = 0; - memset(BaseSha1, 0, sizeof(BaseSha1)); -} - -Fuzzer::~Fuzzer() { } - -void Fuzzer::AllocateCurrentUnitData() { - if (CurrentUnitData || MaxInputLen == 0) return; - CurrentUnitData = new uint8_t[MaxInputLen]; -} - -void Fuzzer::StaticDeathCallback() { - assert(F); - F->DeathCallback(); -} - -void Fuzzer::DumpCurrentUnit(const char *Prefix) { - if (!CurrentUnitData) return; // Happens when running individual inputs. - MD.PrintMutationSequence(); - Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str()); - size_t UnitSize = CurrentUnitSize; - if (UnitSize <= kMaxUnitSizeToPrint) { - PrintHexArray(CurrentUnitData, UnitSize, "\n"); - PrintASCII(CurrentUnitData, UnitSize, "\n"); - } - WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize}, - Prefix); -} - -NO_SANITIZE_MEMORY -void Fuzzer::DeathCallback() { - DumpCurrentUnit("crash-"); - PrintFinalStats(); -} - -void Fuzzer::StaticAlarmCallback() { - assert(F); - F->AlarmCallback(); -} - -void Fuzzer::StaticCrashSignalCallback() { - assert(F); - F->CrashCallback(); -} - -void Fuzzer::StaticExitCallback() { - assert(F); - F->ExitCallback(); -} - -void Fuzzer::StaticInterruptCallback() { - assert(F); - F->InterruptCallback(); -} - -void Fuzzer::StaticFileSizeExceedCallback() { - Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid()); - exit(1); -} - -void Fuzzer::CrashCallback() { - Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid()); - if (EF->__sanitizer_print_stack_trace) - EF->__sanitizer_print_stack_trace(); - Printf("NOTE: libFuzzer has rudimentary signal handlers.\n" - " Combine libFuzzer with AddressSanitizer or similar for better " - "crash reports.\n"); - Printf("SUMMARY: libFuzzer: deadly signal\n"); - DumpCurrentUnit("crash-"); - PrintFinalStats(); - _Exit(Options.ErrorExitCode); // Stop right now. -} - -void Fuzzer::ExitCallback() { - if (!RunningCB) - return; // This exit did not come from the user callback - Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid()); - if (EF->__sanitizer_print_stack_trace) - EF->__sanitizer_print_stack_trace(); - Printf("SUMMARY: libFuzzer: fuzz target exited\n"); - DumpCurrentUnit("crash-"); - PrintFinalStats(); - _Exit(Options.ErrorExitCode); -} - - -void Fuzzer::InterruptCallback() { - Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid()); - PrintFinalStats(); - _Exit(0); // Stop right now, don't perform any at-exit actions. -} - -NO_SANITIZE_MEMORY -void Fuzzer::AlarmCallback() { - assert(Options.UnitTimeoutSec > 0); - // In Windows Alarm callback is executed by a different thread. -#if !LIBFUZZER_WINDOWS - if (!InFuzzingThread()) return; -#endif - if (!RunningCB) - return; // We have not started running units yet. - size_t Seconds = - duration_cast(system_clock::now() - UnitStartTime).count(); - if (Seconds == 0) - return; - if (Options.Verbosity >= 2) - Printf("AlarmCallback %zd\n", Seconds); - if (Seconds >= (size_t)Options.UnitTimeoutSec) { - Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds); - Printf(" and the timeout value is %d (use -timeout=N to change)\n", - Options.UnitTimeoutSec); - DumpCurrentUnit("timeout-"); - Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(), - Seconds); - if (EF->__sanitizer_print_stack_trace) - EF->__sanitizer_print_stack_trace(); - Printf("SUMMARY: libFuzzer: timeout\n"); - PrintFinalStats(); - _Exit(Options.TimeoutExitCode); // Stop right now. - } -} - -void Fuzzer::RssLimitCallback() { - Printf( - "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n", - GetPid(), GetPeakRSSMb(), Options.RssLimitMb); - Printf(" To change the out-of-memory limit use -rss_limit_mb=\n\n"); - if (EF->__sanitizer_print_memory_profile) - EF->__sanitizer_print_memory_profile(95, 8); - DumpCurrentUnit("oom-"); - Printf("SUMMARY: libFuzzer: out-of-memory\n"); - PrintFinalStats(); - _Exit(Options.ErrorExitCode); // Stop right now. -} - -void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) { - size_t ExecPerSec = execPerSec(); - if (!Options.Verbosity) - return; - Printf("#%zd\t%s", TotalNumberOfRuns, Where); - if (size_t N = TPC.GetTotalPCCoverage()) - Printf(" cov: %zd", N); - if (size_t N = Corpus.NumFeatures()) - Printf( " ft: %zd", N); - if (!Corpus.empty()) { - Printf(" corp: %zd", Corpus.NumActiveUnits()); - if (size_t N = Corpus.SizeInBytes()) { - if (N < (1<<14)) - Printf("/%zdb", N); - else if (N < (1 << 24)) - Printf("/%zdKb", N >> 10); - else - Printf("/%zdMb", N >> 20); - } - } - if (Units) - Printf(" units: %zd", Units); - - Printf(" exec/s: %zd", ExecPerSec); - Printf(" rss: %zdMb", GetPeakRSSMb()); - Printf("%s", End); -} - -void Fuzzer::PrintFinalStats() { - if (Options.PrintCoverage) - TPC.PrintCoverage(); - if (Options.DumpCoverage) - TPC.DumpCoverage(); - if (Options.PrintCorpusStats) - Corpus.PrintStats(); - if (!Options.PrintFinalStats) return; - size_t ExecPerSec = execPerSec(); - Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns); - Printf("stat::average_exec_per_sec: %zd\n", ExecPerSec); - Printf("stat::new_units_added: %zd\n", NumberOfNewUnitsAdded); - Printf("stat::slowest_unit_time_sec: %zd\n", TimeOfLongestUnitInSeconds); - Printf("stat::peak_rss_mb: %zd\n", GetPeakRSSMb()); -} - -void Fuzzer::SetMaxInputLen(size_t MaxInputLen) { - assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0. - assert(MaxInputLen); - this->MaxInputLen = MaxInputLen; - this->MaxMutationLen = MaxInputLen; - AllocateCurrentUnitData(); - Printf("INFO: -max_len is not provided; " - "libFuzzer will not generate inputs larger than %zd bytes\n", - MaxInputLen); -} - -void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) { - assert(MaxMutationLen && MaxMutationLen <= MaxInputLen); - this->MaxMutationLen = MaxMutationLen; -} - -void Fuzzer::CheckExitOnSrcPosOrItem() { - if (!Options.ExitOnSrcPos.empty()) { - static auto *PCsSet = new std::set; - auto HandlePC = [&](uintptr_t PC) { - if (!PCsSet->insert(PC).second) return; - std::string Descr = DescribePC("%F %L", PC + 1); - if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) { - Printf("INFO: found line matching '%s', exiting.\n", - Options.ExitOnSrcPos.c_str()); - _Exit(0); - } - }; - TPC.ForEachObservedPC(HandlePC); - } - if (!Options.ExitOnItem.empty()) { - if (Corpus.HasUnit(Options.ExitOnItem)) { - Printf("INFO: found item with checksum '%s', exiting.\n", - Options.ExitOnItem.c_str()); - _Exit(0); - } - } -} - -void Fuzzer::RereadOutputCorpus(size_t MaxSize) { - if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return; - std::vector AdditionalCorpus; - ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus, - &EpochOfLastReadOfOutputCorpus, MaxSize, - /*ExitOnError*/ false); - if (Options.Verbosity >= 2) - Printf("Reload: read %zd new units.\n", AdditionalCorpus.size()); - bool Reloaded = false; - for (auto &U : AdditionalCorpus) { - if (U.size() > MaxSize) - U.resize(MaxSize); - if (!Corpus.HasUnit(U)) { - if (RunOne(U.data(), U.size())) { - CheckExitOnSrcPosOrItem(); - Reloaded = true; - } - } - } - if (Reloaded) - PrintStats("RELOAD"); -} - -void Fuzzer::ShuffleCorpus(UnitVector *V) { - std::shuffle(V->begin(), V->end(), MD.GetRand()); - if (Options.PreferSmall) - std::stable_sort(V->begin(), V->end(), [](const Unit &A, const Unit &B) { - return A.size() < B.size(); - }); -} - -void Fuzzer::ShuffleAndMinimize(UnitVector *InitialCorpus) { - Printf("#0\tREAD units: %zd\n", InitialCorpus->size()); - if (Options.ShuffleAtStartUp) - ShuffleCorpus(InitialCorpus); - - // Test the callback with empty input and never try it again. - uint8_t dummy; - ExecuteCallback(&dummy, 0); - - for (const auto &U : *InitialCorpus) { - RunOne(U.data(), U.size()); - CheckExitOnSrcPosOrItem(); - TryDetectingAMemoryLeak(U.data(), U.size(), - /*DuringInitialCorpusExecution*/ true); - } - PrintStats("INITED"); - if (Corpus.empty()) { - Printf("ERROR: no interesting inputs were found. " - "Is the code instrumented for coverage? Exiting.\n"); - exit(1); - } -} - -void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) { - auto TimeOfUnit = - duration_cast(UnitStopTime - UnitStartTime).count(); - if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) && - secondsSinceProcessStartUp() >= 2) - PrintStats("pulse "); - if (TimeOfUnit > TimeOfLongestUnitInSeconds * 1.1 && - TimeOfUnit >= Options.ReportSlowUnits) { - TimeOfLongestUnitInSeconds = TimeOfUnit; - Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds); - WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-"); - } -} - -bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile, - InputInfo *II) { - if (!Size) return false; - - ExecuteCallback(Data, Size); - - UniqFeatureSetTmp.clear(); - size_t FoundUniqFeaturesOfII = 0; - size_t NumUpdatesBefore = Corpus.NumFeatureUpdates(); - TPC.CollectFeatures([&](size_t Feature) { - if (Corpus.AddFeature(Feature, Size, Options.Shrink)) - UniqFeatureSetTmp.push_back(Feature); - if (Options.ReduceInputs && II) - if (std::binary_search(II->UniqFeatureSet.begin(), - II->UniqFeatureSet.end(), Feature)) - FoundUniqFeaturesOfII++; - }); - PrintPulseAndReportSlowInput(Data, Size); - size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore; - if (NumNewFeatures) { - TPC.UpdateObservedPCs(); - Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile, - UniqFeatureSetTmp); - return true; - } - if (II && FoundUniqFeaturesOfII && - FoundUniqFeaturesOfII == II->UniqFeatureSet.size() && - II->U.size() > Size) { - Corpus.Replace(II, {Data, Data + Size}); - return true; - } - return false; -} - -size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const { - assert(InFuzzingThread()); - *Data = CurrentUnitData; - return CurrentUnitSize; -} - -void Fuzzer::CrashOnOverwrittenData() { - Printf("==%d== ERROR: libFuzzer: fuzz target overwrites it's const input\n", - GetPid()); - DumpCurrentUnit("crash-"); - Printf("SUMMARY: libFuzzer: out-of-memory\n"); - _Exit(Options.ErrorExitCode); // Stop right now. -} - -// Compare two arrays, but not all bytes if the arrays are large. -static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) { - const size_t Limit = 64; - if (Size <= 64) - return !memcmp(A, B, Size); - // Compare first and last Limit/2 bytes. - return !memcmp(A, B, Limit / 2) && - !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2); -} - -void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) { - TPC.RecordInitialStack(); - TotalNumberOfRuns++; - assert(InFuzzingThread()); - if (SMR.IsClient()) - SMR.WriteByteArray(Data, Size); - // We copy the contents of Unit into a separate heap buffer - // so that we reliably find buffer overflows in it. - uint8_t *DataCopy = new uint8_t[Size]; - memcpy(DataCopy, Data, Size); - if (CurrentUnitData && CurrentUnitData != Data) - memcpy(CurrentUnitData, Data, Size); - CurrentUnitSize = Size; - AllocTracer.Start(Options.TraceMalloc); - UnitStartTime = system_clock::now(); - TPC.ResetMaps(); - RunningCB = true; - int Res = CB(DataCopy, Size); - RunningCB = false; - UnitStopTime = system_clock::now(); - (void)Res; - assert(Res == 0); - HasMoreMallocsThanFrees = AllocTracer.Stop(); - if (!LooseMemeq(DataCopy, Data, Size)) - CrashOnOverwrittenData(); - CurrentUnitSize = 0; - delete[] DataCopy; -} - -void Fuzzer::WriteToOutputCorpus(const Unit &U) { - if (Options.OnlyASCII) - assert(IsASCII(U)); - if (Options.OutputCorpus.empty()) - return; - std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U)); - WriteToFile(U, Path); - if (Options.Verbosity >= 2) - Printf("Written %zd bytes to %s\n", U.size(), Path.c_str()); -} - -void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) { - if (!Options.SaveArtifacts) - return; - std::string Path = Options.ArtifactPrefix + Prefix + Hash(U); - if (!Options.ExactArtifactPath.empty()) - Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix. - WriteToFile(U, Path); - Printf("artifact_prefix='%s'; Test unit written to %s\n", - Options.ArtifactPrefix.c_str(), Path.c_str()); - if (U.size() <= kMaxUnitSizeToPrint) - Printf("Base64: %s\n", Base64(U).c_str()); -} - -void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) { - if (!Options.PrintNEW) - return; - PrintStats(Text, ""); - if (Options.Verbosity) { - Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize()); - MD.PrintMutationSequence(); - Printf("\n"); - } -} - -void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) { - II->NumSuccessfullMutations++; - MD.RecordSuccessfulMutationSequence(); - PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : - "NEW "); - WriteToOutputCorpus(U); - NumberOfNewUnitsAdded++; - CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus. - LastCorpusUpdateRun = TotalNumberOfRuns; - LastCorpusUpdateTime = system_clock::now(); -} - -// Tries detecting a memory leak on the particular input that we have just -// executed before calling this function. -void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, - bool DuringInitialCorpusExecution) { - if (!HasMoreMallocsThanFrees) return; // mallocs==frees, a leak is unlikely. - if (!Options.DetectLeaks) return; - if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) || - !(EF->__lsan_do_recoverable_leak_check)) - return; // No lsan. - // Run the target once again, but with lsan disabled so that if there is - // a real leak we do not report it twice. - EF->__lsan_disable(); - ExecuteCallback(Data, Size); - EF->__lsan_enable(); - if (!HasMoreMallocsThanFrees) return; // a leak is unlikely. - if (NumberOfLeakDetectionAttempts++ > 1000) { - Options.DetectLeaks = false; - Printf("INFO: libFuzzer disabled leak detection after every mutation.\n" - " Most likely the target function accumulates allocated\n" - " memory in a global state w/o actually leaking it.\n" - " You may try running this binary with -trace_malloc=[12]" - " to get a trace of mallocs and frees.\n" - " If LeakSanitizer is enabled in this process it will still\n" - " run on the process shutdown.\n"); - return; - } - // Now perform the actual lsan pass. This is expensive and we must ensure - // we don't call it too often. - if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it. - if (DuringInitialCorpusExecution) - Printf("\nINFO: a leak has been found in the initial corpus.\n\n"); - Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n"); - CurrentUnitSize = Size; - DumpCurrentUnit("leak-"); - PrintFinalStats(); - _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on. - } -} - -void Fuzzer::MutateAndTestOne() { - MD.StartMutationSequence(); - - auto &II = Corpus.ChooseUnitToMutate(MD.GetRand()); - const auto &U = II.U; - memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1)); - assert(CurrentUnitData); - size_t Size = U.size(); - assert(Size <= MaxInputLen && "Oversized Unit"); - memcpy(CurrentUnitData, U.data(), Size); - - assert(MaxMutationLen > 0); - - size_t CurrentMaxMutationLen = - Min(MaxMutationLen, Max(U.size(), TmpMaxMutationLen)); - assert(CurrentMaxMutationLen > 0); - - for (int i = 0; i < Options.MutateDepth; i++) { - if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) - break; - size_t NewSize = 0; - NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen); - assert(NewSize > 0 && "Mutator returned empty unit"); - assert(NewSize <= CurrentMaxMutationLen && "Mutator return overisized unit"); - Size = NewSize; - II.NumExecutedMutations++; - if (RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II)) - ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size}); - - TryDetectingAMemoryLeak(CurrentUnitData, Size, - /*DuringInitialCorpusExecution*/ false); - } -} - -void Fuzzer::Loop() { - TPC.SetPrintNewPCs(Options.PrintNewCovPcs); - system_clock::time_point LastCorpusReload = system_clock::now(); - if (Options.DoCrossOver) - MD.SetCorpus(&Corpus); - while (true) { - auto Now = system_clock::now(); - if (duration_cast(Now - LastCorpusReload).count() >= - Options.ReloadIntervalSec) { - RereadOutputCorpus(MaxInputLen); - LastCorpusReload = system_clock::now(); - } - if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) - break; - if (TimedOut()) break; - - // Update TmpMaxMutationLen - if (Options.ExperimentalLenControl) { - if (TmpMaxMutationLen < MaxMutationLen && - (TotalNumberOfRuns - LastCorpusUpdateRun > 1000 && - duration_cast(Now - LastCorpusUpdateTime).count() >= 1)) { - LastCorpusUpdateRun = TotalNumberOfRuns; - LastCorpusUpdateTime = Now; - TmpMaxMutationLen = - Min(MaxMutationLen, - TmpMaxMutationLen + Max(size_t(4), TmpMaxMutationLen / 8)); - if (TmpMaxMutationLen <= MaxMutationLen) - Printf("#%zd\tTEMP_MAX_LEN: %zd\n", TotalNumberOfRuns, - TmpMaxMutationLen); - } - } else { - TmpMaxMutationLen = MaxMutationLen; - } - - // Perform several mutations and runs. - MutateAndTestOne(); - } - - PrintStats("DONE ", "\n"); - MD.PrintRecommendedDictionary(); -} - -void Fuzzer::MinimizeCrashLoop(const Unit &U) { - if (U.size() <= 1) return; - while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) { - MD.StartMutationSequence(); - memcpy(CurrentUnitData, U.data(), U.size()); - for (int i = 0; i < Options.MutateDepth; i++) { - size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen); - assert(NewSize > 0 && NewSize <= MaxMutationLen); - ExecuteCallback(CurrentUnitData, NewSize); - PrintPulseAndReportSlowInput(CurrentUnitData, NewSize); - TryDetectingAMemoryLeak(CurrentUnitData, NewSize, - /*DuringInitialCorpusExecution*/ false); - } - } -} - -void Fuzzer::AnnounceOutput(const uint8_t *Data, size_t Size) { - if (SMR.IsServer()) { - SMR.WriteByteArray(Data, Size); - } else if (SMR.IsClient()) { - SMR.PostClient(); - SMR.WaitServer(); - size_t OtherSize = SMR.ReadByteArraySize(); - uint8_t *OtherData = SMR.GetByteArray(); - if (Size != OtherSize || memcmp(Data, OtherData, Size) != 0) { - size_t i = 0; - for (i = 0; i < Min(Size, OtherSize); i++) - if (Data[i] != OtherData[i]) - break; - Printf("==%lu== ERROR: libFuzzer: equivalence-mismatch. Sizes: %zd %zd; " - "offset %zd\n", GetPid(), Size, OtherSize, i); - DumpCurrentUnit("mismatch-"); - Printf("SUMMARY: libFuzzer: equivalence-mismatch\n"); - PrintFinalStats(); - _Exit(Options.ErrorExitCode); - } - } -} - -} // namespace fuzzer - -extern "C" { - -size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { - assert(fuzzer::F); - return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize); -} - -// Experimental -void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) { - assert(fuzzer::F); - fuzzer::F->AnnounceOutput(Data, Size); -} -} // extern "C" Index: lib/fuzzer/FuzzerMain.cpp =================================================================== --- lib/fuzzer/FuzzerMain.cpp +++ /dev/null @@ -1,21 +0,0 @@ -//===- FuzzerMain.cpp - main() function and flags -------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// main() and flags. -//===----------------------------------------------------------------------===// - -#include "FuzzerDefs.h" - -extern "C" { -// This function should be defined by the user. -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); -} // extern "C" - -int main(int argc, char **argv) { - return fuzzer::FuzzerDriver(&argc, &argv, LLVMFuzzerTestOneInput); -} Index: lib/fuzzer/FuzzerMerge.h =================================================================== --- lib/fuzzer/FuzzerMerge.h +++ /dev/null @@ -1,80 +0,0 @@ -//===- FuzzerMerge.h - merging corpa ----------------------------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Merging Corpora. -// -// The task: -// Take the existing corpus (possibly empty) and merge new inputs into -// it so that only inputs with new coverage ('features') are added. -// The process should tolerate the crashes, OOMs, leaks, etc. -// -// Algorithm: -// The outter process collects the set of files and writes their names -// into a temporary "control" file, then repeatedly launches the inner -// process until all inputs are processed. -// The outer process does not actually execute the target code. -// -// The inner process reads the control file and sees a) list of all the inputs -// and b) the last processed input. Then it starts processing the inputs one -// by one. Before processing every input it writes one line to control file: -// STARTED INPUT_ID INPUT_SIZE -// After processing an input it write another line: -// DONE INPUT_ID Feature1 Feature2 Feature3 ... -// If a crash happens while processing an input the last line in the control -// file will be "STARTED INPUT_ID" and so the next process will know -// where to resume. -// -// Once all inputs are processed by the innner process(es) the outer process -// reads the control files and does the merge based entirely on the contents -// of control file. -// It uses a single pass greedy algorithm choosing first the smallest inputs -// within the same size the inputs that have more new features. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_MERGE_H -#define LLVM_FUZZER_MERGE_H - -#include "FuzzerDefs.h" - -#include -#include -#include -#include - -namespace fuzzer { - -struct MergeFileInfo { - std::string Name; - size_t Size = 0; - std::vector Features; -}; - -struct Merger { - std::vector Files; - size_t NumFilesInFirstCorpus = 0; - size_t FirstNotProcessedFile = 0; - std::string LastFailure; - - bool Parse(std::istream &IS, bool ParseCoverage); - bool Parse(const std::string &Str, bool ParseCoverage); - void ParseOrExit(std::istream &IS, bool ParseCoverage); - void PrintSummary(std::ostream &OS); - std::set ParseSummary(std::istream &IS); - size_t Merge(const std::set &InitialFeatures, - std::vector *NewFiles); - size_t Merge(std::vector *NewFiles) { - return Merge(std::set{}, NewFiles); - } - size_t ApproximateMemoryConsumption() const; - std::set AllFeatures() const; -}; - -} // namespace fuzzer - -#endif // LLVM_FUZZER_MERGE_H Index: lib/fuzzer/FuzzerMerge.cpp =================================================================== --- lib/fuzzer/FuzzerMerge.cpp +++ /dev/null @@ -1,338 +0,0 @@ -//===- FuzzerMerge.cpp - merging corpora ----------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Merging corpora. -//===----------------------------------------------------------------------===// - -#include "FuzzerMerge.h" -#include "FuzzerIO.h" -#include "FuzzerInternal.h" -#include "FuzzerTracePC.h" -#include "FuzzerUtil.h" - -#include -#include -#include -#include - -namespace fuzzer { - -bool Merger::Parse(const std::string &Str, bool ParseCoverage) { - std::istringstream SS(Str); - return Parse(SS, ParseCoverage); -} - -void Merger::ParseOrExit(std::istream &IS, bool ParseCoverage) { - if (!Parse(IS, ParseCoverage)) { - Printf("MERGE: failed to parse the control file (unexpected error)\n"); - exit(1); - } -} - -// The control file example: -// -// 3 # The number of inputs -// 1 # The number of inputs in the first corpus, <= the previous number -// file0 -// file1 -// file2 # One file name per line. -// STARTED 0 123 # FileID, file size -// DONE 0 1 4 6 8 # FileID COV1 COV2 ... -// STARTED 1 456 # If DONE is missing, the input crashed while processing. -// STARTED 2 567 -// DONE 2 8 9 -bool Merger::Parse(std::istream &IS, bool ParseCoverage) { - LastFailure.clear(); - std::string Line; - - // Parse NumFiles. - if (!std::getline(IS, Line, '\n')) return false; - std::istringstream L1(Line); - size_t NumFiles = 0; - L1 >> NumFiles; - if (NumFiles == 0 || NumFiles > 10000000) return false; - - // Parse NumFilesInFirstCorpus. - if (!std::getline(IS, Line, '\n')) return false; - std::istringstream L2(Line); - NumFilesInFirstCorpus = NumFiles + 1; - L2 >> NumFilesInFirstCorpus; - if (NumFilesInFirstCorpus > NumFiles) return false; - - // Parse file names. - Files.resize(NumFiles); - for (size_t i = 0; i < NumFiles; i++) - if (!std::getline(IS, Files[i].Name, '\n')) - return false; - - // Parse STARTED and DONE lines. - size_t ExpectedStartMarker = 0; - const size_t kInvalidStartMarker = -1; - size_t LastSeenStartMarker = kInvalidStartMarker; - std::vector TmpFeatures; - while (std::getline(IS, Line, '\n')) { - std::istringstream ISS1(Line); - std::string Marker; - size_t N; - ISS1 >> Marker; - ISS1 >> N; - if (Marker == "STARTED") { - // STARTED FILE_ID FILE_SIZE - if (ExpectedStartMarker != N) - return false; - ISS1 >> Files[ExpectedStartMarker].Size; - LastSeenStartMarker = ExpectedStartMarker; - assert(ExpectedStartMarker < Files.size()); - ExpectedStartMarker++; - } else if (Marker == "DONE") { - // DONE FILE_ID COV1 COV2 COV3 ... - size_t CurrentFileIdx = N; - if (CurrentFileIdx != LastSeenStartMarker) - return false; - LastSeenStartMarker = kInvalidStartMarker; - if (ParseCoverage) { - TmpFeatures.clear(); // use a vector from outer scope to avoid resizes. - while (ISS1 >> std::hex >> N) - TmpFeatures.push_back(N); - std::sort(TmpFeatures.begin(), TmpFeatures.end()); - Files[CurrentFileIdx].Features = TmpFeatures; - } - } else { - return false; - } - } - if (LastSeenStartMarker != kInvalidStartMarker) - LastFailure = Files[LastSeenStartMarker].Name; - - FirstNotProcessedFile = ExpectedStartMarker; - return true; -} - -size_t Merger::ApproximateMemoryConsumption() const { - size_t Res = 0; - for (const auto &F: Files) - Res += sizeof(F) + F.Features.size() * sizeof(F.Features[0]); - return Res; -} - -// Decides which files need to be merged (add thost to NewFiles). -// Returns the number of new features added. -size_t Merger::Merge(const std::set &InitialFeatures, - std::vector *NewFiles) { - NewFiles->clear(); - assert(NumFilesInFirstCorpus <= Files.size()); - std::set AllFeatures(InitialFeatures); - - // What features are in the initial corpus? - for (size_t i = 0; i < NumFilesInFirstCorpus; i++) { - auto &Cur = Files[i].Features; - AllFeatures.insert(Cur.begin(), Cur.end()); - } - size_t InitialNumFeatures = AllFeatures.size(); - - // Remove all features that we already know from all other inputs. - for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) { - auto &Cur = Files[i].Features; - std::vector Tmp; - std::set_difference(Cur.begin(), Cur.end(), AllFeatures.begin(), - AllFeatures.end(), std::inserter(Tmp, Tmp.begin())); - Cur.swap(Tmp); - } - - // Sort. Give preference to - // * smaller files - // * files with more features. - std::sort(Files.begin() + NumFilesInFirstCorpus, Files.end(), - [&](const MergeFileInfo &a, const MergeFileInfo &b) -> bool { - if (a.Size != b.Size) - return a.Size < b.Size; - return a.Features.size() > b.Features.size(); - }); - - // One greedy pass: add the file's features to AllFeatures. - // If new features were added, add this file to NewFiles. - for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) { - auto &Cur = Files[i].Features; - // Printf("%s -> sz %zd ft %zd\n", Files[i].Name.c_str(), - // Files[i].Size, Cur.size()); - size_t OldSize = AllFeatures.size(); - AllFeatures.insert(Cur.begin(), Cur.end()); - if (AllFeatures.size() > OldSize) - NewFiles->push_back(Files[i].Name); - } - return AllFeatures.size() - InitialNumFeatures; -} - -void Merger::PrintSummary(std::ostream &OS) { - for (auto &File : Files) { - OS << std::hex; - OS << File.Name << " size: " << File.Size << " features: "; - for (auto Feature : File.Features) - OS << " " << Feature; - OS << "\n"; - } -} - -std::set Merger::AllFeatures() const { - std::set S; - for (auto &File : Files) - S.insert(File.Features.begin(), File.Features.end()); - return S; -} - -std::set Merger::ParseSummary(std::istream &IS) { - std::string Line, Tmp; - std::set Res; - while (std::getline(IS, Line, '\n')) { - size_t N; - std::istringstream ISS1(Line); - ISS1 >> Tmp; // Name - ISS1 >> Tmp; // size: - assert(Tmp == "size:" && "Corrupt summary file"); - ISS1 >> std::hex; - ISS1 >> N; // File Size - ISS1 >> Tmp; // features: - assert(Tmp == "features:" && "Corrupt summary file"); - while (ISS1 >> std::hex >> N) - Res.insert(N); - } - return Res; -} - -// Inner process. May crash if the target crashes. -void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { - Printf("MERGE-INNER: using the control file '%s'\n", CFPath.c_str()); - Merger M; - std::ifstream IF(CFPath); - M.ParseOrExit(IF, false); - IF.close(); - if (!M.LastFailure.empty()) - Printf("MERGE-INNER: '%s' caused a failure at the previous merge step\n", - M.LastFailure.c_str()); - - Printf("MERGE-INNER: %zd total files;" - " %zd processed earlier; will process %zd files now\n", - M.Files.size(), M.FirstNotProcessedFile, - M.Files.size() - M.FirstNotProcessedFile); - - std::ofstream OF(CFPath, std::ofstream::out | std::ofstream::app); - for (size_t i = M.FirstNotProcessedFile; i < M.Files.size(); i++) { - auto U = FileToVector(M.Files[i].Name); - if (U.size() > MaxInputLen) { - U.resize(MaxInputLen); - U.shrink_to_fit(); - } - std::ostringstream StartedLine; - // Write the pre-run marker. - OF << "STARTED " << std::dec << i << " " << U.size() << "\n"; - OF.flush(); // Flush is important since ExecuteCommand may crash. - // Run. - TPC.ResetMaps(); - ExecuteCallback(U.data(), U.size()); - // Collect coverage. - std::set Features; - TPC.CollectFeatures([&](size_t Feature) -> bool { - Features.insert(Feature); - return true; - }); - // Show stats. - if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1))) - PrintStats("pulse "); - // Write the post-run marker and the coverage. - OF << "DONE " << i; - for (size_t F : Features) - OF << " " << std::hex << F; - OF << "\n"; - } -} - -// Outer process. Does not call the target code and thus sohuld not fail. -void Fuzzer::CrashResistantMerge(const std::vector &Args, - const std::vector &Corpora, - const char *CoverageSummaryInputPathOrNull, - const char *CoverageSummaryOutputPathOrNull) { - if (Corpora.size() <= 1) { - Printf("Merge requires two or more corpus dirs\n"); - return; - } - std::vector AllFiles; - ListFilesInDirRecursive(Corpora[0], nullptr, &AllFiles, /*TopDir*/true); - size_t NumFilesInFirstCorpus = AllFiles.size(); - for (size_t i = 1; i < Corpora.size(); i++) - ListFilesInDirRecursive(Corpora[i], nullptr, &AllFiles, /*TopDir*/true); - Printf("MERGE-OUTER: %zd files, %zd in the initial corpus\n", - AllFiles.size(), NumFilesInFirstCorpus); - auto CFPath = DirPlusFile(TmpDir(), - "libFuzzerTemp." + std::to_string(GetPid()) + ".txt"); - // Write the control file. - RemoveFile(CFPath); - std::ofstream ControlFile(CFPath); - ControlFile << AllFiles.size() << "\n"; - ControlFile << NumFilesInFirstCorpus << "\n"; - for (auto &Path: AllFiles) - ControlFile << Path << "\n"; - if (!ControlFile) { - Printf("MERGE-OUTER: failed to write to the control file: %s\n", - CFPath.c_str()); - exit(1); - } - ControlFile.close(); - - // Execute the inner process untill it passes. - // Every inner process should execute at least one input. - auto BaseCmd = SplitBefore("-ignore_remaining_args=1", - CloneArgsWithoutX(Args, "keep-all-flags")); - bool Success = false; - for (size_t i = 1; i <= AllFiles.size(); i++) { - Printf("MERGE-OUTER: attempt %zd\n", i); - auto ExitCode = ExecuteCommand(BaseCmd.first + " -merge_control_file=" + - CFPath + " " + BaseCmd.second); - if (!ExitCode) { - Printf("MERGE-OUTER: succesfull in %zd attempt(s)\n", i); - Success = true; - break; - } - } - if (!Success) { - Printf("MERGE-OUTER: zero succesfull attempts, exiting\n"); - exit(1); - } - // Read the control file and do the merge. - Merger M; - std::ifstream IF(CFPath); - IF.seekg(0, IF.end); - Printf("MERGE-OUTER: the control file has %zd bytes\n", (size_t)IF.tellg()); - IF.seekg(0, IF.beg); - M.ParseOrExit(IF, true); - IF.close(); - Printf("MERGE-OUTER: consumed %zdMb (%zdMb rss) to parse the control file\n", - M.ApproximateMemoryConsumption() >> 20, GetPeakRSSMb()); - if (CoverageSummaryOutputPathOrNull) { - Printf("MERGE-OUTER: writing coverage summary for %zd files to %s\n", - M.Files.size(), CoverageSummaryOutputPathOrNull); - std::ofstream SummaryOut(CoverageSummaryOutputPathOrNull); - M.PrintSummary(SummaryOut); - } - std::vector NewFiles; - std::set InitialFeatures; - if (CoverageSummaryInputPathOrNull) { - std::ifstream SummaryIn(CoverageSummaryInputPathOrNull); - InitialFeatures = M.ParseSummary(SummaryIn); - Printf("MERGE-OUTER: coverage summary loaded from %s, %zd features found\n", - CoverageSummaryInputPathOrNull, InitialFeatures.size()); - } - size_t NumNewFeatures = M.Merge(InitialFeatures, &NewFiles); - Printf("MERGE-OUTER: %zd new files with %zd new features added\n", - NewFiles.size(), NumNewFeatures); - for (auto &F: NewFiles) - WriteToOutputCorpus(FileToVector(F)); - // We are done, delete the control file. - RemoveFile(CFPath); -} - -} // namespace fuzzer Index: lib/fuzzer/FuzzerMutate.h =================================================================== --- lib/fuzzer/FuzzerMutate.h +++ /dev/null @@ -1,150 +0,0 @@ -//===- FuzzerMutate.h - Internal header for the Fuzzer ----------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// fuzzer::MutationDispatcher -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_MUTATE_H -#define LLVM_FUZZER_MUTATE_H - -#include "FuzzerDefs.h" -#include "FuzzerDictionary.h" -#include "FuzzerOptions.h" -#include "FuzzerRandom.h" - -namespace fuzzer { - -class MutationDispatcher { -public: - MutationDispatcher(Random &Rand, const FuzzingOptions &Options); - ~MutationDispatcher() {} - /// Indicate that we are about to start a new sequence of mutations. - void StartMutationSequence(); - /// Print the current sequence of mutations. - void PrintMutationSequence(); - /// Indicate that the current sequence of mutations was successfull. - void RecordSuccessfulMutationSequence(); - /// Mutates data by invoking user-provided mutator. - size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by invoking user-provided crossover. - size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by shuffling bytes. - size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by erasing bytes. - size_t Mutate_EraseBytes(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by inserting a byte. - size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by inserting several repeated bytes. - size_t Mutate_InsertRepeatedBytes(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by chanding one byte. - size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by chanding one bit. - size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by copying/inserting a part of data into a different place. - size_t Mutate_CopyPart(uint8_t *Data, size_t Size, size_t MaxSize); - - /// Mutates data by adding a word from the manual dictionary. - size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size, - size_t MaxSize); - - /// Mutates data by adding a word from the TORC. - size_t Mutate_AddWordFromTORC(uint8_t *Data, size_t Size, size_t MaxSize); - - /// Mutates data by adding a word from the persistent automatic dictionary. - size_t Mutate_AddWordFromPersistentAutoDictionary(uint8_t *Data, size_t Size, - size_t MaxSize); - - /// Tries to find an ASCII integer in Data, changes it to another ASCII int. - size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize); - /// Change a 1-, 2-, 4-, or 8-byte integer in interesting ways. - size_t Mutate_ChangeBinaryInteger(uint8_t *Data, size_t Size, size_t MaxSize); - - /// CrossOver Data with some other element of the corpus. - size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize); - - /// Applies one of the configured mutations. - /// Returns the new size of data which could be up to MaxSize. - size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize); - /// Applies one of the default mutations. Provided as a service - /// to mutation authors. - size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize); - - /// Creates a cross-over of two pieces of Data, returns its size. - size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, - size_t Size2, uint8_t *Out, size_t MaxOutSize); - - void AddWordToManualDictionary(const Word &W); - - void PrintRecommendedDictionary(); - - void SetCorpus(const InputCorpus *Corpus) { this->Corpus = Corpus; } - - Random &GetRand() { return Rand; } - -private: - - struct Mutator { - size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max); - const char *Name; - }; - - size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, - size_t MaxSize); - size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, - const std::vector &Mutators); - - size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To, - size_t ToSize, size_t MaxToSize); - size_t CopyPartOf(const uint8_t *From, size_t FromSize, uint8_t *To, - size_t ToSize); - size_t ApplyDictionaryEntry(uint8_t *Data, size_t Size, size_t MaxSize, - DictionaryEntry &DE); - - template - DictionaryEntry MakeDictionaryEntryFromCMP(T Arg1, T Arg2, - const uint8_t *Data, size_t Size); - DictionaryEntry MakeDictionaryEntryFromCMP(const Word &Arg1, const Word &Arg2, - const uint8_t *Data, size_t Size); - DictionaryEntry MakeDictionaryEntryFromCMP(const void *Arg1, const void *Arg2, - const void *Arg1Mutation, - const void *Arg2Mutation, - size_t ArgSize, - const uint8_t *Data, size_t Size); - - Random &Rand; - const FuzzingOptions Options; - - // Dictionary provided by the user via -dict=DICT_FILE. - Dictionary ManualDictionary; - // Temporary dictionary modified by the fuzzer itself, - // recreated periodically. - Dictionary TempAutoDictionary; - // Persistent dictionary modified by the fuzzer, consists of - // entries that led to successfull discoveries in the past mutations. - Dictionary PersistentAutoDictionary; - - std::vector CurrentMutatorSequence; - std::vector CurrentDictionaryEntrySequence; - - static const size_t kCmpDictionaryEntriesDequeSize = 16; - DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize]; - size_t CmpDictionaryEntriesDequeIdx = 0; - - const InputCorpus *Corpus = nullptr; - std::vector MutateInPlaceHere; - // CustomCrossOver needs its own buffer as a custom implementation may call - // LLVMFuzzerMutate, which in turn may resize MutateInPlaceHere. - std::vector CustomCrossOverInPlaceHere; - - std::vector Mutators; - std::vector DefaultMutators; -}; - -} // namespace fuzzer - -#endif // LLVM_FUZZER_MUTATE_H Index: lib/fuzzer/FuzzerMutate.cpp =================================================================== --- lib/fuzzer/FuzzerMutate.cpp +++ /dev/null @@ -1,533 +0,0 @@ -//===- FuzzerMutate.cpp - Mutate a test input -----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Mutate a test input. -//===----------------------------------------------------------------------===// - -#include "FuzzerMutate.h" -#include "FuzzerCorpus.h" -#include "FuzzerDefs.h" -#include "FuzzerExtFunctions.h" -#include "FuzzerIO.h" -#include "FuzzerOptions.h" - -namespace fuzzer { - -const size_t Dictionary::kMaxDictSize; - -static void PrintASCII(const Word &W, const char *PrintAfter) { - PrintASCII(W.data(), W.size(), PrintAfter); -} - -MutationDispatcher::MutationDispatcher(Random &Rand, - const FuzzingOptions &Options) - : Rand(Rand), Options(Options) { - DefaultMutators.insert( - DefaultMutators.begin(), - { - {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"}, - {&MutationDispatcher::Mutate_InsertByte, "InsertByte"}, - {&MutationDispatcher::Mutate_InsertRepeatedBytes, - "InsertRepeatedBytes"}, - {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}, - {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}, - {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}, - {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}, - {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"}, - {&MutationDispatcher::Mutate_CopyPart, "CopyPart"}, - {&MutationDispatcher::Mutate_CrossOver, "CrossOver"}, - {&MutationDispatcher::Mutate_AddWordFromManualDictionary, - "ManualDict"}, - {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, - "PersAutoDict"}, - }); - if(Options.UseCmp) - DefaultMutators.push_back( - {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"}); - - if (EF->LLVMFuzzerCustomMutator) - Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"}); - else - Mutators = DefaultMutators; - - if (EF->LLVMFuzzerCustomCrossOver) - Mutators.push_back( - {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"}); -} - -static char RandCh(Random &Rand) { - if (Rand.RandBool()) return Rand(256); - const char *Special = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00"; - return Special[Rand(sizeof(Special) - 1)]; -} - -size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size, - size_t MaxSize) { - return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand()); -} - -size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size, - size_t MaxSize) { - if (!Corpus || Corpus->size() < 2 || Size == 0) - return 0; - size_t Idx = Rand(Corpus->size()); - const Unit &Other = (*Corpus)[Idx]; - if (Other.empty()) - return 0; - CustomCrossOverInPlaceHere.resize(MaxSize); - auto &U = CustomCrossOverInPlaceHere; - size_t NewSize = EF->LLVMFuzzerCustomCrossOver( - Data, Size, Other.data(), Other.size(), U.data(), U.size(), Rand.Rand()); - if (!NewSize) - return 0; - assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit"); - memcpy(Data, U.data(), NewSize); - return NewSize; -} - -size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size, - size_t MaxSize) { - if (Size > MaxSize || Size == 0) return 0; - size_t ShuffleAmount = - Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size. - size_t ShuffleStart = Rand(Size - ShuffleAmount); - assert(ShuffleStart + ShuffleAmount <= Size); - std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand); - return Size; -} - -size_t MutationDispatcher::Mutate_EraseBytes(uint8_t *Data, size_t Size, - size_t MaxSize) { - if (Size <= 1) return 0; - size_t N = Rand(Size / 2) + 1; - assert(N < Size); - size_t Idx = Rand(Size - N + 1); - // Erase Data[Idx:Idx+N]. - memmove(Data + Idx, Data + Idx + N, Size - Idx - N); - // Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx); - return Size - N; -} - -size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size, - size_t MaxSize) { - if (Size >= MaxSize) return 0; - size_t Idx = Rand(Size + 1); - // Insert new value at Data[Idx]. - memmove(Data + Idx + 1, Data + Idx, Size - Idx); - Data[Idx] = RandCh(Rand); - return Size + 1; -} - -size_t MutationDispatcher::Mutate_InsertRepeatedBytes(uint8_t *Data, - size_t Size, - size_t MaxSize) { - const size_t kMinBytesToInsert = 3; - if (Size + kMinBytesToInsert >= MaxSize) return 0; - size_t MaxBytesToInsert = std::min(MaxSize - Size, (size_t)128); - size_t N = Rand(MaxBytesToInsert - kMinBytesToInsert + 1) + kMinBytesToInsert; - assert(Size + N <= MaxSize && N); - size_t Idx = Rand(Size + 1); - // Insert new values at Data[Idx]. - memmove(Data + Idx + N, Data + Idx, Size - Idx); - // Give preference to 0x00 and 0xff. - uint8_t Byte = Rand.RandBool() ? Rand(256) : (Rand.RandBool() ? 0 : 255); - for (size_t i = 0; i < N; i++) - Data[Idx + i] = Byte; - return Size + N; -} - -size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size, - size_t MaxSize) { - if (Size > MaxSize) return 0; - size_t Idx = Rand(Size); - Data[Idx] = RandCh(Rand); - return Size; -} - -size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size, - size_t MaxSize) { - if (Size > MaxSize) return 0; - size_t Idx = Rand(Size); - Data[Idx] ^= 1 << Rand(8); - return Size; -} - -size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data, - size_t Size, - size_t MaxSize) { - return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize); -} - -size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size, - size_t MaxSize, - DictionaryEntry &DE) { - const Word &W = DE.GetW(); - bool UsePositionHint = DE.HasPositionHint() && - DE.GetPositionHint() + W.size() < Size && - Rand.RandBool(); - if (Rand.RandBool()) { // Insert W. - if (Size + W.size() > MaxSize) return 0; - size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1); - memmove(Data + Idx + W.size(), Data + Idx, Size - Idx); - memcpy(Data + Idx, W.data(), W.size()); - Size += W.size(); - } else { // Overwrite some bytes with W. - if (W.size() > Size) return 0; - size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size - W.size()); - memcpy(Data + Idx, W.data(), W.size()); - } - return Size; -} - -// Somewhere in the past we have observed a comparison instructions -// with arguments Arg1 Arg2. This function tries to guess a dictionary -// entry that will satisfy that comparison. -// It first tries to find one of the arguments (possibly swapped) in the -// input and if it succeeds it creates a DE with a position hint. -// Otherwise it creates a DE with one of the arguments w/o a position hint. -DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( - const void *Arg1, const void *Arg2, - const void *Arg1Mutation, const void *Arg2Mutation, - size_t ArgSize, const uint8_t *Data, - size_t Size) { - ScopedDoingMyOwnMemOrStr scoped_doing_my_own_mem_os_str; - bool HandleFirst = Rand.RandBool(); - const void *ExistingBytes, *DesiredBytes; - Word W; - const uint8_t *End = Data + Size; - for (int Arg = 0; Arg < 2; Arg++) { - ExistingBytes = HandleFirst ? Arg1 : Arg2; - DesiredBytes = HandleFirst ? Arg2Mutation : Arg1Mutation; - HandleFirst = !HandleFirst; - W.Set(reinterpret_cast(DesiredBytes), ArgSize); - const size_t kMaxNumPositions = 8; - size_t Positions[kMaxNumPositions]; - size_t NumPositions = 0; - for (const uint8_t *Cur = Data; - Cur < End && NumPositions < kMaxNumPositions; Cur++) { - Cur = - (const uint8_t *)SearchMemory(Cur, End - Cur, ExistingBytes, ArgSize); - if (!Cur) break; - Positions[NumPositions++] = Cur - Data; - } - if (!NumPositions) continue; - return DictionaryEntry(W, Positions[Rand(NumPositions)]); - } - DictionaryEntry DE(W); - return DE; -} - - -template -DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( - T Arg1, T Arg2, const uint8_t *Data, size_t Size) { - if (Rand.RandBool()) Arg1 = Bswap(Arg1); - if (Rand.RandBool()) Arg2 = Bswap(Arg2); - T Arg1Mutation = Arg1 + Rand(-1, 1); - T Arg2Mutation = Arg2 + Rand(-1, 1); - return MakeDictionaryEntryFromCMP(&Arg1, &Arg2, &Arg1Mutation, &Arg2Mutation, - sizeof(Arg1), Data, Size); -} - -DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( - const Word &Arg1, const Word &Arg2, const uint8_t *Data, size_t Size) { - return MakeDictionaryEntryFromCMP(Arg1.data(), Arg2.data(), Arg1.data(), - Arg2.data(), Arg1.size(), Data, Size); -} - -size_t MutationDispatcher::Mutate_AddWordFromTORC( - uint8_t *Data, size_t Size, size_t MaxSize) { - Word W; - DictionaryEntry DE; - switch (Rand(4)) { - case 0: { - auto X = TPC.TORC8.Get(Rand.Rand()); - DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); - } break; - case 1: { - auto X = TPC.TORC4.Get(Rand.Rand()); - if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool()) - DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data, Size); - else - DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); - } break; - case 2: { - auto X = TPC.TORCW.Get(Rand.Rand()); - DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); - } break; - case 3: if (Options.UseMemmem) { - auto X = TPC.MMT.Get(Rand.Rand()); - DE = DictionaryEntry(X); - } break; - default: - assert(0); - } - if (!DE.GetW().size()) return 0; - Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE); - if (!Size) return 0; - DictionaryEntry &DERef = - CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ % - kCmpDictionaryEntriesDequeSize]; - DERef = DE; - CurrentDictionaryEntrySequence.push_back(&DERef); - return Size; -} - -size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary( - uint8_t *Data, size_t Size, size_t MaxSize) { - return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize); -} - -size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data, - size_t Size, size_t MaxSize) { - if (Size > MaxSize) return 0; - if (D.empty()) return 0; - DictionaryEntry &DE = D[Rand(D.size())]; - Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE); - if (!Size) return 0; - DE.IncUseCount(); - CurrentDictionaryEntrySequence.push_back(&DE); - return Size; -} - -// Overwrites part of To[0,ToSize) with a part of From[0,FromSize). -// Returns ToSize. -size_t MutationDispatcher::CopyPartOf(const uint8_t *From, size_t FromSize, - uint8_t *To, size_t ToSize) { - // Copy From[FromBeg, FromBeg + CopySize) into To[ToBeg, ToBeg + CopySize). - size_t ToBeg = Rand(ToSize); - size_t CopySize = Rand(ToSize - ToBeg) + 1; - assert(ToBeg + CopySize <= ToSize); - CopySize = std::min(CopySize, FromSize); - size_t FromBeg = Rand(FromSize - CopySize + 1); - assert(FromBeg + CopySize <= FromSize); - memmove(To + ToBeg, From + FromBeg, CopySize); - return ToSize; -} - -// Inserts part of From[0,ToSize) into To. -// Returns new size of To on success or 0 on failure. -size_t MutationDispatcher::InsertPartOf(const uint8_t *From, size_t FromSize, - uint8_t *To, size_t ToSize, - size_t MaxToSize) { - if (ToSize >= MaxToSize) return 0; - size_t AvailableSpace = MaxToSize - ToSize; - size_t MaxCopySize = std::min(AvailableSpace, FromSize); - size_t CopySize = Rand(MaxCopySize) + 1; - size_t FromBeg = Rand(FromSize - CopySize + 1); - assert(FromBeg + CopySize <= FromSize); - size_t ToInsertPos = Rand(ToSize + 1); - assert(ToInsertPos + CopySize <= MaxToSize); - size_t TailSize = ToSize - ToInsertPos; - if (To == From) { - MutateInPlaceHere.resize(MaxToSize); - memcpy(MutateInPlaceHere.data(), From + FromBeg, CopySize); - memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize); - memmove(To + ToInsertPos, MutateInPlaceHere.data(), CopySize); - } else { - memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize); - memmove(To + ToInsertPos, From + FromBeg, CopySize); - } - return ToSize + CopySize; -} - -size_t MutationDispatcher::Mutate_CopyPart(uint8_t *Data, size_t Size, - size_t MaxSize) { - if (Size > MaxSize || Size == 0) return 0; - if (Rand.RandBool()) - return CopyPartOf(Data, Size, Data, Size); - else - return InsertPartOf(Data, Size, Data, Size, MaxSize); -} - -size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, - size_t MaxSize) { - if (Size > MaxSize) return 0; - size_t B = Rand(Size); - while (B < Size && !isdigit(Data[B])) B++; - if (B == Size) return 0; - size_t E = B; - while (E < Size && isdigit(Data[E])) E++; - assert(B < E); - // now we have digits in [B, E). - // strtol and friends don't accept non-zero-teminated data, parse it manually. - uint64_t Val = Data[B] - '0'; - for (size_t i = B + 1; i < E; i++) - Val = Val * 10 + Data[i] - '0'; - - // Mutate the integer value. - switch(Rand(5)) { - case 0: Val++; break; - case 1: Val--; break; - case 2: Val /= 2; break; - case 3: Val *= 2; break; - case 4: Val = Rand(Val * Val); break; - default: assert(0); - } - // Just replace the bytes with the new ones, don't bother moving bytes. - for (size_t i = B; i < E; i++) { - size_t Idx = E + B - i - 1; - assert(Idx >= B && Idx < E); - Data[Idx] = (Val % 10) + '0'; - Val /= 10; - } - return Size; -} - -template -size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) { - if (Size < sizeof(T)) return 0; - size_t Off = Rand(Size - sizeof(T) + 1); - assert(Off + sizeof(T) <= Size); - T Val; - if (Off < 64 && !Rand(4)) { - Val = Size; - if (Rand.RandBool()) - Val = Bswap(Val); - } else { - memcpy(&Val, Data + Off, sizeof(Val)); - T Add = Rand(21); - Add -= 10; - if (Rand.RandBool()) - Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes. - else - Val = Val + Add; // Add assuming current endiannes. - if (Add == 0 || Rand.RandBool()) // Maybe negate. - Val = -Val; - } - memcpy(Data + Off, &Val, sizeof(Val)); - return Size; -} - -size_t MutationDispatcher::Mutate_ChangeBinaryInteger(uint8_t *Data, - size_t Size, - size_t MaxSize) { - if (Size > MaxSize) return 0; - switch (Rand(4)) { - case 3: return ChangeBinaryInteger(Data, Size, Rand); - case 2: return ChangeBinaryInteger(Data, Size, Rand); - case 1: return ChangeBinaryInteger(Data, Size, Rand); - case 0: return ChangeBinaryInteger(Data, Size, Rand); - default: assert(0); - } - return 0; -} - -size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size, - size_t MaxSize) { - if (Size > MaxSize) return 0; - if (!Corpus || Corpus->size() < 2 || Size == 0) return 0; - size_t Idx = Rand(Corpus->size()); - const Unit &O = (*Corpus)[Idx]; - if (O.empty()) return 0; - MutateInPlaceHere.resize(MaxSize); - auto &U = MutateInPlaceHere; - size_t NewSize = 0; - switch(Rand(3)) { - case 0: - NewSize = CrossOver(Data, Size, O.data(), O.size(), U.data(), U.size()); - break; - case 1: - NewSize = InsertPartOf(O.data(), O.size(), U.data(), U.size(), MaxSize); - if (!NewSize) - NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size()); - break; - case 2: - NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size()); - break; - default: assert(0); - } - assert(NewSize > 0 && "CrossOver returned empty unit"); - assert(NewSize <= MaxSize && "CrossOver returned overisized unit"); - memcpy(Data, U.data(), NewSize); - return NewSize; -} - -void MutationDispatcher::StartMutationSequence() { - CurrentMutatorSequence.clear(); - CurrentDictionaryEntrySequence.clear(); -} - -// Copy successful dictionary entries to PersistentAutoDictionary. -void MutationDispatcher::RecordSuccessfulMutationSequence() { - for (auto DE : CurrentDictionaryEntrySequence) { - // PersistentAutoDictionary.AddWithSuccessCountOne(DE); - DE->IncSuccessCount(); - assert(DE->GetW().size()); - // Linear search is fine here as this happens seldom. - if (!PersistentAutoDictionary.ContainsWord(DE->GetW())) - PersistentAutoDictionary.push_back({DE->GetW(), 1}); - } -} - -void MutationDispatcher::PrintRecommendedDictionary() { - std::vector V; - for (auto &DE : PersistentAutoDictionary) - if (!ManualDictionary.ContainsWord(DE.GetW())) - V.push_back(DE); - if (V.empty()) return; - Printf("###### Recommended dictionary. ######\n"); - for (auto &DE: V) { - assert(DE.GetW().size()); - Printf("\""); - PrintASCII(DE.GetW(), "\""); - Printf(" # Uses: %zd\n", DE.GetUseCount()); - } - Printf("###### End of recommended dictionary. ######\n"); -} - -void MutationDispatcher::PrintMutationSequence() { - Printf("MS: %zd ", CurrentMutatorSequence.size()); - for (auto M : CurrentMutatorSequence) - Printf("%s-", M.Name); - if (!CurrentDictionaryEntrySequence.empty()) { - Printf(" DE: "); - for (auto DE : CurrentDictionaryEntrySequence) { - Printf("\""); - PrintASCII(DE->GetW(), "\"-"); - } - } -} - -size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { - return MutateImpl(Data, Size, MaxSize, Mutators); -} - -size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size, - size_t MaxSize) { - return MutateImpl(Data, Size, MaxSize, DefaultMutators); -} - -// Mutates Data in place, returns new size. -size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size, - size_t MaxSize, - const std::vector &Mutators) { - assert(MaxSize > 0); - // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize), - // in which case they will return 0. - // Try several times before returning un-mutated data. - for (int Iter = 0; Iter < 100; Iter++) { - auto M = Mutators[Rand(Mutators.size())]; - size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize); - if (NewSize && NewSize <= MaxSize) { - if (Options.OnlyASCII) - ToASCII(Data, NewSize); - CurrentMutatorSequence.push_back(M); - return NewSize; - } - } - *Data = ' '; - return 1; // Fallback, should not happen frequently. -} - -void MutationDispatcher::AddWordToManualDictionary(const Word &W) { - ManualDictionary.push_back( - {W, std::numeric_limits::max()}); -} - -} // namespace fuzzer Index: lib/fuzzer/FuzzerOptions.h =================================================================== --- lib/fuzzer/FuzzerOptions.h +++ /dev/null @@ -1,68 +0,0 @@ -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// fuzzer::FuzzingOptions -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_OPTIONS_H -#define LLVM_FUZZER_OPTIONS_H - -#include "FuzzerDefs.h" - -namespace fuzzer { - -struct FuzzingOptions { - int Verbosity = 1; - size_t MaxLen = 0; - bool ExperimentalLenControl = false; - int UnitTimeoutSec = 300; - int TimeoutExitCode = 77; - int ErrorExitCode = 77; - int MaxTotalTimeSec = 0; - int RssLimitMb = 0; - bool DoCrossOver = true; - int MutateDepth = 5; - bool UseCounters = false; - bool UseIndirCalls = true; - bool UseMemmem = true; - bool UseCmp = false; - bool UseValueProfile = false; - bool Shrink = false; - bool ReduceInputs = false; - int ReloadIntervalSec = 1; - bool ShuffleAtStartUp = true; - bool PreferSmall = true; - size_t MaxNumberOfRuns = -1L; - int ReportSlowUnits = 10; - bool OnlyASCII = false; - std::string OutputCorpus; - std::string ArtifactPrefix = "./"; - std::string ExactArtifactPath; - std::string ExitOnSrcPos; - std::string ExitOnItem; - bool SaveArtifacts = true; - bool PrintNEW = true; // Print a status line when new units are found; - bool PrintNewCovPcs = false; - bool PrintFinalStats = false; - bool PrintCorpusStats = false; - bool PrintCoverage = false; - bool DumpCoverage = false; - bool DetectLeaks = true; - int TraceMalloc = 0; - bool HandleAbrt = false; - bool HandleBus = false; - bool HandleFpe = false; - bool HandleIll = false; - bool HandleInt = false; - bool HandleSegv = false; - bool HandleTerm = false; - bool HandleXfsz = false; -}; - -} // namespace fuzzer - -#endif // LLVM_FUZZER_OPTIONS_H Index: lib/fuzzer/FuzzerRandom.h =================================================================== --- lib/fuzzer/FuzzerRandom.h +++ /dev/null @@ -1,34 +0,0 @@ -//===- FuzzerRandom.h - Internal header for the Fuzzer ----------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// fuzzer::Random -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_RANDOM_H -#define LLVM_FUZZER_RANDOM_H - -#include - -namespace fuzzer { -class Random : public std::mt19937 { - public: - Random(unsigned int seed) : std::mt19937(seed) {} - result_type operator()() { return this->std::mt19937::operator()(); } - size_t Rand() { return this->operator()(); } - size_t RandBool() { return Rand() % 2; } - size_t operator()(size_t n) { return n ? Rand() % n : 0; } - intptr_t operator()(intptr_t From, intptr_t To) { - assert(From < To); - intptr_t RangeSize = To - From + 1; - return operator()(RangeSize) + From; - } -}; - -} // namespace fuzzer - -#endif // LLVM_FUZZER_RANDOM_H Index: lib/fuzzer/FuzzerSHA1.h =================================================================== --- lib/fuzzer/FuzzerSHA1.h +++ /dev/null @@ -1,33 +0,0 @@ -//===- FuzzerSHA1.h - Internal header for the SHA1 utils --------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// SHA1 utils. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_SHA1_H -#define LLVM_FUZZER_SHA1_H - -#include "FuzzerDefs.h" -#include -#include - -namespace fuzzer { - -// Private copy of SHA1 implementation. -static const int kSHA1NumBytes = 20; - -// Computes SHA1 hash of 'Len' bytes in 'Data', writes kSHA1NumBytes to 'Out'. -void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out); - -std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]); - -std::string Hash(const Unit &U); - -} // namespace fuzzer - -#endif // LLVM_FUZZER_SHA1_H Index: lib/fuzzer/FuzzerSHA1.cpp =================================================================== --- lib/fuzzer/FuzzerSHA1.cpp +++ /dev/null @@ -1,222 +0,0 @@ -//===- FuzzerSHA1.h - Private copy of the SHA1 implementation ---*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// This code is taken from public domain -// (http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c) -// and modified by adding anonymous namespace, adding an interface -// function fuzzer::ComputeSHA1() and removing unnecessary code. -// -// lib/Fuzzer can not use SHA1 implementation from openssl because -// openssl may not be available and because we may be fuzzing openssl itself. -// For the same reason we do not want to depend on SHA1 from LLVM tree. -//===----------------------------------------------------------------------===// - -#include "FuzzerSHA1.h" -#include "FuzzerDefs.h" - -/* This code is public-domain - it is based on libcrypt - * placed in the public domain by Wei Dai and other contributors. - */ - -#include -#include -#include -#include - -namespace { // Added for LibFuzzer - -#ifdef __BIG_ENDIAN__ -# define SHA_BIG_ENDIAN -#elif defined __LITTLE_ENDIAN__ -/* override */ -#elif defined __BYTE_ORDER -# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -# define SHA_BIG_ENDIAN -# endif -#else // ! defined __LITTLE_ENDIAN__ -# include // machine/endian.h -# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -# define SHA_BIG_ENDIAN -# endif -#endif - - -/* header */ - -#define HASH_LENGTH 20 -#define BLOCK_LENGTH 64 - -typedef struct sha1nfo { - uint32_t buffer[BLOCK_LENGTH/4]; - uint32_t state[HASH_LENGTH/4]; - uint32_t byteCount; - uint8_t bufferOffset; - uint8_t keyBuffer[BLOCK_LENGTH]; - uint8_t innerHash[HASH_LENGTH]; -} sha1nfo; - -/* public API - prototypes - TODO: doxygen*/ - -/** - */ -void sha1_init(sha1nfo *s); -/** - */ -void sha1_writebyte(sha1nfo *s, uint8_t data); -/** - */ -void sha1_write(sha1nfo *s, const char *data, size_t len); -/** - */ -uint8_t* sha1_result(sha1nfo *s); - - -/* code */ -#define SHA1_K0 0x5a827999 -#define SHA1_K20 0x6ed9eba1 -#define SHA1_K40 0x8f1bbcdc -#define SHA1_K60 0xca62c1d6 - -void sha1_init(sha1nfo *s) { - s->state[0] = 0x67452301; - s->state[1] = 0xefcdab89; - s->state[2] = 0x98badcfe; - s->state[3] = 0x10325476; - s->state[4] = 0xc3d2e1f0; - s->byteCount = 0; - s->bufferOffset = 0; -} - -uint32_t sha1_rol32(uint32_t number, uint8_t bits) { - return ((number << bits) | (number >> (32-bits))); -} - -void sha1_hashBlock(sha1nfo *s) { - uint8_t i; - uint32_t a,b,c,d,e,t; - - a=s->state[0]; - b=s->state[1]; - c=s->state[2]; - d=s->state[3]; - e=s->state[4]; - for (i=0; i<80; i++) { - if (i>=16) { - t = s->buffer[(i+13)&15] ^ s->buffer[(i+8)&15] ^ s->buffer[(i+2)&15] ^ s->buffer[i&15]; - s->buffer[i&15] = sha1_rol32(t,1); - } - if (i<20) { - t = (d ^ (b & (c ^ d))) + SHA1_K0; - } else if (i<40) { - t = (b ^ c ^ d) + SHA1_K20; - } else if (i<60) { - t = ((b & c) | (d & (b | c))) + SHA1_K40; - } else { - t = (b ^ c ^ d) + SHA1_K60; - } - t+=sha1_rol32(a,5) + e + s->buffer[i&15]; - e=d; - d=c; - c=sha1_rol32(b,30); - b=a; - a=t; - } - s->state[0] += a; - s->state[1] += b; - s->state[2] += c; - s->state[3] += d; - s->state[4] += e; -} - -void sha1_addUncounted(sha1nfo *s, uint8_t data) { - uint8_t * const b = (uint8_t*) s->buffer; -#ifdef SHA_BIG_ENDIAN - b[s->bufferOffset] = data; -#else - b[s->bufferOffset ^ 3] = data; -#endif - s->bufferOffset++; - if (s->bufferOffset == BLOCK_LENGTH) { - sha1_hashBlock(s); - s->bufferOffset = 0; - } -} - -void sha1_writebyte(sha1nfo *s, uint8_t data) { - ++s->byteCount; - sha1_addUncounted(s, data); -} - -void sha1_write(sha1nfo *s, const char *data, size_t len) { - for (;len--;) sha1_writebyte(s, (uint8_t) *data++); -} - -void sha1_pad(sha1nfo *s) { - // Implement SHA-1 padding (fips180-2 §5.1.1) - - // Pad with 0x80 followed by 0x00 until the end of the block - sha1_addUncounted(s, 0x80); - while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00); - - // Append length in the last 8 bytes - sha1_addUncounted(s, 0); // We're only using 32 bit lengths - sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths - sha1_addUncounted(s, 0); // So zero pad the top bits - sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8 - sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as - sha1_addUncounted(s, s->byteCount >> 13); // byte. - sha1_addUncounted(s, s->byteCount >> 5); - sha1_addUncounted(s, s->byteCount << 3); -} - -uint8_t* sha1_result(sha1nfo *s) { - // Pad to complete the last block - sha1_pad(s); - -#ifndef SHA_BIG_ENDIAN - // Swap byte order back - int i; - for (i=0; i<5; i++) { - s->state[i]= - (((s->state[i])<<24)& 0xff000000) - | (((s->state[i])<<8) & 0x00ff0000) - | (((s->state[i])>>8) & 0x0000ff00) - | (((s->state[i])>>24)& 0x000000ff); - } -#endif - - // Return pointer to hash (20 characters) - return (uint8_t*) s->state; -} - -} // namespace; Added for LibFuzzer - -namespace fuzzer { - -// The rest is added for LibFuzzer -void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out) { - sha1nfo s; - sha1_init(&s); - sha1_write(&s, (const char*)Data, Len); - memcpy(Out, sha1_result(&s), HASH_LENGTH); -} - -std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]) { - std::stringstream SS; - for (int i = 0; i < kSHA1NumBytes; i++) - SS << std::hex << std::setfill('0') << std::setw(2) << (unsigned)Sha1[i]; - return SS.str(); -} - -std::string Hash(const Unit &U) { - uint8_t Hash[kSHA1NumBytes]; - ComputeSHA1(U.data(), U.size(), Hash); - return Sha1ToString(Hash); -} - -} Index: lib/fuzzer/FuzzerShmem.h =================================================================== --- lib/fuzzer/FuzzerShmem.h +++ /dev/null @@ -1,69 +0,0 @@ -//===- FuzzerShmem.h - shared memory interface ------------------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// SharedMemoryRegion -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_SHMEM_H -#define LLVM_FUZZER_SHMEM_H - -#include -#include -#include - -#include "FuzzerDefs.h" - -namespace fuzzer { - -class SharedMemoryRegion { - public: - bool Create(const char *Name); - bool Open(const char *Name); - bool Destroy(const char *Name); - uint8_t *GetData() { return Data; } - void PostServer() {Post(0);} - void WaitServer() {Wait(0);} - void PostClient() {Post(1);} - void WaitClient() {Wait(1);} - - size_t WriteByteArray(const uint8_t *Bytes, size_t N) { - assert(N <= kShmemSize - sizeof(N)); - memcpy(GetData(), &N, sizeof(N)); - memcpy(GetData() + sizeof(N), Bytes, N); - assert(N == ReadByteArraySize()); - return N; - } - size_t ReadByteArraySize() { - size_t Res; - memcpy(&Res, GetData(), sizeof(Res)); - return Res; - } - uint8_t *GetByteArray() { return GetData() + sizeof(size_t); } - - bool IsServer() const { return Data && IAmServer; } - bool IsClient() const { return Data && !IAmServer; } - -private: - - static const size_t kShmemSize = 1 << 22; - bool IAmServer; - std::string Path(const char *Name); - std::string SemName(const char *Name, int Idx); - void Post(int Idx); - void Wait(int Idx); - - bool Map(int fd); - uint8_t *Data = nullptr; - void *Semaphore[2]; -}; - -extern SharedMemoryRegion SMR; - -} // namespace fuzzer - -#endif // LLVM_FUZZER_SHMEM_H Index: lib/fuzzer/FuzzerShmemPosix.cpp =================================================================== --- lib/fuzzer/FuzzerShmemPosix.cpp +++ /dev/null @@ -1,103 +0,0 @@ -//===- FuzzerShmemPosix.cpp - Posix shared memory ---------------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// SharedMemoryRegion -//===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" -#if LIBFUZZER_POSIX - -#include "FuzzerIO.h" -#include "FuzzerShmem.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace fuzzer { - -std::string SharedMemoryRegion::Path(const char *Name) { - return DirPlusFile(TmpDir(), Name); -} - -std::string SharedMemoryRegion::SemName(const char *Name, int Idx) { - std::string Res(Name); - return Res + (char)('0' + Idx); -} - -bool SharedMemoryRegion::Map(int fd) { - Data = - (uint8_t *)mmap(0, kShmemSize, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0); - if (Data == (uint8_t*)-1) - return false; - return true; -} - -bool SharedMemoryRegion::Create(const char *Name) { - int fd = open(Path(Name).c_str(), O_CREAT | O_RDWR, 0777); - if (fd < 0) return false; - if (ftruncate(fd, kShmemSize) < 0) return false; - if (!Map(fd)) - return false; - for (int i = 0; i < 2; i++) { - sem_unlink(SemName(Name, i).c_str()); - Semaphore[i] = sem_open(SemName(Name, i).c_str(), O_CREAT, 0644, 0); - if (Semaphore[i] == (void *)-1) - return false; - } - IAmServer = true; - return true; -} - -bool SharedMemoryRegion::Open(const char *Name) { - int fd = open(Path(Name).c_str(), O_RDWR); - if (fd < 0) return false; - struct stat stat_res; - if (0 != fstat(fd, &stat_res)) - return false; - assert(stat_res.st_size == kShmemSize); - if (!Map(fd)) - return false; - for (int i = 0; i < 2; i++) { - Semaphore[i] = sem_open(SemName(Name, i).c_str(), 0); - if (Semaphore[i] == (void *)-1) - return false; - } - IAmServer = false; - return true; -} - -bool SharedMemoryRegion::Destroy(const char *Name) { - return 0 == unlink(Path(Name).c_str()); -} - -void SharedMemoryRegion::Post(int Idx) { - assert(Idx == 0 || Idx == 1); - sem_post((sem_t*)Semaphore[Idx]); -} - -void SharedMemoryRegion::Wait(int Idx) { - assert(Idx == 0 || Idx == 1); - for (int i = 0; i < 10 && sem_wait((sem_t*)Semaphore[Idx]); i++) { - // sem_wait may fail if interrupted by a signal. - sleep(i); - if (i) - Printf("%s: sem_wait[%d] failed %s\n", i < 9 ? "WARNING" : "ERROR", i, - strerror(errno)); - if (i == 9) abort(); - } -} - -} // namespace fuzzer - -#endif // LIBFUZZER_POSIX Index: lib/fuzzer/FuzzerShmemWindows.cpp =================================================================== --- lib/fuzzer/FuzzerShmemWindows.cpp +++ /dev/null @@ -1,64 +0,0 @@ -//===- FuzzerShmemWindows.cpp - Posix shared memory -------------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// SharedMemoryRegion -//===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" -#if LIBFUZZER_WINDOWS - -#include "FuzzerIO.h" -#include "FuzzerShmem.h" - -#include -#include -#include -#include - -namespace fuzzer { - -std::string SharedMemoryRegion::Path(const char *Name) { - return DirPlusFile(TmpDir(), Name); -} - -std::string SharedMemoryRegion::SemName(const char *Name, int Idx) { - std::string Res(Name); - return Res + (char)('0' + Idx); -} - -bool SharedMemoryRegion::Map(int fd) { - assert(0 && "UNIMPLEMENTED"); - return false; -} - -bool SharedMemoryRegion::Create(const char *Name) { - assert(0 && "UNIMPLEMENTED"); - return false; -} - -bool SharedMemoryRegion::Open(const char *Name) { - assert(0 && "UNIMPLEMENTED"); - return false; -} - -bool SharedMemoryRegion::Destroy(const char *Name) { - assert(0 && "UNIMPLEMENTED"); - return false; -} - -void SharedMemoryRegion::Post(int Idx) { - assert(0 && "UNIMPLEMENTED"); -} - -void SharedMemoryRegion::Wait(int Idx) { - Semaphore[1] = nullptr; - assert(0 && "UNIMPLEMENTED"); -} - -} // namespace fuzzer - -#endif // LIBFUZZER_WINDOWS Index: lib/fuzzer/FuzzerTracePC.h =================================================================== --- lib/fuzzer/FuzzerTracePC.h +++ /dev/null @@ -1,253 +0,0 @@ -//===- FuzzerTracePC.h - Internal header for the Fuzzer ---------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// fuzzer::TracePC -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_TRACE_PC -#define LLVM_FUZZER_TRACE_PC - -#include "FuzzerDefs.h" -#include "FuzzerDictionary.h" -#include "FuzzerValueBitMap.h" - -#include - -namespace fuzzer { - -// TableOfRecentCompares (TORC) remembers the most recently performed -// comparisons of type T. -// We record the arguments of CMP instructions in this table unconditionally -// because it seems cheaper this way than to compute some expensive -// conditions inside __sanitizer_cov_trace_cmp*. -// After the unit has been executed we may decide to use the contents of -// this table to populate a Dictionary. -template -struct TableOfRecentCompares { - static const size_t kSize = kSizeT; - struct Pair { - T A, B; - }; - ATTRIBUTE_NO_SANITIZE_ALL - void Insert(size_t Idx, const T &Arg1, const T &Arg2) { - Idx = Idx % kSize; - Table[Idx].A = Arg1; - Table[Idx].B = Arg2; - } - - Pair Get(size_t I) { return Table[I % kSize]; } - - Pair Table[kSize]; -}; - -template -struct MemMemTable { - static const size_t kSize = kSizeT; - Word MemMemWords[kSize]; - Word EmptyWord; - - void Add(const uint8_t *Data, size_t Size) { - if (Size <= 2) return; - Size = std::min(Size, Word::GetMaxSize()); - size_t Idx = SimpleFastHash(Data, Size) % kSize; - MemMemWords[Idx].Set(Data, Size); - } - const Word &Get(size_t Idx) { - for (size_t i = 0; i < kSize; i++) { - const Word &W = MemMemWords[(Idx + i) % kSize]; - if (W.size()) return W; - } - EmptyWord.Set(nullptr, 0); - return EmptyWord; - } -}; - -class TracePC { - public: - static const size_t kNumPCs = 1 << 21; - // 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 HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop); - void HandlePCsInit(const uint8_t *Start, const uint8_t *Stop); - void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee); - 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; } - void SetPrintNewPCs(bool P) { DoPrintNewPCs = P; } - void UpdateObservedPCs(); - template void CollectFeatures(Callback CB) const; - - void ResetMaps() { - ValueProfileMap.Reset(); - if (NumModules) - memset(Counters(), 0, GetNumPCs()); - ClearExtraCounters(); - ClearInlineCounters(); - } - - void ClearInlineCounters(); - - void UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize); - void PrintFeatureSet(); - - void PrintModuleInfo(); - - void PrintCoverage(); - void DumpCoverage(); - - void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2, - size_t n, bool StopAtZero); - - TableOfRecentCompares TORC4; - TableOfRecentCompares TORC8; - TableOfRecentCompares TORCW; - MemMemTable<1024> MMT; - - size_t GetNumPCs() const { - return NumGuards == 0 ? (1 << kTracePcBits) : Min(kNumPCs, NumGuards + 1); - } - uintptr_t GetPC(size_t Idx) { - assert(Idx < GetNumPCs()); - return PCs()[Idx]; - } - - void RecordCurrentStack() { - uintptr_t Stack = GetCurrentStack(); - if (Stack < LowestStack) - LowestStack = Stack; - } - void RecordInitialStack() { - InitialStack = GetCurrentStack(); - LowestStack = InitialStack; - } - uintptr_t GetCurrentStack() const { - return reinterpret_cast(__builtin_frame_address(0)); - } - uintptr_t GetMaxStackOffset() const { return InitialStack - LowestStack; } - - template - void ForEachObservedPC(CallBack CB) { - for (auto PC : ObservedPCs) - CB(PC); - } - -private: - bool UseCounters = false; - bool UseValueProfile = false; - bool DoPrintNewPCs = false; - - struct Module { - uint32_t *Start, *Stop; - }; - - Module Modules[4096]; - 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; - - struct { const uintptr_t *Start, *Stop; } ModulePCTable[4096]; - size_t NumPCTables; - size_t NumPCsInPCTables; - - uint8_t *Counters() const; - uintptr_t *PCs() const; - - std::set ObservedPCs; - - ValueBitMap ValueProfileMap; - uintptr_t InitialStack, LowestStack; // Assume stack grows down. -}; - -template -// void Callback(size_t FirstFeature, size_t Idx, uint8_t Value); -ATTRIBUTE_NO_SANITIZE_ALL -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); - 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) -ATTRIBUTE_NO_SANITIZE_ADDRESS -__attribute__((noinline)) -void TracePC::CollectFeatures(Callback HandleFeature) const { - uint8_t *Counters = this->Counters(); - size_t N = GetNumPCs(); - auto Handle8bitCounter = [&](size_t FirstFeature, - size_t Idx, uint8_t Counter) { - assert(Counter); - unsigned Bit = 0; - /**/ if (Counter >= 128) Bit = 7; - else if (Counter >= 32) Bit = 6; - else if (Counter >= 16) Bit = 5; - else if (Counter >= 8) Bit = 4; - else if (Counter >= 4) Bit = 3; - else if (Counter >= 3) Bit = 2; - else if (Counter >= 2) Bit = 1; - HandleFeature(FirstFeature + Idx * 8 + Bit); - }; - - size_t FirstFeature = 0; - - if (!NumInline8bitCounters) { - ForEachNonZeroByte(Counters, Counters + N, FirstFeature, Handle8bitCounter); - FirstFeature += N * 8; - } - - if (NumInline8bitCounters) { - 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); - FirstFeature += (ExtraCountersEnd() - ExtraCountersBegin()) * 8; - - if (UseValueProfile) { - ValueProfileMap.ForEach([&](size_t Idx) { - HandleFeature(FirstFeature + Idx); - }); - FirstFeature += ValueProfileMap.SizeInBits(); - } - - if (auto MaxStackOffset = GetMaxStackOffset()) - HandleFeature(FirstFeature + MaxStackOffset); -} - -extern TracePC TPC; - -} // namespace fuzzer - -#endif // LLVM_FUZZER_TRACE_PC Index: lib/fuzzer/FuzzerTracePC.cpp =================================================================== --- lib/fuzzer/FuzzerTracePC.cpp +++ /dev/null @@ -1,566 +0,0 @@ -//===- 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_guard[_init], -// the callback required for -fsanitize-coverage=trace-pc-guard instrumentation. -// -//===----------------------------------------------------------------------===// - -#include "FuzzerTracePC.h" -#include "FuzzerCorpus.h" -#include "FuzzerDefs.h" -#include "FuzzerDictionary.h" -#include "FuzzerExtFunctions.h" -#include "FuzzerIO.h" -#include "FuzzerUtil.h" -#include "FuzzerValueBitMap.h" -#include - -// The coverage counters and PCs. -// These are declared as global variables named "__sancov_*" to simplify -// experiments with inlined instrumentation. -alignas(64) ATTRIBUTE_INTERFACE -uint8_t __sancov_trace_pc_guard_8bit_counters[fuzzer::TracePC::kNumPCs]; - -ATTRIBUTE_INTERFACE -uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs]; - -namespace fuzzer { - -TracePC TPC; - -int ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr; - -uint8_t *TracePC::Counters() const { - return __sancov_trace_pc_guard_8bit_counters; -} - -uintptr_t *TracePC::PCs() const { - return __sancov_trace_pc_pcs; -} - -size_t TracePC::GetTotalPCCoverage() { - if (ObservedPCs.size()) - return ObservedPCs.size(); - size_t Res = 0; - for (size_t i = 1, N = GetNumPCs(); i < N; i++) - if (PCs()[i]) - Res++; - 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::HandlePCsInit(const uint8_t *Start, const uint8_t *Stop) { - const uintptr_t *B = reinterpret_cast(Start); - const uintptr_t *E = reinterpret_cast(Stop); - if (NumPCTables && ModulePCTable[NumPCTables - 1].Start == B) return; - assert(NumPCTables < sizeof(ModulePCTable) / sizeof(ModulePCTable[0])); - ModulePCTable[NumPCTables++] = {B, E}; - NumPCsInPCTables += E - B; -} - -void TracePC::HandleInit(uint32_t *Start, uint32_t *Stop) { - if (Start == Stop || *Start) return; - assert(NumModules < sizeof(Modules) / sizeof(Modules[0])); - for (uint32_t *P = Start; P < Stop; P++) { - NumGuards++; - if (NumGuards == kNumPCs) { - RawPrint( - "WARNING: The binary has too many instrumented PCs.\n" - " You may want to reduce the size of the binary\n" - " for more efficient fuzzing and precise coverage data\n"); - } - *P = NumGuards % kNumPCs; - } - Modules[NumModules].Start = Start; - Modules[NumModules].Stop = Stop; - NumModules++; -} - -void TracePC::PrintModuleInfo() { - if (NumGuards) { - Printf("INFO: Loaded %zd modules (%zd guards): ", NumModules, NumGuards); - for (size_t i = 0; i < NumModules; i++) - Printf("%zd [%p, %p), ", Modules[i].Stop - Modules[i].Start, - Modules[i].Start, Modules[i].Stop); - Printf("\n"); - } - if (NumModulesWithInline8bitCounters) { - Printf("INFO: Loaded %zd modules (%zd inline 8-bit counters): ", - NumModulesWithInline8bitCounters, NumInline8bitCounters); - for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) - Printf("%zd [%p, %p), ", ModuleCounters[i].Stop - ModuleCounters[i].Start, - ModuleCounters[i].Start, ModuleCounters[i].Stop); - Printf("\n"); - } - if (NumPCTables) { - Printf("INFO: Loaded %zd PC tables (%zd PCs): ", NumPCTables, - NumPCsInPCTables); - for (size_t i = 0; i < NumPCTables; i++) { - Printf("%zd [%p,%p), ", ModulePCTable[i].Stop - ModulePCTable[i].Start, - ModulePCTable[i].Start, ModulePCTable[i].Stop); - } - Printf("\n"); - - if ((NumGuards && NumGuards != NumPCsInPCTables) || - (NumInline8bitCounters && NumInline8bitCounters != NumPCsInPCTables)) { - Printf("ERROR: The size of coverage PC tables does not match the" - " number of instrumented PCs. This might be a bug in the compiler," - " please contact the libFuzzer developers.\n"); - _Exit(1); - } - } -} - -ATTRIBUTE_NO_SANITIZE_ALL -void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) { - const uintptr_t kBits = 12; - const uintptr_t kMask = (1 << kBits) - 1; - uintptr_t Idx = (Caller & kMask) | ((Callee & kMask) << kBits); - ValueProfileMap.AddValueModPrime(Idx); -} - -void TracePC::UpdateObservedPCs() { - if (NumPCsInPCTables) { - auto Observe = [&](uintptr_t PC) { - bool Inserted = ObservedPCs.insert(PC).second; - if (Inserted && DoPrintNewPCs) - PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PC + 1); - }; - - if (NumInline8bitCounters == NumPCsInPCTables) { - for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { - uint8_t *Beg = ModuleCounters[i].Start; - size_t Size = ModuleCounters[i].Stop - Beg; - assert(Size == - (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); - for (size_t j = 0; j < Size; j++) - if (Beg[j]) - Observe(ModulePCTable[i].Start[j]); - } - } else if (NumGuards == NumPCsInPCTables) { - size_t GuardIdx = 1; - for (size_t i = 0; i < NumModules; i++) { - uint32_t *Beg = Modules[i].Start; - size_t Size = Modules[i].Stop - Beg; - assert(Size == - (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start)); - for (size_t j = 0; j < Size; j++, GuardIdx++) - if (Counters()[GuardIdx]) - Observe(ModulePCTable[i].Start[j]); - } - } - } -} - -inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) { - // TODO: this implementation is x86 only. - // see sanitizer_common GetPreviousInstructionPc for full implementation. - return PC - 1; -} - -inline ALWAYS_INLINE uintptr_t GetNextInstructionPc(uintptr_t PC) { - // TODO: this implementation is x86 only. - // see sanitizer_common GetPreviousInstructionPc for full implementation. - return PC + 1; -} - -static std::string GetModuleName(uintptr_t PC) { - char ModulePathRaw[4096] = ""; // What's PATH_MAX in portable C++? - void *OffsetRaw = nullptr; - if (!EF->__sanitizer_get_module_and_offset_for_pc( - reinterpret_cast(PC), ModulePathRaw, - sizeof(ModulePathRaw), &OffsetRaw)) - return ""; - return ModulePathRaw; -} - -void TracePC::PrintCoverage() { - if (!EF->__sanitizer_symbolize_pc || - !EF->__sanitizer_get_module_and_offset_for_pc) { - Printf("INFO: __sanitizer_symbolize_pc or " - "__sanitizer_get_module_and_offset_for_pc is not available," - " not printing coverage\n"); - return; - } - Printf("COVERAGE:\n"); - std::string LastFunctionName = ""; - std::string LastFileStr = ""; - std::set UncoveredLines; - std::set CoveredLines; - - auto FunctionEndCallback = [&](const std::string &CurrentFunc, - const std::string &CurrentFile) { - if (LastFunctionName != CurrentFunc) { - if (CoveredLines.empty() && !UncoveredLines.empty()) { - Printf("UNCOVERED_FUNC: %s\n", LastFunctionName.c_str()); - } else { - for (auto Line : UncoveredLines) { - if (!CoveredLines.count(Line)) - Printf("UNCOVERED_LINE: %s %s:%zd\n", LastFunctionName.c_str(), - LastFileStr.c_str(), Line); - } - } - - UncoveredLines.clear(); - CoveredLines.clear(); - LastFunctionName = CurrentFunc; - LastFileStr = CurrentFile; - } - }; - - for (size_t i = 0; i < NumPCTables; i++) { - auto &M = ModulePCTable[i]; - assert(M.Start < M.Stop); - auto ModuleName = GetModuleName(*M.Start); - for (auto Ptr = M.Start; Ptr < M.Stop; Ptr++) { - auto PC = *Ptr; - auto VisualizePC = GetNextInstructionPc(PC); - bool IsObserved = ObservedPCs.count(PC); - std::string FileStr = DescribePC("%s", VisualizePC); - if (!IsInterestingCoverageFile(FileStr)) continue; - std::string FunctionStr = DescribePC("%F", VisualizePC); - FunctionEndCallback(FunctionStr, FileStr); - std::string LineStr = DescribePC("%l", VisualizePC); - size_t Line = std::stoul(LineStr); - if (IsObserved && CoveredLines.insert(Line).second) - Printf("COVERED: %s %s:%zd\n", FunctionStr.c_str(), FileStr.c_str(), - Line); - else - UncoveredLines.insert(Line); - } - } - FunctionEndCallback("", ""); -} - -void TracePC::DumpCoverage() { - if (EF->__sanitizer_dump_coverage) { - std::vector PCsCopy(GetNumPCs()); - for (size_t i = 0; i < GetNumPCs(); i++) - PCsCopy[i] = PCs()[i] ? GetPreviousInstructionPc(PCs()[i]) : 0; - EF->__sanitizer_dump_coverage(PCsCopy.data(), PCsCopy.size()); - } -} - -// Value profile. -// We keep track of various values that affect control flow. -// These values are inserted into a bit-set-based hash map. -// Every new bit in the map is treated as a new coverage. -// -// For memcmp/strcmp/etc the interesting value is the length of the common -// prefix of the parameters. -// For cmp instructions the interesting value is a XOR of the parameters. -// The interesting value is mixed up with the PC and is then added to the map. - -ATTRIBUTE_NO_SANITIZE_ALL -void TracePC::AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2, - size_t n, bool StopAtZero) { - if (!n) return; - size_t Len = std::min(n, Word::GetMaxSize()); - const uint8_t *A1 = reinterpret_cast(s1); - const uint8_t *A2 = reinterpret_cast(s2); - uint8_t B1[Word::kMaxSize]; - uint8_t B2[Word::kMaxSize]; - // Copy the data into locals in this non-msan-instrumented function - // to avoid msan complaining further. - size_t Hash = 0; // Compute some simple hash of both strings. - for (size_t i = 0; i < Len; i++) { - B1[i] = A1[i]; - B2[i] = A2[i]; - size_t T = B1[i]; - Hash ^= (T << 8) | B2[i]; - } - size_t I = 0; - for (; I < Len; I++) - if (B1[I] != B2[I] || (StopAtZero && B1[I] == 0)) - break; - size_t PC = reinterpret_cast(caller_pc); - size_t Idx = (PC & 4095) | (I << 12); - ValueProfileMap.AddValue(Idx); - TORCW.Insert(Idx ^ Hash, Word(B1, Len), Word(B2, Len)); -} - -template -ATTRIBUTE_TARGET_POPCNT ALWAYS_INLINE -ATTRIBUTE_NO_SANITIZE_ALL -void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) { - uint64_t ArgXor = Arg1 ^ Arg2; - uint64_t ArgDistance = __builtin_popcountll(ArgXor) + 1; // [1,65] - uintptr_t Idx = ((PC & 4095) + 1) * ArgDistance; - if (sizeof(T) == 4) - TORC4.Insert(ArgXor, Arg1, Arg2); - else if (sizeof(T) == 8) - TORC8.Insert(ArgXor, Arg1, Arg2); - ValueProfileMap.AddValue(Idx); -} - -static size_t InternalStrnlen(const char *S, size_t MaxLen) { - size_t Len = 0; - for (; Len < MaxLen && S[Len]; Len++) {} - return Len; -} - -// Finds min of (strlen(S1), strlen(S2)). -// Needed bacause one of these strings may actually be non-zero terminated. -static size_t InternalStrnlen2(const char *S1, const char *S2) { - size_t Len = 0; - for (; S1[Len] && S2[Len]; Len++) {} - return Len; -} - -void TracePC::ClearInlineCounters() { - for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) { - uint8_t *Beg = ModuleCounters[i].Start; - size_t Size = ModuleCounters[i].Stop - Beg; - memset(Beg, 0, Size); - } -} - -} // namespace fuzzer - -extern "C" { -ATTRIBUTE_INTERFACE -ATTRIBUTE_NO_SANITIZE_ALL -void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); - uint32_t Idx = *Guard; - __sancov_trace_pc_pcs[Idx] = PC; - __sancov_trace_pc_guard_8bit_counters[Idx]++; - // Uncomment the following line to get stack-depth profiling. - // fuzzer::TPC.RecordCurrentStack(); -} - -// Best-effort support for -fsanitize-coverage=trace-pc, which is available -// in both Clang and GCC. -ATTRIBUTE_INTERFACE -ATTRIBUTE_NO_SANITIZE_ALL -void __sanitizer_cov_trace_pc() { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); - uintptr_t Idx = PC & (((uintptr_t)1 << fuzzer::TracePC::kTracePcBits) - 1); - __sancov_trace_pc_pcs[Idx] = PC; - __sancov_trace_pc_guard_8bit_counters[Idx]++; -} - -ATTRIBUTE_INTERFACE -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 -void __sanitizer_cov_pcs_init(const uint8_t *pcs_beg, const uint8_t *pcs_end) { - fuzzer::TPC.HandlePCsInit(pcs_beg, pcs_end); -} - -ATTRIBUTE_INTERFACE -ATTRIBUTE_NO_SANITIZE_ALL -void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); - fuzzer::TPC.HandleCallerCallee(PC, Callee); -} - -ATTRIBUTE_INTERFACE -ATTRIBUTE_NO_SANITIZE_ALL -ATTRIBUTE_TARGET_POPCNT -void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); - fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); -} - -ATTRIBUTE_INTERFACE -ATTRIBUTE_NO_SANITIZE_ALL -ATTRIBUTE_TARGET_POPCNT -// Now the __sanitizer_cov_trace_const_cmp[1248] callbacks just mimic -// the behaviour of __sanitizer_cov_trace_cmp[1248] ones. This, however, -// should be changed later to make full use of instrumentation. -void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); - fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); -} - -ATTRIBUTE_INTERFACE -ATTRIBUTE_NO_SANITIZE_ALL -ATTRIBUTE_TARGET_POPCNT -void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); - fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); -} - -ATTRIBUTE_INTERFACE -ATTRIBUTE_NO_SANITIZE_ALL -ATTRIBUTE_TARGET_POPCNT -void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); - fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); -} - -ATTRIBUTE_INTERFACE -ATTRIBUTE_NO_SANITIZE_ALL -ATTRIBUTE_TARGET_POPCNT -void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); - fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); -} - -ATTRIBUTE_INTERFACE -ATTRIBUTE_NO_SANITIZE_ALL -ATTRIBUTE_TARGET_POPCNT -void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); - fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); -} - -ATTRIBUTE_INTERFACE -ATTRIBUTE_NO_SANITIZE_ALL -ATTRIBUTE_TARGET_POPCNT -void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); - fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); -} - -ATTRIBUTE_INTERFACE -ATTRIBUTE_NO_SANITIZE_ALL -ATTRIBUTE_TARGET_POPCNT -void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); - fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); -} - -ATTRIBUTE_INTERFACE -ATTRIBUTE_NO_SANITIZE_ALL -ATTRIBUTE_TARGET_POPCNT -void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) { - uint64_t N = Cases[0]; - uint64_t ValSizeInBits = Cases[1]; - uint64_t *Vals = Cases + 2; - // Skip the most common and the most boring case. - if (Vals[N - 1] < 256 && Val < 256) - return; - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); - size_t i; - uint64_t Token = 0; - for (i = 0; i < N; i++) { - Token = Val ^ Vals[i]; - if (Val < Vals[i]) - break; - } - - if (ValSizeInBits == 16) - fuzzer::TPC.HandleCmp(PC + i, static_cast(Token), (uint16_t)(0)); - else if (ValSizeInBits == 32) - fuzzer::TPC.HandleCmp(PC + i, static_cast(Token), (uint32_t)(0)); - else - fuzzer::TPC.HandleCmp(PC + i, Token, (uint64_t)(0)); -} - -ATTRIBUTE_INTERFACE -ATTRIBUTE_NO_SANITIZE_ALL -ATTRIBUTE_TARGET_POPCNT -void __sanitizer_cov_trace_div4(uint32_t Val) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); - fuzzer::TPC.HandleCmp(PC, Val, (uint32_t)0); -} - -ATTRIBUTE_INTERFACE -ATTRIBUTE_NO_SANITIZE_ALL -ATTRIBUTE_TARGET_POPCNT -void __sanitizer_cov_trace_div8(uint64_t Val) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); - fuzzer::TPC.HandleCmp(PC, Val, (uint64_t)0); -} - -ATTRIBUTE_INTERFACE -ATTRIBUTE_NO_SANITIZE_ALL -ATTRIBUTE_TARGET_POPCNT -void __sanitizer_cov_trace_gep(uintptr_t Idx) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); - fuzzer::TPC.HandleCmp(PC, Idx, (uintptr_t)0); -} - -ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY -void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1, - const void *s2, size_t n, int result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; - if (result == 0) return; // No reason to mutate. - if (n <= 1) return; // Not interesting. - fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/false); -} - -ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY -void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1, - const char *s2, size_t n, int result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; - if (result == 0) return; // No reason to mutate. - size_t Len1 = fuzzer::InternalStrnlen(s1, n); - size_t Len2 = fuzzer::InternalStrnlen(s2, n); - n = std::min(n, Len1); - n = std::min(n, Len2); - if (n <= 1) return; // Not interesting. - fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/true); -} - -ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY -void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1, - const char *s2, int result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; - if (result == 0) return; // No reason to mutate. - size_t N = fuzzer::InternalStrnlen2(s1, s2); - if (N <= 1) return; // Not interesting. - fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, N, /*StopAtZero*/true); -} - -ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY -void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1, - const char *s2, size_t n, int result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; - return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result); -} - -ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY -void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1, - const char *s2, int result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; - return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result); -} - -ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY -void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1, - const char *s2, char *result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; - fuzzer::TPC.MMT.Add(reinterpret_cast(s2), strlen(s2)); -} - -ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY -void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1, - const char *s2, char *result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; - fuzzer::TPC.MMT.Add(reinterpret_cast(s2), strlen(s2)); -} - -ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY -void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1, - const void *s2, size_t len2, void *result) { - if (fuzzer::ScopedDoingMyOwnMemOrStr::DoingMyOwnMemOrStr) return; - fuzzer::TPC.MMT.Add(reinterpret_cast(s2), len2); -} -} // extern "C" Index: lib/fuzzer/FuzzerUtil.h =================================================================== --- lib/fuzzer/FuzzerUtil.h +++ /dev/null @@ -1,84 +0,0 @@ -//===- FuzzerUtil.h - Internal header for the Fuzzer Utils ------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Util functions. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_UTIL_H -#define LLVM_FUZZER_UTIL_H - -#include "FuzzerDefs.h" - -namespace fuzzer { - -void PrintHexArray(const Unit &U, const char *PrintAfter = ""); - -void PrintHexArray(const uint8_t *Data, size_t Size, - const char *PrintAfter = ""); - -void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = ""); - -void PrintASCII(const Unit &U, const char *PrintAfter = ""); - -// Changes U to contain only ASCII (isprint+isspace) characters. -// Returns true iff U has been changed. -bool ToASCII(uint8_t *Data, size_t Size); - -bool IsASCII(const Unit &U); - -bool IsASCII(const uint8_t *Data, size_t Size); - -std::string Base64(const Unit &U); - -void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC); - -std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC); - -unsigned NumberOfCpuCores(); - -// Platform specific functions. -void SetSignalHandler(const FuzzingOptions& Options); - -void SleepSeconds(int Seconds); - -unsigned long GetPid(); - -size_t GetPeakRSSMb(); - -int ExecuteCommand(const std::string &Command); - -FILE *OpenProcessPipe(const char *Command, const char *Mode); - -const void *SearchMemory(const void *haystack, size_t haystacklen, - const void *needle, size_t needlelen); - -std::string CloneArgsWithoutX(const std::vector &Args, - const char *X1, const char *X2); - -inline std::string CloneArgsWithoutX(const std::vector &Args, - const char *X) { - return CloneArgsWithoutX(Args, X, X); -} - -inline std::pair SplitBefore(std::string X, - std::string S) { - auto Pos = S.find(X); - if (Pos == std::string::npos) - return std::make_pair(S, ""); - return std::make_pair(S.substr(0, Pos), S.substr(Pos)); -} - -std::string DisassembleCmd(const std::string &FileName); - -std::string SearchRegexCmd(const std::string &Regex); - -size_t SimpleFastHash(const uint8_t *Data, size_t Size); - -} // namespace fuzzer - -#endif // LLVM_FUZZER_UTIL_H Index: lib/fuzzer/FuzzerUtil.cpp =================================================================== --- lib/fuzzer/FuzzerUtil.cpp +++ /dev/null @@ -1,215 +0,0 @@ -//===- FuzzerUtil.cpp - Misc utils ----------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Misc utils. -//===----------------------------------------------------------------------===// - -#include "FuzzerUtil.h" -#include "FuzzerIO.h" -#include "FuzzerInternal.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace fuzzer { - -void PrintHexArray(const uint8_t *Data, size_t Size, - const char *PrintAfter) { - for (size_t i = 0; i < Size; i++) - Printf("0x%x,", (unsigned)Data[i]); - Printf("%s", PrintAfter); -} - -void Print(const Unit &v, const char *PrintAfter) { - PrintHexArray(v.data(), v.size(), PrintAfter); -} - -void PrintASCIIByte(uint8_t Byte) { - if (Byte == '\\') - Printf("\\\\"); - else if (Byte == '"') - Printf("\\\""); - else if (Byte >= 32 && Byte < 127) - Printf("%c", Byte); - else - Printf("\\x%02x", Byte); -} - -void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) { - for (size_t i = 0; i < Size; i++) - PrintASCIIByte(Data[i]); - Printf("%s", PrintAfter); -} - -void PrintASCII(const Unit &U, const char *PrintAfter) { - PrintASCII(U.data(), U.size(), PrintAfter); -} - -bool ToASCII(uint8_t *Data, size_t Size) { - bool Changed = false; - for (size_t i = 0; i < Size; i++) { - uint8_t &X = Data[i]; - auto NewX = X; - NewX &= 127; - if (!isspace(NewX) && !isprint(NewX)) - NewX = ' '; - Changed |= NewX != X; - X = NewX; - } - return Changed; -} - -bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); } - -bool IsASCII(const uint8_t *Data, size_t Size) { - for (size_t i = 0; i < Size; i++) - if (!(isprint(Data[i]) || isspace(Data[i]))) return false; - return true; -} - -bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) { - U->clear(); - if (Str.empty()) return false; - size_t L = 0, R = Str.size() - 1; // We are parsing the range [L,R]. - // Skip spaces from both sides. - while (L < R && isspace(Str[L])) L++; - while (R > L && isspace(Str[R])) R--; - if (R - L < 2) return false; - // Check the closing " - if (Str[R] != '"') return false; - R--; - // Find the opening " - while (L < R && Str[L] != '"') L++; - if (L >= R) return false; - assert(Str[L] == '\"'); - L++; - assert(L <= R); - for (size_t Pos = L; Pos <= R; Pos++) { - uint8_t V = (uint8_t)Str[Pos]; - if (!isprint(V) && !isspace(V)) return false; - if (V =='\\') { - // Handle '\\' - if (Pos + 1 <= R && (Str[Pos + 1] == '\\' || Str[Pos + 1] == '"')) { - U->push_back(Str[Pos + 1]); - Pos++; - continue; - } - // Handle '\xAB' - if (Pos + 3 <= R && Str[Pos + 1] == 'x' - && isxdigit(Str[Pos + 2]) && isxdigit(Str[Pos + 3])) { - char Hex[] = "0xAA"; - Hex[2] = Str[Pos + 2]; - Hex[3] = Str[Pos + 3]; - U->push_back(strtol(Hex, nullptr, 16)); - Pos += 3; - continue; - } - return false; // Invalid escape. - } else { - // Any other character. - U->push_back(V); - } - } - return true; -} - -bool ParseDictionaryFile(const std::string &Text, std::vector *Units) { - if (Text.empty()) { - Printf("ParseDictionaryFile: file does not exist or is empty\n"); - return false; - } - std::istringstream ISS(Text); - Units->clear(); - Unit U; - int LineNo = 0; - std::string S; - while (std::getline(ISS, S, '\n')) { - LineNo++; - size_t Pos = 0; - while (Pos < S.size() && isspace(S[Pos])) Pos++; // Skip spaces. - if (Pos == S.size()) continue; // Empty line. - if (S[Pos] == '#') continue; // Comment line. - if (ParseOneDictionaryEntry(S, &U)) { - Units->push_back(U); - } else { - Printf("ParseDictionaryFile: error in line %d\n\t\t%s\n", LineNo, - S.c_str()); - return false; - } - } - return true; -} - -std::string Base64(const Unit &U) { - static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - std::string Res; - size_t i; - for (i = 0; i + 2 < U.size(); i += 3) { - uint32_t x = (U[i] << 16) + (U[i + 1] << 8) + U[i + 2]; - Res += Table[(x >> 18) & 63]; - Res += Table[(x >> 12) & 63]; - Res += Table[(x >> 6) & 63]; - Res += Table[x & 63]; - } - if (i + 1 == U.size()) { - uint32_t x = (U[i] << 16); - Res += Table[(x >> 18) & 63]; - Res += Table[(x >> 12) & 63]; - Res += "=="; - } else if (i + 2 == U.size()) { - uint32_t x = (U[i] << 16) + (U[i + 1] << 8); - Res += Table[(x >> 18) & 63]; - Res += Table[(x >> 12) & 63]; - Res += Table[(x >> 6) & 63]; - Res += "="; - } - return Res; -} - -std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) { - if (!EF->__sanitizer_symbolize_pc) return ""; - char PcDescr[1024]; - EF->__sanitizer_symbolize_pc(reinterpret_cast(PC), - SymbolizedFMT, PcDescr, sizeof(PcDescr)); - PcDescr[sizeof(PcDescr) - 1] = 0; // Just in case. - return PcDescr; -} - -void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) { - if (EF->__sanitizer_symbolize_pc) - Printf("%s", DescribePC(SymbolizedFMT, PC).c_str()); - else - Printf(FallbackFMT, PC); -} - -unsigned NumberOfCpuCores() { - unsigned N = std::thread::hardware_concurrency(); - if (!N) { - Printf("WARNING: std::thread::hardware_concurrency not well defined for " - "your platform. Assuming CPU count of 1.\n"); - N = 1; - } - return N; -} - -size_t SimpleFastHash(const uint8_t *Data, size_t Size) { - size_t Res = 0; - for (size_t i = 0; i < Size; i++) - Res = Res * 11 + Data[i]; - return Res; -} - -} // namespace fuzzer Index: lib/fuzzer/FuzzerUtilDarwin.cpp =================================================================== --- lib/fuzzer/FuzzerUtilDarwin.cpp +++ /dev/null @@ -1,161 +0,0 @@ -//===- FuzzerUtilDarwin.cpp - Misc utils ----------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Misc utils for Darwin. -//===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" -#if LIBFUZZER_APPLE - -#include "FuzzerIO.h" -#include -#include -#include -#include -#include -#include - -// There is no header for this on macOS so declare here -extern "C" char **environ; - -namespace fuzzer { - -static std::mutex SignalMutex; -// Global variables used to keep track of how signal handling should be -// restored. They should **not** be accessed without holding `SignalMutex`. -static int ActiveThreadCount = 0; -static struct sigaction OldSigIntAction; -static struct sigaction OldSigQuitAction; -static sigset_t OldBlockedSignalsSet; - -// This is a reimplementation of Libc's `system()`. On Darwin the Libc -// implementation contains a mutex which prevents it from being used -// concurrently. This implementation **can** be used concurrently. It sets the -// signal handlers when the first thread enters and restores them when the last -// thread finishes execution of the function and ensures this is not racey by -// using a mutex. -int ExecuteCommand(const std::string &Command) { - posix_spawnattr_t SpawnAttributes; - if (posix_spawnattr_init(&SpawnAttributes)) - return -1; - // Block and ignore signals of the current process when the first thread - // enters. - { - std::lock_guard Lock(SignalMutex); - if (ActiveThreadCount == 0) { - static struct sigaction IgnoreSignalAction; - sigset_t BlockedSignalsSet; - memset(&IgnoreSignalAction, 0, sizeof(IgnoreSignalAction)); - IgnoreSignalAction.sa_handler = SIG_IGN; - - if (sigaction(SIGINT, &IgnoreSignalAction, &OldSigIntAction) == -1) { - Printf("Failed to ignore SIGINT\n"); - (void)posix_spawnattr_destroy(&SpawnAttributes); - return -1; - } - if (sigaction(SIGQUIT, &IgnoreSignalAction, &OldSigQuitAction) == -1) { - Printf("Failed to ignore SIGQUIT\n"); - // Try our best to restore the signal handlers. - (void)sigaction(SIGINT, &OldSigIntAction, NULL); - (void)posix_spawnattr_destroy(&SpawnAttributes); - return -1; - } - - (void)sigemptyset(&BlockedSignalsSet); - (void)sigaddset(&BlockedSignalsSet, SIGCHLD); - if (sigprocmask(SIG_BLOCK, &BlockedSignalsSet, &OldBlockedSignalsSet) == - -1) { - Printf("Failed to block SIGCHLD\n"); - // Try our best to restore the signal handlers. - (void)sigaction(SIGQUIT, &OldSigQuitAction, NULL); - (void)sigaction(SIGINT, &OldSigIntAction, NULL); - (void)posix_spawnattr_destroy(&SpawnAttributes); - return -1; - } - } - ++ActiveThreadCount; - } - - // NOTE: Do not introduce any new `return` statements past this - // point. It is important that `ActiveThreadCount` always be decremented - // when leaving this function. - - // Make sure the child process uses the default handlers for the - // following signals rather than inheriting what the parent has. - sigset_t DefaultSigSet; - (void)sigemptyset(&DefaultSigSet); - (void)sigaddset(&DefaultSigSet, SIGQUIT); - (void)sigaddset(&DefaultSigSet, SIGINT); - (void)posix_spawnattr_setsigdefault(&SpawnAttributes, &DefaultSigSet); - // Make sure the child process doesn't block SIGCHLD - (void)posix_spawnattr_setsigmask(&SpawnAttributes, &OldBlockedSignalsSet); - short SpawnFlags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; - (void)posix_spawnattr_setflags(&SpawnAttributes, SpawnFlags); - - pid_t Pid; - char **Environ = environ; // Read from global - const char *CommandCStr = Command.c_str(); - char *const Argv[] = { - strdup("sh"), - strdup("-c"), - strdup(CommandCStr), - NULL - }; - int ErrorCode = 0, ProcessStatus = 0; - // FIXME: We probably shouldn't hardcode the shell path. - ErrorCode = posix_spawn(&Pid, "/bin/sh", NULL, &SpawnAttributes, - Argv, Environ); - (void)posix_spawnattr_destroy(&SpawnAttributes); - if (!ErrorCode) { - pid_t SavedPid = Pid; - do { - // Repeat until call completes uninterrupted. - Pid = waitpid(SavedPid, &ProcessStatus, /*options=*/0); - } while (Pid == -1 && errno == EINTR); - if (Pid == -1) { - // Fail for some other reason. - ProcessStatus = -1; - } - } else if (ErrorCode == ENOMEM || ErrorCode == EAGAIN) { - // Fork failure. - ProcessStatus = -1; - } else { - // Shell execution failure. - ProcessStatus = W_EXITCODE(127, 0); - } - for (unsigned i = 0, n = sizeof(Argv) / sizeof(Argv[0]); i < n; ++i) - free(Argv[i]); - - // Restore the signal handlers of the current process when the last thread - // using this function finishes. - { - std::lock_guard Lock(SignalMutex); - --ActiveThreadCount; - if (ActiveThreadCount == 0) { - bool FailedRestore = false; - if (sigaction(SIGINT, &OldSigIntAction, NULL) == -1) { - Printf("Failed to restore SIGINT handling\n"); - FailedRestore = true; - } - if (sigaction(SIGQUIT, &OldSigQuitAction, NULL) == -1) { - Printf("Failed to restore SIGQUIT handling\n"); - FailedRestore = true; - } - if (sigprocmask(SIG_BLOCK, &OldBlockedSignalsSet, NULL) == -1) { - Printf("Failed to unblock SIGCHLD\n"); - FailedRestore = true; - } - if (FailedRestore) - ProcessStatus = -1; - } - } - return ProcessStatus; -} - -} // namespace fuzzer - -#endif // LIBFUZZER_APPLE Index: lib/fuzzer/FuzzerUtilLinux.cpp =================================================================== --- lib/fuzzer/FuzzerUtilLinux.cpp +++ /dev/null @@ -1,24 +0,0 @@ -//===- FuzzerUtilLinux.cpp - Misc utils for Linux. ------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Misc utils for Linux. -//===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" -#if LIBFUZZER_LINUX - -#include - -namespace fuzzer { - -int ExecuteCommand(const std::string &Command) { - return system(Command.c_str()); -} - -} // namespace fuzzer - -#endif // LIBFUZZER_LINUX Index: lib/fuzzer/FuzzerUtilPosix.cpp =================================================================== --- lib/fuzzer/FuzzerUtilPosix.cpp +++ /dev/null @@ -1,144 +0,0 @@ -//===- FuzzerUtilPosix.cpp - Misc utils for Posix. ------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Misc utils implementation using Posix API. -//===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" -#if LIBFUZZER_POSIX -#include "FuzzerIO.h" -#include "FuzzerInternal.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace fuzzer { - -static void AlarmHandler(int, siginfo_t *, void *) { - Fuzzer::StaticAlarmCallback(); -} - -static void CrashHandler(int, siginfo_t *, void *) { - Fuzzer::StaticCrashSignalCallback(); -} - -static void InterruptHandler(int, siginfo_t *, void *) { - Fuzzer::StaticInterruptCallback(); -} - -static void FileSizeExceedHandler(int, siginfo_t *, void *) { - Fuzzer::StaticFileSizeExceedCallback(); -} - -static void SetSigaction(int signum, - void (*callback)(int, siginfo_t *, void *)) { - struct sigaction sigact = {}; - if (sigaction(signum, nullptr, &sigact)) { - Printf("libFuzzer: sigaction failed with %d\n", errno); - exit(1); - } - if (sigact.sa_flags & SA_SIGINFO) { - if (sigact.sa_sigaction) - return; - } else { - if (sigact.sa_handler != SIG_DFL && sigact.sa_handler != SIG_IGN && - sigact.sa_handler != SIG_ERR) - return; - } - - sigact = {}; - sigact.sa_sigaction = callback; - if (sigaction(signum, &sigact, 0)) { - Printf("libFuzzer: sigaction failed with %d\n", errno); - exit(1); - } -} - -void SetTimer(int Seconds) { - struct itimerval T { - {Seconds, 0}, { Seconds, 0 } - }; - if (setitimer(ITIMER_REAL, &T, nullptr)) { - Printf("libFuzzer: setitimer failed with %d\n", errno); - exit(1); - } - SetSigaction(SIGALRM, AlarmHandler); -} - -void SetSignalHandler(const FuzzingOptions& Options) { - if (Options.UnitTimeoutSec > 0) - SetTimer(Options.UnitTimeoutSec / 2 + 1); - if (Options.HandleInt) - SetSigaction(SIGINT, InterruptHandler); - if (Options.HandleTerm) - SetSigaction(SIGTERM, InterruptHandler); - if (Options.HandleSegv) - SetSigaction(SIGSEGV, CrashHandler); - if (Options.HandleBus) - SetSigaction(SIGBUS, CrashHandler); - if (Options.HandleAbrt) - SetSigaction(SIGABRT, CrashHandler); - if (Options.HandleIll) - SetSigaction(SIGILL, CrashHandler); - if (Options.HandleFpe) - SetSigaction(SIGFPE, CrashHandler); - if (Options.HandleXfsz) - SetSigaction(SIGXFSZ, FileSizeExceedHandler); -} - -void SleepSeconds(int Seconds) { - sleep(Seconds); // Use C API to avoid coverage from instrumented libc++. -} - -unsigned long GetPid() { return (unsigned long)getpid(); } - -size_t GetPeakRSSMb() { - struct rusage usage; - if (getrusage(RUSAGE_SELF, &usage)) - return 0; - if (LIBFUZZER_LINUX) { - // ru_maxrss is in KiB - return usage.ru_maxrss >> 10; - } else if (LIBFUZZER_APPLE) { - // ru_maxrss is in bytes - return usage.ru_maxrss >> 20; - } - assert(0 && "GetPeakRSSMb() is not implemented for your platform"); - return 0; -} - -FILE *OpenProcessPipe(const char *Command, const char *Mode) { - return popen(Command, Mode); -} - -const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, - size_t PattLen) { - return memmem(Data, DataLen, Patt, PattLen); -} - -std::string DisassembleCmd(const std::string &FileName) { - return "objdump -d " + FileName; -} - -std::string SearchRegexCmd(const std::string &Regex) { - return "grep '" + Regex + "'"; -} - -} // namespace fuzzer - -#endif // LIBFUZZER_POSIX Index: lib/fuzzer/FuzzerUtilWindows.cpp =================================================================== --- lib/fuzzer/FuzzerUtilWindows.cpp +++ /dev/null @@ -1,193 +0,0 @@ -//===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// Misc utils implementation for Windows. -//===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" -#if LIBFUZZER_WINDOWS -#include "FuzzerIO.h" -#include "FuzzerInternal.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// This must be included after windows.h. -#include - -namespace fuzzer { - -static const FuzzingOptions* HandlerOpt = nullptr; - -static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) { - switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { - case EXCEPTION_ACCESS_VIOLATION: - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - case EXCEPTION_STACK_OVERFLOW: - if (HandlerOpt->HandleSegv) - Fuzzer::StaticCrashSignalCallback(); - break; - case EXCEPTION_DATATYPE_MISALIGNMENT: - case EXCEPTION_IN_PAGE_ERROR: - if (HandlerOpt->HandleBus) - Fuzzer::StaticCrashSignalCallback(); - break; - case EXCEPTION_ILLEGAL_INSTRUCTION: - case EXCEPTION_PRIV_INSTRUCTION: - if (HandlerOpt->HandleIll) - Fuzzer::StaticCrashSignalCallback(); - break; - case EXCEPTION_FLT_DENORMAL_OPERAND: - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - case EXCEPTION_FLT_INEXACT_RESULT: - case EXCEPTION_FLT_INVALID_OPERATION: - case EXCEPTION_FLT_OVERFLOW: - case EXCEPTION_FLT_STACK_CHECK: - case EXCEPTION_FLT_UNDERFLOW: - case EXCEPTION_INT_DIVIDE_BY_ZERO: - case EXCEPTION_INT_OVERFLOW: - if (HandlerOpt->HandleFpe) - Fuzzer::StaticCrashSignalCallback(); - break; - // TODO: handle (Options.HandleXfsz) - } - return EXCEPTION_CONTINUE_SEARCH; -} - -BOOL WINAPI CtrlHandler(DWORD dwCtrlType) { - switch (dwCtrlType) { - case CTRL_C_EVENT: - if (HandlerOpt->HandleInt) - Fuzzer::StaticInterruptCallback(); - return TRUE; - case CTRL_BREAK_EVENT: - if (HandlerOpt->HandleTerm) - Fuzzer::StaticInterruptCallback(); - return TRUE; - } - return FALSE; -} - -void CALLBACK AlarmHandler(PVOID, BOOLEAN) { - Fuzzer::StaticAlarmCallback(); -} - -class TimerQ { - HANDLE TimerQueue; - public: - TimerQ() : TimerQueue(NULL) {}; - ~TimerQ() { - if (TimerQueue) - DeleteTimerQueueEx(TimerQueue, NULL); - }; - void SetTimer(int Seconds) { - if (!TimerQueue) { - TimerQueue = CreateTimerQueue(); - if (!TimerQueue) { - Printf("libFuzzer: CreateTimerQueue failed.\n"); - exit(1); - } - } - HANDLE Timer; - if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL, - Seconds*1000, Seconds*1000, 0)) { - Printf("libFuzzer: CreateTimerQueueTimer failed.\n"); - exit(1); - } - }; -}; - -static TimerQ Timer; - -static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); } - -void SetSignalHandler(const FuzzingOptions& Options) { - HandlerOpt = &Options; - - if (Options.UnitTimeoutSec > 0) - Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1); - - if (Options.HandleInt || Options.HandleTerm) - if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) { - DWORD LastError = GetLastError(); - Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n", - LastError); - exit(1); - } - - if (Options.HandleSegv || Options.HandleBus || Options.HandleIll || - Options.HandleFpe) - SetUnhandledExceptionFilter(ExceptionHandler); - - if (Options.HandleAbrt) - if (SIG_ERR == signal(SIGABRT, CrashHandler)) { - Printf("libFuzzer: signal failed with %d\n", errno); - exit(1); - } -} - -void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); } - -unsigned long GetPid() { return GetCurrentProcessId(); } - -size_t GetPeakRSSMb() { - PROCESS_MEMORY_COUNTERS info; - if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info))) - return 0; - return info.PeakWorkingSetSize >> 20; -} - -FILE *OpenProcessPipe(const char *Command, const char *Mode) { - return _popen(Command, Mode); -} - -int ExecuteCommand(const std::string &Command) { - return system(Command.c_str()); -} - -const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, - size_t PattLen) { - // TODO: make this implementation more efficient. - const char *Cdata = (const char *)Data; - const char *Cpatt = (const char *)Patt; - - if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen) - return NULL; - - if (PattLen == 1) - return memchr(Data, *Cpatt, DataLen); - - const char *End = Cdata + DataLen - PattLen + 1; - - for (const char *It = Cdata; It < End; ++It) - if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0) - return It; - - return NULL; -} - -std::string DisassembleCmd(const std::string &FileName) { - if (ExecuteCommand("dumpbin /summary > nul") == 0) - return "dumpbin /disasm " + FileName; - Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n"); - exit(1); -} - -std::string SearchRegexCmd(const std::string &Regex) { - return "findstr /r \"" + Regex + "\""; -} - -} // namespace fuzzer - -#endif // LIBFUZZER_WINDOWS Index: lib/fuzzer/FuzzerValueBitMap.h =================================================================== --- lib/fuzzer/FuzzerValueBitMap.h +++ /dev/null @@ -1,73 +0,0 @@ -//===- FuzzerValueBitMap.h - INTERNAL - Bit map -----------------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// ValueBitMap. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_FUZZER_VALUE_BIT_MAP_H -#define LLVM_FUZZER_VALUE_BIT_MAP_H - -#include "FuzzerDefs.h" - -namespace fuzzer { - -// A bit map containing kMapSizeInWords bits. -struct ValueBitMap { - static const size_t kMapSizeInBits = 1 << 16; - static const size_t kMapPrimeMod = 65371; // Largest Prime < kMapSizeInBits; - static const size_t kBitsInWord = (sizeof(uintptr_t) * 8); - static const size_t kMapSizeInWords = kMapSizeInBits / kBitsInWord; - public: - - // Clears all bits. - void Reset() { memset(Map, 0, sizeof(Map)); } - - // Computes a hash function of Value and sets the corresponding bit. - // Returns true if the bit was changed from 0 to 1. - ATTRIBUTE_NO_SANITIZE_ALL - inline bool AddValue(uintptr_t Value) { - uintptr_t Idx = Value % kMapSizeInBits; - uintptr_t WordIdx = Idx / kBitsInWord; - uintptr_t BitIdx = Idx % kBitsInWord; - uintptr_t Old = Map[WordIdx]; - uintptr_t New = Old | (1UL << BitIdx); - Map[WordIdx] = New; - return New != Old; - } - - ATTRIBUTE_NO_SANITIZE_ALL - inline bool AddValueModPrime(uintptr_t Value) { - return AddValue(Value % kMapPrimeMod); - } - - inline bool Get(uintptr_t Idx) { - assert(Idx < kMapSizeInBits); - uintptr_t WordIdx = Idx / kBitsInWord; - uintptr_t BitIdx = Idx % kBitsInWord; - return Map[WordIdx] & (1UL << BitIdx); - } - - size_t SizeInBits() const { return kMapSizeInBits; } - - template - ATTRIBUTE_NO_SANITIZE_ALL - void ForEach(Callback CB) const { - for (size_t i = 0; i < kMapSizeInWords; i++) - if (uintptr_t M = Map[i]) - for (size_t j = 0; j < sizeof(M) * 8; j++) - if (M & ((uintptr_t)1 << j)) - CB(i * sizeof(M) * 8 + j); - } - - private: - uintptr_t Map[kMapSizeInWords] __attribute__((aligned(512))); -}; - -} // namespace fuzzer - -#endif // LLVM_FUZZER_VALUE_BIT_MAP_H Index: lib/fuzzer/README.txt =================================================================== --- lib/fuzzer/README.txt +++ /dev/null @@ -1,2 +0,0 @@ -Move to http://llvm.org/docs/LibFuzzer.html - Index: lib/fuzzer/afl/afl_driver.cpp =================================================================== --- lib/fuzzer/afl/afl_driver.cpp +++ /dev/null @@ -1,335 +0,0 @@ -//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -//===----------------------------------------------------------------------===// - -/* This file allows to fuzz libFuzzer-style target functions - (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode. - -Usage: -################################################################################ -cat << EOF > test_fuzzer.cc -#include -#include -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - if (size > 0 && data[0] == 'H') - if (size > 1 && data[1] == 'I') - if (size > 2 && data[2] == '!') - __builtin_trap(); - return 0; -} -EOF -# Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang. -clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c -# Build afl-llvm-rt.o.c from the AFL distribution. -clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c -# Build this file, link it with afl-llvm-rt.o.o and the target code. -clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o -# Run AFL: -rm -rf IN OUT; mkdir IN OUT; echo z > IN/z; -$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out -################################################################################ -Environment Variables: -There are a few environment variables that can be set to use features that -afl-fuzz doesn't have. - -AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file -specified. If the file does not exist, it is created. This is useful for getting -stack traces (when using ASAN for example) or original error messages on hard to -reproduce bugs. - -AFL_DRIVER_EXTRA_STATS_FILENAME: Setting this causes afl_driver to write extra -statistics to the file specified. Currently these are peak_rss_mb -(the peak amount of virtual memory used in MB) and slowest_unit_time_secs. If -the file does not exist it is created. If the file does exist then -afl_driver assumes it was restarted by afl-fuzz and will try to read old -statistics from the file. If that fails then the process will quit. - -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -// Platform detection. Copied from FuzzerInternal.h -#ifdef __linux__ -#define LIBFUZZER_LINUX 1 -#define LIBFUZZER_APPLE 0 -#elif __APPLE__ -#define LIBFUZZER_LINUX 0 -#define LIBFUZZER_APPLE 1 -#else -#error "Support for your platform has not been implemented" -#endif - -// Used to avoid repeating error checking boilerplate. If cond is false, a -// fatal error has occured in the program. In this event print error_message -// to stderr and abort(). Otherwise do nothing. Note that setting -// AFL_DRIVER_STDERR_DUPLICATE_FILENAME may cause error_message to be appended -// to the file as well, if the error occurs after the duplication is performed. -#define CHECK_ERROR(cond, error_message) \ - if (!(cond)) { \ - fprintf(stderr, (error_message)); \ - abort(); \ - } - -// libFuzzer interface is thin, so we don't include any libFuzzer headers. -extern "C" { -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); -__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); -} - -// Notify AFL about persistent mode. -static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##"; -extern "C" int __afl_persistent_loop(unsigned int); -static volatile char suppress_warning2 = AFL_PERSISTENT[0]; - -// Notify AFL about deferred forkserver. -static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##"; -extern "C" void __afl_manual_init(); -static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0]; - -// Input buffer. -static const size_t kMaxAflInputSize = 1 << 20; -static uint8_t AflInputBuf[kMaxAflInputSize]; - -// Variables we need for writing to the extra stats file. -static FILE *extra_stats_file = NULL; -static uint32_t previous_peak_rss = 0; -static time_t slowest_unit_time_secs = 0; -static const int kNumExtraStats = 2; -static const char *kExtraStatsFormatString = "peak_rss_mb : %u\n" - "slowest_unit_time_sec : %u\n"; - -// Copied from FuzzerUtil.cpp. -size_t GetPeakRSSMb() { - struct rusage usage; - if (getrusage(RUSAGE_SELF, &usage)) - return 0; - if (LIBFUZZER_LINUX) { - // ru_maxrss is in KiB - return usage.ru_maxrss >> 10; - } else if (LIBFUZZER_APPLE) { - // ru_maxrss is in bytes - return usage.ru_maxrss >> 20; - } - assert(0 && "GetPeakRSSMb() is not implemented for your platform"); - return 0; -} - -// Based on SetSigaction in FuzzerUtil.cpp -static void SetSigaction(int signum, - void (*callback)(int, siginfo_t *, void *)) { - struct sigaction sigact; - memset(&sigact, 0, sizeof(sigact)); - sigact.sa_sigaction = callback; - if (sigaction(signum, &sigact, 0)) { - fprintf(stderr, "libFuzzer: sigaction failed with %d\n", errno); - exit(1); - } -} - -// Write extra stats to the file specified by the user. If none is specified -// this function will never be called. -static void write_extra_stats() { - uint32_t peak_rss = GetPeakRSSMb(); - - if (peak_rss < previous_peak_rss) - peak_rss = previous_peak_rss; - - int chars_printed = fprintf(extra_stats_file, kExtraStatsFormatString, - peak_rss, slowest_unit_time_secs); - - CHECK_ERROR(chars_printed != 0, "Failed to write extra_stats_file"); - - CHECK_ERROR(fclose(extra_stats_file) == 0, - "Failed to close extra_stats_file"); -} - -// Call write_extra_stats before we exit. -static void crash_handler(int, siginfo_t *, void *) { - // Make sure we don't try calling write_extra_stats again if we crashed while - // trying to call it. - static bool first_crash = true; - CHECK_ERROR(first_crash, - "Crashed in crash signal handler. This is a bug in the fuzzer."); - - first_crash = false; - write_extra_stats(); -} - -// If the user has specified an extra_stats_file through the environment -// variable AFL_DRIVER_EXTRA_STATS_FILENAME, then perform necessary set up -// to write stats to it on exit. If no file is specified, do nothing. Otherwise -// install signal and exit handlers to write to the file when the process exits. -// Then if the file doesn't exist create it and set extra stats to 0. But if it -// does exist then read the initial values of the extra stats from the file -// and check that the file is writable. -static void maybe_initialize_extra_stats() { - // If AFL_DRIVER_EXTRA_STATS_FILENAME isn't set then we have nothing to do. - char *extra_stats_filename = getenv("AFL_DRIVER_EXTRA_STATS_FILENAME"); - if (!extra_stats_filename) - return; - - // Open the file and find the previous peak_rss_mb value. - // This is necessary because the fuzzing process is restarted after N - // iterations are completed. So we may need to get this value from a previous - // process to be accurate. - extra_stats_file = fopen(extra_stats_filename, "r"); - - // If extra_stats_file already exists: read old stats from it. - if (extra_stats_file) { - int matches = fscanf(extra_stats_file, kExtraStatsFormatString, - &previous_peak_rss, &slowest_unit_time_secs); - - // Make sure we have read a real extra stats file and that we have used it - // to set slowest_unit_time_secs and previous_peak_rss. - CHECK_ERROR(matches == kNumExtraStats, "Extra stats file is corrupt"); - - CHECK_ERROR(fclose(extra_stats_file) == 0, "Failed to close file"); - - // Now open the file for writing. - extra_stats_file = fopen(extra_stats_filename, "w"); - CHECK_ERROR(extra_stats_file, - "Failed to open extra stats file for writing"); - } else { - // Looks like this is the first time in a fuzzing job this is being called. - extra_stats_file = fopen(extra_stats_filename, "w+"); - CHECK_ERROR(extra_stats_file, "failed to create extra stats file"); - } - - // Make sure that crash_handler gets called on any kind of fatal error. - int crash_signals[] = {SIGSEGV, SIGBUS, SIGABRT, SIGILL, SIGFPE, SIGINT, - SIGTERM}; - - const size_t num_signals = sizeof(crash_signals) / sizeof(crash_signals[0]); - - for (size_t idx = 0; idx < num_signals; idx++) - SetSigaction(crash_signals[idx], crash_handler); - - // Make sure it gets called on other kinds of exits. - atexit(write_extra_stats); -} - -// If the user asks us to duplicate stderr, then do it. -static void maybe_duplicate_stderr() { - char* stderr_duplicate_filename = - getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); - - if (!stderr_duplicate_filename) - return; - - FILE* stderr_duplicate_stream = - freopen(stderr_duplicate_filename, "a+", stderr); - - if (!stderr_duplicate_stream) { - fprintf( - stderr, - "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); - abort(); - } -} - -// Define LLVMFuzzerMutate to avoid link failures for targets that use it -// with libFuzzer's LLVMFuzzerCustomMutator. -extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { - assert(false && "LLVMFuzzerMutate should not be called from afl_driver"); - return 0; -} - -// Execute any files provided as parameters. -int ExecuteFilesOnyByOne(int argc, char **argv) { - for (int i = 1; i < argc; i++) { - std::ifstream in(argv[i]); - in.seekg(0, in.end); - size_t length = in.tellg(); - in.seekg (0, in.beg); - std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl; - // Allocate exactly length bytes so that we reliably catch buffer overflows. - std::vector bytes(length); - in.read(bytes.data(), bytes.size()); - assert(in); - LLVMFuzzerTestOneInput(reinterpret_cast(bytes.data()), - bytes.size()); - std::cout << "Execution successfull" << std::endl; - } - return 0; -} - -int main(int argc, char **argv) { - fprintf(stderr, - "======================= INFO =========================\n" - "This binary is built for AFL-fuzz.\n" - "To run the target function on individual input(s) execute this:\n" - " %s < INPUT_FILE\n" - "or\n" - " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n" - "To fuzz with afl-fuzz execute this:\n" - " afl-fuzz [afl-flags] %s [-N]\n" - "afl-fuzz will run N iterations before " - "re-spawning the process (default: 1000)\n" - "======================================================\n", - argv[0], argv[0], argv[0]); - if (LLVMFuzzerInitialize) - LLVMFuzzerInitialize(&argc, &argv); - // Do any other expensive one-time initialization here. - - maybe_duplicate_stderr(); - maybe_initialize_extra_stats(); - - __afl_manual_init(); - - int N = 1000; - if (argc == 2 && argv[1][0] == '-') - N = atoi(argv[1] + 1); - else if(argc == 2 && (N = atoi(argv[1])) > 0) - fprintf(stderr, "WARNING: using the deprecated call style `%s %d`\n", - argv[0], N); - else if (argc > 1) - return ExecuteFilesOnyByOne(argc, argv); - - assert(N > 0); - time_t unit_time_secs; - int num_runs = 0; - while (__afl_persistent_loop(N)) { - ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize); - if (n_read > 0) { - // Copy AflInputBuf into a separate buffer to let asan find buffer - // overflows. Don't use unique_ptr/etc to avoid extra dependencies. - uint8_t *copy = new uint8_t[n_read]; - memcpy(copy, AflInputBuf, n_read); - - struct timeval unit_start_time; - CHECK_ERROR(gettimeofday(&unit_start_time, NULL) == 0, - "Calling gettimeofday failed"); - - num_runs++; - LLVMFuzzerTestOneInput(copy, n_read); - - struct timeval unit_stop_time; - CHECK_ERROR(gettimeofday(&unit_stop_time, NULL) == 0, - "Calling gettimeofday failed"); - - // Update slowest_unit_time_secs if we see a new max. - unit_time_secs = unit_stop_time.tv_sec - unit_start_time.tv_sec; - if (slowest_unit_time_secs < unit_time_secs) - slowest_unit_time_secs = unit_time_secs; - - delete[] copy; - } - } - fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs); -} Index: lib/fuzzer/build.sh =================================================================== --- lib/fuzzer/build.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -LIBFUZZER_SRC_DIR=$(dirname $0) -CXX="${CXX:-clang}" -for f in $LIBFUZZER_SRC_DIR/*.cpp; do - $CXX -g -O2 -fno-omit-frame-pointer -std=c++11 $f -c & -done -wait -rm -f libFuzzer.a -ar ru libFuzzer.a Fuzzer*.o -rm -f Fuzzer*.o - Index: lib/fuzzer/cxx.dict =================================================================== --- lib/fuzzer/cxx.dict +++ /dev/null @@ -1,122 +0,0 @@ -"++" -"--" -"<<" -">>" -"+=" -"-=" -"*=" -"/=" -">>=" -"<<=" -"&=" -"|=" -"^=" -"%=" -"!=" -"&&" -"||" -"==" -">=" -"<=" -"->" -"alignas" -"alignof" -"and" -"and_eq" -"asm" -"auto" -"bitand" -"bitor" -"bool" -"break" -"case" -"catch" -"char" -"char16_t" -"char32_t" -"class" -"compl" -"concept" -"const" -"constexpr" -"const_cast" -"continue" -"decltype" -"default" -"delete" -"do" -"double" -"dynamic_cast" -"else" -"enum" -"explicit" -"export" -"extern" -"false" -"float" -"for" -"friend" -"goto" -"if" -"inline" -"int" -"long" -"mutable" -"namespace" -"new" -"noexcept" -"not" -"not_eq" -"nullptr" -"operator" -"or" -"or_eq" -"private" -"protected" -"public" -"register" -"reinterpret_cast" -"requires" -"return" -"short" -"signed" -"sizeof" -"static" -"static_assert" -"static_cast" -"struct" -"switch" -"template" -"this" -"thread_local" -"throw" -"true" -"try" -"typedef" -"typeid" -"typename" -"union" -"unsigned" -"using" -"virtual" -"void" -"volatile" -"wchar_t" -"while" -"xor" -"xor_eq" -"if" -"elif" -"else" -"endif" -"defined" -"ifdef" -"ifndef" -"define" -"undef" -"include" -"line" -"error" -"pragma" -"override" -"final" Index: lib/fuzzer/standalone/StandaloneFuzzTargetMain.c =================================================================== --- lib/fuzzer/standalone/StandaloneFuzzTargetMain.c +++ /dev/null @@ -1,41 +0,0 @@ -/*===- StandaloneFuzzTargetMain.c - standalone main() for fuzz targets. ---===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// This main() function can be linked to a fuzz target (i.e. a library -// that exports LLVMFuzzerTestOneInput() and possibly LLVMFuzzerInitialize()) -// instead of libFuzzer. This main() function will not perform any fuzzing -// but will simply feed all input files one by one to the fuzz target. -// -// Use this file to provide reproducers for bugs when linking against libFuzzer -// or other fuzzing engine is undesirable. -//===----------------------------------------------------------------------===*/ -#include -#include -#include - -extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size); -__attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv); -int main(int argc, char **argv) { - fprintf(stderr, "StandaloneFuzzTargetMain: running %d inputs\n", argc - 1); - if (LLVMFuzzerInitialize) - LLVMFuzzerInitialize(&argc, &argv); - for (int i = 1; i < argc; i++) { - fprintf(stderr, "Running: %s\n", argv[i]); - FILE *f = fopen(argv[i], "r"); - assert(f); - fseek(f, 0, SEEK_END); - size_t len = ftell(f); - fseek(f, 0, SEEK_SET); - unsigned char *buf = (unsigned char*)malloc(len); - size_t n_read = fread(buf, 1, len, f); - assert(n_read == len); - LLVMFuzzerTestOneInput(buf, len); - free(buf); - fprintf(stderr, "Done: %s: (%zd bytes)\n", argv[i], n_read); - } -} Index: lib/fuzzer/test/AFLDriverTest.cpp =================================================================== --- lib/fuzzer/test/AFLDriverTest.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Contains dummy functions used to avoid dependency on AFL. -#include -#include -#include - -extern "C" void __afl_manual_init() {} - -extern "C" int __afl_persistent_loop(unsigned int N) { - static int Count = N; - fprintf(stderr, "__afl_persistent_loop calle, Count = %d\n", Count); - if (Count--) return 1; - return 0; -} - -// This declaration exists to prevent the Darwin linker -// from complaining about this being a missing weak symbol. -extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { - fprintf(stderr, "LLVMFuzzerInitialize called\n"); - return 0; -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - fprintf(stderr, "LLVMFuzzerTestOneInput called; Size = %zd\n", Size); - return 0; -} Index: lib/fuzzer/test/AbsNegAndConstant64Test.cpp =================================================================== --- lib/fuzzer/test/AbsNegAndConstant64Test.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// abs(x) < 0 and y == Const puzzle, 64-bit variant. -#include -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < 16) return 0; - int64_t x; - uint64_t y; - memcpy(&x, Data, sizeof(x)); - memcpy(&y, Data + sizeof(x), sizeof(y)); - if (llabs(x) < 0 && y == 0xbaddcafedeadbeefULL) { - printf("BINGO; Found the target, exiting; x = 0x%lx y 0x%lx\n", x, y); - fflush(stdout); - exit(1); - } - return 0; -} - Index: lib/fuzzer/test/AbsNegAndConstantTest.cpp =================================================================== --- lib/fuzzer/test/AbsNegAndConstantTest.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// abs(x) < 0 and y == Const puzzle. -#include -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < 8) return 0; - int x; - unsigned y; - memcpy(&x, Data, sizeof(x)); - memcpy(&y, Data + sizeof(x), sizeof(y)); - if (abs(x) < 0 && y == 0xbaddcafe) { - printf("BINGO; Found the target, exiting; x = 0x%x y 0x%x\n", x, y); - fflush(stdout); - exit(1); - } - return 0; -} - Index: lib/fuzzer/test/AccumulateAllocationsTest.cpp =================================================================== --- lib/fuzzer/test/AccumulateAllocationsTest.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Test with a more mallocs than frees, but no leak. -#include -#include - -const int kAllocatedPointersSize = 10000; -int NumAllocatedPointers = 0; -int *AllocatedPointers[kAllocatedPointersSize]; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (NumAllocatedPointers < kAllocatedPointersSize) - AllocatedPointers[NumAllocatedPointers++] = new int; - return 0; -} - Index: lib/fuzzer/test/BadStrcmpTest.cpp =================================================================== --- lib/fuzzer/test/BadStrcmpTest.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Test that we don't creash in case of bad strcmp params. -#include -#include -#include - -static volatile int Sink; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size != 10) return 0; - // Data is not zero-terminated, so this call is bad. - // Still, there are cases when such calles appear, see e.g. - // https://bugs.llvm.org/show_bug.cgi?id=32357 - Sink = strcmp(reinterpret_cast(Data), "123456789"); - return 0; -} - Index: lib/fuzzer/test/BogusInitializeTest.cpp =================================================================== --- lib/fuzzer/test/BogusInitializeTest.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Make sure LLVMFuzzerInitialize does not change argv[0]. -#include -#include - -extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { - ***argv = 'X'; - return 0; -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - return 0; -} Index: lib/fuzzer/test/BufferOverflowOnInput.cpp =================================================================== --- lib/fuzzer/test/BufferOverflowOnInput.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find the string "Hi!". -#include -#include -#include -#include -#include -#include - -static volatile bool SeedLargeBuffer; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - assert(Data); - if (Size >= 4) - SeedLargeBuffer = true; - if (Size == 3 && SeedLargeBuffer && Data[3]) { - std::cout << "Woops, reading Data[3] w/o crashing\n" << std::flush; - exit(1); - } - return 0; -} - Index: lib/fuzzer/test/CMakeLists.txt =================================================================== --- lib/fuzzer/test/CMakeLists.txt +++ /dev/null @@ -1,66 +0,0 @@ - -if(APPLE) - # LeakSanitizer is not supported on OSX and Windows right now - set(HAS_LSAN 0) - message(WARNING "LeakSanitizer is not supported." - " Building and running LibFuzzer LeakSanitizer tests is disabled." - ) -else() - set(HAS_LSAN 1) -endif() - -############################################################################### -# Unit tests -############################################################################### - -add_custom_target(FuzzerUnitTests) -set_target_properties(FuzzerUnitTests PROPERTIES FOLDER "libFuzzer tests") - -add_executable(LLVMFuzzer-Unittest FuzzerUnittest.cpp) - -target_link_libraries(LLVMFuzzer-Unittest - gtest - gtest_main - LLVMFuzzerNoMain - ) - -target_include_directories(LLVMFuzzer-Unittest PRIVATE - "${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include" - ) - -set_target_properties(LLVMFuzzer-Unittest - PROPERTIES RUNTIME_OUTPUT_DIRECTORY - "${CMAKE_CURRENT_BINARY_DIR}" -) - -include_directories(..) - -############################################################################### -# Configure lit to run the tests -# -# Note this is done after declaring all tests so we can inform lit if any tests -# need to be disabled. -############################################################################### - -# Use just-built Clang to compile/link tests on all platforms, except for -# Windows where we need to use clang-cl instead. -set(LIBFUZZER_TEST_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang) -set(LIBFUZZER_TEST_CXX_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++) - -# LIT-based libFuzzer tests. -configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg - ) - -# libFuzzer unit tests. -configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/unit/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/unit/lit.site.cfg - ) - -add_lit_testsuite(check-fuzzer "Running Fuzzer tests" - ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS LLVMFuzzer-Unittest) - -add_dependencies(check-fuzzer LLVMFuzzer asan clang llvm-symbolizer FileCheck sancov not) Index: lib/fuzzer/test/CallerCalleeTest.cpp =================================================================== --- lib/fuzzer/test/CallerCalleeTest.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. -// Try to find the target using the indirect caller-callee pairs. -#include -#include -#include -#include -#include - -typedef void (*F)(); -static F t[256]; - -void f34() { - std::cerr << "BINGO\n"; - exit(1); -} -void f23() { t[(unsigned)'d'] = f34;} -void f12() { t[(unsigned)'c'] = f23;} -void f01() { t[(unsigned)'b'] = f12;} -void f00() {} - -static F t0[256] = { - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, - f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, -}; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < 4) return 0; - // Spoof the counters. - for (int i = 0; i < 200; i++) { - f23(); - f12(); - f01(); - } - memcpy(t, t0, sizeof(t)); - t[(unsigned)'a'] = f01; - t[Data[0]](); - t[Data[1]](); - t[Data[2]](); - t[Data[3]](); - return 0; -} - Index: lib/fuzzer/test/CleanseTest.cpp =================================================================== --- lib/fuzzer/test/CleanseTest.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Test the the fuzzer is able to 'cleanse' the reproducer -// by replacing all irrelevant bytes with garbage. -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size >= 20 && Data[1] == '1' && Data[5] == '5' && Data[10] == 'A' && - Data[19] == 'Z') - abort(); - return 0; -} - Index: lib/fuzzer/test/CounterTest.cpp =================================================================== --- lib/fuzzer/test/CounterTest.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Test for a fuzzer: must find the case where a particular basic block is -// executed many times. -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - int Num = 0; - for (size_t i = 0; i < Size; i++) - if (Data[i] == 'A' + i) - Num++; - if (Num >= 4) { - std::cerr << "BINGO!\n"; - exit(1); - } - return 0; -} Index: lib/fuzzer/test/CustomCrossOverAndMutateTest.cpp =================================================================== --- lib/fuzzer/test/CustomCrossOverAndMutateTest.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Test that libFuzzer does not crash when LLVMFuzzerMutate called from -// LLVMFuzzerCustomCrossOver. -#include -#include -#include -#include -#include -#include -#include - -#include "FuzzerInterface.h" - -static volatile int sink; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - std::string Str(reinterpret_cast(Data), Size); - if (Size && Data[0] == '0') - sink++; - return 0; -} - -extern "C" size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, - const uint8_t *Data2, size_t Size2, - uint8_t *Out, size_t MaxOutSize, - unsigned int Seed) { - std::vector Buffer(MaxOutSize * 10); - LLVMFuzzerMutate(Buffer.data(), Buffer.size(), Buffer.size()); - size_t Size = std::min(Size1, MaxOutSize); - memcpy(Out, Data1, Size); - return Size; -} Index: lib/fuzzer/test/CustomCrossOverTest.cpp =================================================================== --- lib/fuzzer/test/CustomCrossOverTest.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a cutom mutator. -#include -#include -#include -#include -#include -#include -#include -#include - -#include "FuzzerInterface.h" - -static const char *Separator = "-_^_-"; -static const char *Target = "012-_^_-abc"; - -static volatile int sink; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - assert(Data); - std::string Str(reinterpret_cast(Data), Size); - - // Ensure that two different elements exist in the corpus. - if (Size && Data[0] == '0') sink++; - if (Size && Data[0] == 'a') sink--; - - if (Str.find(Target) != std::string::npos) { - std::cout << "BINGO; Found the target, exiting\n" << std::flush; - exit(1); - } - return 0; -} - -extern "C" size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, - const uint8_t *Data2, size_t Size2, - uint8_t *Out, size_t MaxOutSize, - unsigned int Seed) { - static bool Printed; - static size_t SeparatorLen = strlen(Separator); - - if (!Printed) { - std::cerr << "In LLVMFuzzerCustomCrossover\n"; - Printed = true; - } - - std::mt19937 R(Seed); - - size_t Offset1 = 0; - size_t Len1 = R() % (Size1 - Offset1); - size_t Offset2 = 0; - size_t Len2 = R() % (Size2 - Offset2); - size_t Size = Len1 + Len2 + SeparatorLen; - - if (Size > MaxOutSize) - return 0; - - memcpy(Out, Data1 + Offset1, Len1); - memcpy(Out + Len1, Separator, SeparatorLen); - memcpy(Out + Len1 + SeparatorLen, Data2 + Offset2, Len2); - - return Len1 + Len2 + SeparatorLen; -} Index: lib/fuzzer/test/CustomMutatorTest.cpp =================================================================== --- lib/fuzzer/test/CustomMutatorTest.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a cutom mutator. -#include -#include -#include -#include -#include -#include - -#include "FuzzerInterface.h" - -static volatile int Sink; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - assert(Data); - if (Size > 0 && Data[0] == 'H') { - Sink = 1; - if (Size > 1 && Data[1] == 'i') { - Sink = 2; - if (Size > 2 && Data[2] == '!') { - std::cout << "BINGO; Found the target, exiting\n" << std::flush; - exit(1); - } - } - } - return 0; -} - -extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, - size_t MaxSize, unsigned int Seed) { - static bool Printed; - if (!Printed) { - std::cerr << "In LLVMFuzzerCustomMutator\n"; - Printed = true; - } - return LLVMFuzzerMutate(Data, Size, MaxSize); -} Index: lib/fuzzer/test/CxxStringEqTest.cpp =================================================================== --- lib/fuzzer/test/CxxStringEqTest.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. Must find a specific string -// used in std::string operator ==. -#include -#include -#include -#include -#include - -static volatile int Sink; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - std::string Str((const char*)Data, Size); - bool Eq = Str == "FooBar"; - Sink = Str == "123456"; // Try to confuse the fuzzer - if (Eq) { - std::cout << "BINGO; Found the target, exiting\n"; - std::cout.flush(); - abort(); - } - return 0; -} - Index: lib/fuzzer/test/DSO1.cpp =================================================================== --- lib/fuzzer/test/DSO1.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Source code for a simple DSO. -#ifdef _WIN32 -__declspec( dllexport ) -#endif -int DSO1(int a) { - if (a < 123456) - return 0; - return 1; -} - -void Uncovered1() { } Index: lib/fuzzer/test/DSO2.cpp =================================================================== --- lib/fuzzer/test/DSO2.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Source code for a simple DSO. -#ifdef _WIN32 -__declspec( dllexport ) -#endif -int DSO2(int a) { - if (a < 3598235) - return 0; - return 1; -} - -void Uncovered2() {} Index: lib/fuzzer/test/DSOTestExtra.cpp =================================================================== --- lib/fuzzer/test/DSOTestExtra.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Source code for a simple DSO. - -int DSOTestExtra(int a) { - if (a < 452345) - return 0; - return 1; -} - Index: lib/fuzzer/test/DSOTestMain.cpp =================================================================== --- lib/fuzzer/test/DSOTestMain.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Source code for a simple DSO. - -#include -#include -#include -#include -extern int DSO1(int a); -extern int DSO2(int a); -extern int DSOTestExtra(int a); - -static volatile int *nil = 0; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - int x, y, z; - if (Size < sizeof(int) * 3) { - x = y = z = 0; - } else { - memcpy(&x, Data + 0 * sizeof(int), sizeof(int)); - memcpy(&y, Data + 1 * sizeof(int), sizeof(int)); - memcpy(&z, Data + 2 * sizeof(int), sizeof(int)); - } - int sum = DSO1(x) + DSO2(y) + (z ? DSOTestExtra(z) : 0); - if (sum == 3) { - fprintf(stderr, "BINGO %d %d %d\n", x, y, z); - *nil = 0; - } - return 0; -} Index: lib/fuzzer/test/DeepRecursionTest.cpp =================================================================== --- lib/fuzzer/test/DeepRecursionTest.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find the deep recursion. -// To generate a crashy input: -// for((i=0;i<110;i++)); do echo -n ABCDEFGHIJ >> INPUT; done -#include -#include -#include - -static volatile int Sink; - -void Recursive(const uint8_t *Data, size_t Size, int Depth) { - if (Depth > 1000) abort(); - if (!Size) return; - if (*Data == ('A' + Depth % 10)) - Recursive(Data + 1, Size - 1, Depth + 1); - Sink++; -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - Recursive(Data, Size, 0); - return 0; -} - Index: lib/fuzzer/test/DivTest.cpp =================================================================== --- lib/fuzzer/test/DivTest.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer: find the interesting argument for div. -#include -#include -#include -#include -#include - -static volatile int Sink; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < 4) return 0; - int a; - memcpy(&a, Data, 4); - Sink = 12345678 / (987654 - a); - return 0; -} - Index: lib/fuzzer/test/EmptyTest.cpp =================================================================== --- lib/fuzzer/test/EmptyTest.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -// A fuzzer with empty target function. - -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - return 0; -} Index: lib/fuzzer/test/EquivalenceATest.cpp =================================================================== --- lib/fuzzer/test/EquivalenceATest.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -#include -#include -#include - -// Test for libFuzzer's "equivalence" fuzzing, part A. -extern "C" void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size); -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - // fprintf(stderr, "A %zd\n", Size); - uint8_t Result[50]; - if (Size > 50) Size = 50; - for (size_t i = 0; i < Size; i++) - Result[Size - i - 1] = Data[i]; - LLVMFuzzerAnnounceOutput(Result, Size); - return 0; -} Index: lib/fuzzer/test/EquivalenceBTest.cpp =================================================================== --- lib/fuzzer/test/EquivalenceBTest.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -#include -#include -#include - -// Test for libFuzzer's "equivalence" fuzzing, part B. -extern "C" void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size); -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - // fprintf(stderr, "B %zd\n", Size); - uint8_t Result[50]; - if (Size > 50) Size = 50; - for (size_t i = 0; i < Size; i++) - Result[Size - i - 1] = Data[i]; - - // Be a bit different from EquivalenceATest - if (Size > 10 && Data[5] == 'B' && Data[6] == 'C' && Data[7] == 'D') { - static int c; - if (!c) - fprintf(stderr, "ZZZZZZZ\n"); - c = 1; - Result[2]++; - } - - LLVMFuzzerAnnounceOutput(Result, Size); - return 0; -} Index: lib/fuzzer/test/FlagsTest.cpp =================================================================== --- lib/fuzzer/test/FlagsTest.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Parse some flags -#include -#include - -static std::vector Flags; - -extern "C" int LLVMFuzzerInitialize(int *Argc, char ***Argv) { - // Parse --flags and anything after -ignore_remaining_args=1 is passed. - int I = 1; - while (I < *Argc) { - std::string S((*Argv)[I++]); - if (S == "-ignore_remaining_args=1") - break; - if (S.substr(0, 2) == "--") - Flags.push_back(S); - } - while (I < *Argc) - Flags.push_back(std::string((*Argv)[I++])); - - return 0; -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - fprintf(stderr, "BINGO "); - for (auto Flag : Flags) - fprintf(stderr, "%s ", Flag.c_str()); - fprintf(stderr, "\n"); - exit(0); -} Index: lib/fuzzer/test/FourIndependentBranchesTest.cpp =================================================================== --- lib/fuzzer/test/FourIndependentBranchesTest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find the string "FUZZ". -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(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); - } - return 0; -} - Index: lib/fuzzer/test/FullCoverageSetTest.cpp =================================================================== --- lib/fuzzer/test/FullCoverageSetTest.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find the string "FUZZER". -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(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 (Size > 4 && Data[4] == 'E') bits |= 16; - if (Size > 5 && Data[5] == 'R') bits |= 32; - if (bits == 63) { - std::cerr << "BINGO!\n"; - exit(1); - } - return 0; -} - Index: lib/fuzzer/test/FuzzerUnittest.cpp =================================================================== --- lib/fuzzer/test/FuzzerUnittest.cpp +++ /dev/null @@ -1,763 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Avoid ODR violations (LibFuzzer is built without ASan and this test is built -// with ASan) involving C++ standard library types when using libcxx. -#define _LIBCPP_HAS_NO_ASAN - -// Do not attempt to use LLVM ostream from gtest. -#define GTEST_NO_LLVM_RAW_OSTREAM 1 - -#include "FuzzerCorpus.h" -#include "FuzzerDictionary.h" -#include "FuzzerInternal.h" -#include "FuzzerMerge.h" -#include "FuzzerMutate.h" -#include "FuzzerRandom.h" -#include "FuzzerTracePC.h" -#include "gtest/gtest.h" -#include -#include -#include - -using namespace fuzzer; - -// For now, have LLVMFuzzerTestOneInput just to make it link. -// Later we may want to make unittests that actually call LLVMFuzzerTestOneInput. -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - abort(); -} - -TEST(Fuzzer, CrossOver) { - std::unique_ptr t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); - Unit A({0, 1, 2}), B({5, 6, 7}); - Unit C; - Unit Expected[] = { - { 0 }, - { 0, 1 }, - { 0, 5 }, - { 0, 1, 2 }, - { 0, 1, 5 }, - { 0, 5, 1 }, - { 0, 5, 6 }, - { 0, 1, 2, 5 }, - { 0, 1, 5, 2 }, - { 0, 1, 5, 6 }, - { 0, 5, 1, 2 }, - { 0, 5, 1, 6 }, - { 0, 5, 6, 1 }, - { 0, 5, 6, 7 }, - { 0, 1, 2, 5, 6 }, - { 0, 1, 5, 2, 6 }, - { 0, 1, 5, 6, 2 }, - { 0, 1, 5, 6, 7 }, - { 0, 5, 1, 2, 6 }, - { 0, 5, 1, 6, 2 }, - { 0, 5, 1, 6, 7 }, - { 0, 5, 6, 1, 2 }, - { 0, 5, 6, 1, 7 }, - { 0, 5, 6, 7, 1 }, - { 0, 1, 2, 5, 6, 7 }, - { 0, 1, 5, 2, 6, 7 }, - { 0, 1, 5, 6, 2, 7 }, - { 0, 1, 5, 6, 7, 2 }, - { 0, 5, 1, 2, 6, 7 }, - { 0, 5, 1, 6, 2, 7 }, - { 0, 5, 1, 6, 7, 2 }, - { 0, 5, 6, 1, 2, 7 }, - { 0, 5, 6, 1, 7, 2 }, - { 0, 5, 6, 7, 1, 2 } - }; - for (size_t Len = 1; Len < 8; Len++) { - std::set FoundUnits, ExpectedUnitsWitThisLength; - for (int Iter = 0; Iter < 3000; Iter++) { - C.resize(Len); - size_t NewSize = MD.CrossOver(A.data(), A.size(), B.data(), B.size(), - C.data(), C.size()); - C.resize(NewSize); - FoundUnits.insert(C); - } - for (const Unit &U : Expected) - if (U.size() <= Len) - ExpectedUnitsWitThisLength.insert(U); - EXPECT_EQ(ExpectedUnitsWitThisLength, FoundUnits); - } -} - -TEST(Fuzzer, Hash) { - uint8_t A[] = {'a', 'b', 'c'}; - fuzzer::Unit U(A, A + sizeof(A)); - EXPECT_EQ("a9993e364706816aba3e25717850c26c9cd0d89d", fuzzer::Hash(U)); - U.push_back('d'); - EXPECT_EQ("81fe8bfe87576c3ecb22426f8e57847382917acf", fuzzer::Hash(U)); -} - -typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size, - size_t MaxSize); - -void TestEraseBytes(Mutator M, int NumIter) { - std::unique_ptr t(new ExternalFunctions()); - fuzzer::EF = t.get(); - uint8_t REM0[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t REM1[8] = {0x00, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t REM2[8] = {0x00, 0x11, 0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t REM3[8] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x77}; - uint8_t REM4[8] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x66, 0x77}; - uint8_t REM5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x66, 0x77}; - uint8_t REM6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x77}; - uint8_t REM7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; - - uint8_t REM8[6] = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t REM9[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; - uint8_t REM10[6] = {0x00, 0x11, 0x22, 0x55, 0x66, 0x77}; - - uint8_t REM11[5] = {0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t REM12[5] = {0x00, 0x11, 0x22, 0x33, 0x44}; - uint8_t REM13[5] = {0x00, 0x44, 0x55, 0x66, 0x77}; - - - Random Rand(0); - MutationDispatcher MD(Rand, {}); - int FoundMask = 0; - for (int i = 0; i < NumIter; i++) { - uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - size_t NewSize = (MD.*M)(T, sizeof(T), sizeof(T)); - if (NewSize == 7 && !memcmp(REM0, T, 7)) FoundMask |= 1 << 0; - if (NewSize == 7 && !memcmp(REM1, T, 7)) FoundMask |= 1 << 1; - if (NewSize == 7 && !memcmp(REM2, T, 7)) FoundMask |= 1 << 2; - if (NewSize == 7 && !memcmp(REM3, T, 7)) FoundMask |= 1 << 3; - if (NewSize == 7 && !memcmp(REM4, T, 7)) FoundMask |= 1 << 4; - if (NewSize == 7 && !memcmp(REM5, T, 7)) FoundMask |= 1 << 5; - if (NewSize == 7 && !memcmp(REM6, T, 7)) FoundMask |= 1 << 6; - if (NewSize == 7 && !memcmp(REM7, T, 7)) FoundMask |= 1 << 7; - - if (NewSize == 6 && !memcmp(REM8, T, 6)) FoundMask |= 1 << 8; - if (NewSize == 6 && !memcmp(REM9, T, 6)) FoundMask |= 1 << 9; - if (NewSize == 6 && !memcmp(REM10, T, 6)) FoundMask |= 1 << 10; - - if (NewSize == 5 && !memcmp(REM11, T, 5)) FoundMask |= 1 << 11; - if (NewSize == 5 && !memcmp(REM12, T, 5)) FoundMask |= 1 << 12; - if (NewSize == 5 && !memcmp(REM13, T, 5)) FoundMask |= 1 << 13; - } - EXPECT_EQ(FoundMask, (1 << 14) - 1); -} - -TEST(FuzzerMutate, EraseBytes1) { - TestEraseBytes(&MutationDispatcher::Mutate_EraseBytes, 200); -} -TEST(FuzzerMutate, EraseBytes2) { - TestEraseBytes(&MutationDispatcher::Mutate, 2000); -} - -void TestInsertByte(Mutator M, int NumIter) { - std::unique_ptr t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); - int FoundMask = 0; - uint8_t INS0[8] = {0xF1, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; - uint8_t INS1[8] = {0x00, 0xF2, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; - uint8_t INS2[8] = {0x00, 0x11, 0xF3, 0x22, 0x33, 0x44, 0x55, 0x66}; - uint8_t INS3[8] = {0x00, 0x11, 0x22, 0xF4, 0x33, 0x44, 0x55, 0x66}; - uint8_t INS4[8] = {0x00, 0x11, 0x22, 0x33, 0xF5, 0x44, 0x55, 0x66}; - uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF6, 0x55, 0x66}; - uint8_t INS6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF7, 0x66}; - uint8_t INS7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF8}; - for (int i = 0; i < NumIter; i++) { - uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; - size_t NewSize = (MD.*M)(T, 7, 8); - if (NewSize == 8 && !memcmp(INS0, T, 8)) FoundMask |= 1 << 0; - if (NewSize == 8 && !memcmp(INS1, T, 8)) FoundMask |= 1 << 1; - if (NewSize == 8 && !memcmp(INS2, T, 8)) FoundMask |= 1 << 2; - if (NewSize == 8 && !memcmp(INS3, T, 8)) FoundMask |= 1 << 3; - if (NewSize == 8 && !memcmp(INS4, T, 8)) FoundMask |= 1 << 4; - if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5; - if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6; - if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7; - } - EXPECT_EQ(FoundMask, 255); -} - -TEST(FuzzerMutate, InsertByte1) { - TestInsertByte(&MutationDispatcher::Mutate_InsertByte, 1 << 15); -} -TEST(FuzzerMutate, InsertByte2) { - TestInsertByte(&MutationDispatcher::Mutate, 1 << 17); -} - -void TestInsertRepeatedBytes(Mutator M, int NumIter) { - std::unique_ptr t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); - int FoundMask = 0; - uint8_t INS0[7] = {0x00, 0x11, 0x22, 0x33, 'a', 'a', 'a'}; - uint8_t INS1[7] = {0x00, 0x11, 0x22, 'a', 'a', 'a', 0x33}; - uint8_t INS2[7] = {0x00, 0x11, 'a', 'a', 'a', 0x22, 0x33}; - uint8_t INS3[7] = {0x00, 'a', 'a', 'a', 0x11, 0x22, 0x33}; - uint8_t INS4[7] = {'a', 'a', 'a', 0x00, 0x11, 0x22, 0x33}; - - uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 'b', 'b', 'b', 'b'}; - uint8_t INS6[8] = {0x00, 0x11, 0x22, 'b', 'b', 'b', 'b', 0x33}; - uint8_t INS7[8] = {0x00, 0x11, 'b', 'b', 'b', 'b', 0x22, 0x33}; - uint8_t INS8[8] = {0x00, 'b', 'b', 'b', 'b', 0x11, 0x22, 0x33}; - uint8_t INS9[8] = {'b', 'b', 'b', 'b', 0x00, 0x11, 0x22, 0x33}; - - for (int i = 0; i < NumIter; i++) { - uint8_t T[8] = {0x00, 0x11, 0x22, 0x33}; - size_t NewSize = (MD.*M)(T, 4, 8); - if (NewSize == 7 && !memcmp(INS0, T, 7)) FoundMask |= 1 << 0; - if (NewSize == 7 && !memcmp(INS1, T, 7)) FoundMask |= 1 << 1; - if (NewSize == 7 && !memcmp(INS2, T, 7)) FoundMask |= 1 << 2; - if (NewSize == 7 && !memcmp(INS3, T, 7)) FoundMask |= 1 << 3; - if (NewSize == 7 && !memcmp(INS4, T, 7)) FoundMask |= 1 << 4; - - if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5; - if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6; - if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7; - if (NewSize == 8 && !memcmp(INS8, T, 8)) FoundMask |= 1 << 8; - if (NewSize == 8 && !memcmp(INS9, T, 8)) FoundMask |= 1 << 9; - - } - EXPECT_EQ(FoundMask, (1 << 10) - 1); -} - -TEST(FuzzerMutate, InsertRepeatedBytes1) { - TestInsertRepeatedBytes(&MutationDispatcher::Mutate_InsertRepeatedBytes, 10000); -} -TEST(FuzzerMutate, InsertRepeatedBytes2) { - TestInsertRepeatedBytes(&MutationDispatcher::Mutate, 300000); -} - -void TestChangeByte(Mutator M, int NumIter) { - std::unique_ptr t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); - int FoundMask = 0; - uint8_t CH0[8] = {0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t CH1[8] = {0x00, 0xF1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t CH2[8] = {0x00, 0x11, 0xF2, 0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t CH3[8] = {0x00, 0x11, 0x22, 0xF3, 0x44, 0x55, 0x66, 0x77}; - uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0xF4, 0x55, 0x66, 0x77}; - uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF5, 0x66, 0x77}; - uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF5, 0x77}; - uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7}; - for (int i = 0; i < NumIter; i++) { - uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - size_t NewSize = (MD.*M)(T, 8, 9); - if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0; - if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1; - if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2; - if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3; - if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4; - if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5; - if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6; - if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7; - } - EXPECT_EQ(FoundMask, 255); -} - -TEST(FuzzerMutate, ChangeByte1) { - TestChangeByte(&MutationDispatcher::Mutate_ChangeByte, 1 << 15); -} -TEST(FuzzerMutate, ChangeByte2) { - TestChangeByte(&MutationDispatcher::Mutate, 1 << 17); -} - -void TestChangeBit(Mutator M, int NumIter) { - std::unique_ptr t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); - int FoundMask = 0; - uint8_t CH0[8] = {0x01, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t CH1[8] = {0x00, 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t CH2[8] = {0x00, 0x11, 0x02, 0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t CH3[8] = {0x00, 0x11, 0x22, 0x37, 0x44, 0x55, 0x66, 0x77}; - uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x54, 0x55, 0x66, 0x77}; - uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x54, 0x66, 0x77}; - uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x76, 0x77}; - uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7}; - for (int i = 0; i < NumIter; i++) { - uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - size_t NewSize = (MD.*M)(T, 8, 9); - if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0; - if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1; - if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2; - if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3; - if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4; - if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5; - if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6; - if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7; - } - EXPECT_EQ(FoundMask, 255); -} - -TEST(FuzzerMutate, ChangeBit1) { - TestChangeBit(&MutationDispatcher::Mutate_ChangeBit, 1 << 16); -} -TEST(FuzzerMutate, ChangeBit2) { - TestChangeBit(&MutationDispatcher::Mutate, 1 << 18); -} - -void TestShuffleBytes(Mutator M, int NumIter) { - std::unique_ptr t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); - int FoundMask = 0; - uint8_t CH0[7] = {0x00, 0x22, 0x11, 0x33, 0x44, 0x55, 0x66}; - uint8_t CH1[7] = {0x11, 0x00, 0x33, 0x22, 0x44, 0x55, 0x66}; - uint8_t CH2[7] = {0x00, 0x33, 0x11, 0x22, 0x44, 0x55, 0x66}; - uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x33}; - uint8_t CH4[7] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x44, 0x66}; - for (int i = 0; i < NumIter; i++) { - uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; - size_t NewSize = (MD.*M)(T, 7, 7); - if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0; - if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1; - if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2; - if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3; - if (NewSize == 7 && !memcmp(CH4, T, 7)) FoundMask |= 1 << 4; - } - EXPECT_EQ(FoundMask, 31); -} - -TEST(FuzzerMutate, ShuffleBytes1) { - TestShuffleBytes(&MutationDispatcher::Mutate_ShuffleBytes, 1 << 16); -} -TEST(FuzzerMutate, ShuffleBytes2) { - TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 20); -} - -void TestCopyPart(Mutator M, int NumIter) { - std::unique_ptr t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); - int FoundMask = 0; - uint8_t CH0[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11}; - uint8_t CH1[7] = {0x55, 0x66, 0x22, 0x33, 0x44, 0x55, 0x66}; - uint8_t CH2[7] = {0x00, 0x55, 0x66, 0x33, 0x44, 0x55, 0x66}; - uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x66}; - uint8_t CH4[7] = {0x00, 0x11, 0x11, 0x22, 0x33, 0x55, 0x66}; - - for (int i = 0; i < NumIter; i++) { - uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; - size_t NewSize = (MD.*M)(T, 7, 7); - if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0; - if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1; - if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2; - if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3; - if (NewSize == 7 && !memcmp(CH4, T, 7)) FoundMask |= 1 << 4; - } - - uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11, 0x22}; - uint8_t CH6[8] = {0x22, 0x33, 0x44, 0x00, 0x11, 0x22, 0x33, 0x44}; - uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x33, 0x44}; - uint8_t CH8[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x22, 0x33, 0x44}; - uint8_t CH9[8] = {0x00, 0x11, 0x22, 0x22, 0x33, 0x44, 0x33, 0x44}; - - for (int i = 0; i < NumIter; i++) { - uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - size_t NewSize = (MD.*M)(T, 5, 8); - if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5; - if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6; - if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7; - if (NewSize == 8 && !memcmp(CH8, T, 8)) FoundMask |= 1 << 8; - if (NewSize == 8 && !memcmp(CH9, T, 8)) FoundMask |= 1 << 9; - } - - EXPECT_EQ(FoundMask, 1023); -} - -TEST(FuzzerMutate, CopyPart1) { - TestCopyPart(&MutationDispatcher::Mutate_CopyPart, 1 << 10); -} -TEST(FuzzerMutate, CopyPart2) { - TestCopyPart(&MutationDispatcher::Mutate, 1 << 13); -} - -void TestAddWordFromDictionary(Mutator M, int NumIter) { - std::unique_ptr t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); - uint8_t Word1[4] = {0xAA, 0xBB, 0xCC, 0xDD}; - uint8_t Word2[3] = {0xFF, 0xEE, 0xEF}; - MD.AddWordToManualDictionary(Word(Word1, sizeof(Word1))); - MD.AddWordToManualDictionary(Word(Word2, sizeof(Word2))); - int FoundMask = 0; - uint8_t CH0[7] = {0x00, 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD}; - uint8_t CH1[7] = {0x00, 0x11, 0xAA, 0xBB, 0xCC, 0xDD, 0x22}; - uint8_t CH2[7] = {0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22}; - uint8_t CH3[7] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x11, 0x22}; - uint8_t CH4[6] = {0x00, 0x11, 0x22, 0xFF, 0xEE, 0xEF}; - uint8_t CH5[6] = {0x00, 0x11, 0xFF, 0xEE, 0xEF, 0x22}; - uint8_t CH6[6] = {0x00, 0xFF, 0xEE, 0xEF, 0x11, 0x22}; - uint8_t CH7[6] = {0xFF, 0xEE, 0xEF, 0x00, 0x11, 0x22}; - for (int i = 0; i < NumIter; i++) { - uint8_t T[7] = {0x00, 0x11, 0x22}; - size_t NewSize = (MD.*M)(T, 3, 7); - if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0; - if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1; - if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2; - if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3; - if (NewSize == 6 && !memcmp(CH4, T, 6)) FoundMask |= 1 << 4; - if (NewSize == 6 && !memcmp(CH5, T, 6)) FoundMask |= 1 << 5; - if (NewSize == 6 && !memcmp(CH6, T, 6)) FoundMask |= 1 << 6; - if (NewSize == 6 && !memcmp(CH7, T, 6)) FoundMask |= 1 << 7; - } - EXPECT_EQ(FoundMask, 255); -} - -TEST(FuzzerMutate, AddWordFromDictionary1) { - TestAddWordFromDictionary( - &MutationDispatcher::Mutate_AddWordFromManualDictionary, 1 << 15); -} - -TEST(FuzzerMutate, AddWordFromDictionary2) { - TestAddWordFromDictionary(&MutationDispatcher::Mutate, 1 << 15); -} - -void TestChangeASCIIInteger(Mutator M, int NumIter) { - std::unique_ptr t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); - - uint8_t CH0[8] = {'1', '2', '3', '4', '5', '6', '7', '7'}; - uint8_t CH1[8] = {'1', '2', '3', '4', '5', '6', '7', '9'}; - uint8_t CH2[8] = {'2', '4', '6', '9', '1', '3', '5', '6'}; - uint8_t CH3[8] = {'0', '6', '1', '7', '2', '8', '3', '9'}; - int FoundMask = 0; - for (int i = 0; i < NumIter; i++) { - uint8_t T[8] = {'1', '2', '3', '4', '5', '6', '7', '8'}; - size_t NewSize = (MD.*M)(T, 8, 8); - /**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0; - else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1; - else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2; - else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3; - else if (NewSize == 8) FoundMask |= 1 << 4; - } - EXPECT_EQ(FoundMask, 31); -} - -TEST(FuzzerMutate, ChangeASCIIInteger1) { - TestChangeASCIIInteger(&MutationDispatcher::Mutate_ChangeASCIIInteger, - 1 << 15); -} - -TEST(FuzzerMutate, ChangeASCIIInteger2) { - TestChangeASCIIInteger(&MutationDispatcher::Mutate, 1 << 15); -} - -void TestChangeBinaryInteger(Mutator M, int NumIter) { - std::unique_ptr t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); - - uint8_t CH0[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x79}; - uint8_t CH1[8] = {0x00, 0x11, 0x22, 0x31, 0x44, 0x55, 0x66, 0x77}; - uint8_t CH2[8] = {0xff, 0x10, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t CH3[8] = {0x00, 0x11, 0x2a, 0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x4f, 0x66, 0x77}; - uint8_t CH5[8] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88}; - uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x00, 0x00, 0x00, 0x08, 0x77}; // Size - uint8_t CH7[8] = {0x00, 0x08, 0x00, 0x33, 0x44, 0x55, 0x66, 0x77}; // Sw(Size) - - int FoundMask = 0; - for (int i = 0; i < NumIter; i++) { - uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - size_t NewSize = (MD.*M)(T, 8, 8); - /**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0; - else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1; - else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2; - else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3; - else if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4; - else if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5; - else if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6; - else if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7; - } - EXPECT_EQ(FoundMask, 255); -} - -TEST(FuzzerMutate, ChangeBinaryInteger1) { - TestChangeBinaryInteger(&MutationDispatcher::Mutate_ChangeBinaryInteger, - 1 << 12); -} - -TEST(FuzzerMutate, ChangeBinaryInteger2) { - TestChangeBinaryInteger(&MutationDispatcher::Mutate, 1 << 15); -} - - -TEST(FuzzerDictionary, ParseOneDictionaryEntry) { - Unit U; - EXPECT_FALSE(ParseOneDictionaryEntry("", &U)); - EXPECT_FALSE(ParseOneDictionaryEntry(" ", &U)); - EXPECT_FALSE(ParseOneDictionaryEntry("\t ", &U)); - EXPECT_FALSE(ParseOneDictionaryEntry(" \" ", &U)); - EXPECT_FALSE(ParseOneDictionaryEntry(" zz\" ", &U)); - EXPECT_FALSE(ParseOneDictionaryEntry(" \"zz ", &U)); - EXPECT_FALSE(ParseOneDictionaryEntry(" \"\" ", &U)); - EXPECT_TRUE(ParseOneDictionaryEntry("\"a\"", &U)); - EXPECT_EQ(U, Unit({'a'})); - EXPECT_TRUE(ParseOneDictionaryEntry("\"abc\"", &U)); - EXPECT_EQ(U, Unit({'a', 'b', 'c'})); - EXPECT_TRUE(ParseOneDictionaryEntry("abc=\"abc\"", &U)); - EXPECT_EQ(U, Unit({'a', 'b', 'c'})); - EXPECT_FALSE(ParseOneDictionaryEntry("\"\\\"", &U)); - EXPECT_TRUE(ParseOneDictionaryEntry("\"\\\\\"", &U)); - EXPECT_EQ(U, Unit({'\\'})); - EXPECT_TRUE(ParseOneDictionaryEntry("\"\\xAB\"", &U)); - EXPECT_EQ(U, Unit({0xAB})); - EXPECT_TRUE(ParseOneDictionaryEntry("\"\\xABz\\xDE\"", &U)); - EXPECT_EQ(U, Unit({0xAB, 'z', 0xDE})); - EXPECT_TRUE(ParseOneDictionaryEntry("\"#\"", &U)); - EXPECT_EQ(U, Unit({'#'})); - EXPECT_TRUE(ParseOneDictionaryEntry("\"\\\"\"", &U)); - EXPECT_EQ(U, Unit({'"'})); -} - -TEST(FuzzerDictionary, ParseDictionaryFile) { - std::vector Units; - EXPECT_FALSE(ParseDictionaryFile("zzz\n", &Units)); - EXPECT_FALSE(ParseDictionaryFile("", &Units)); - EXPECT_TRUE(ParseDictionaryFile("\n", &Units)); - EXPECT_EQ(Units.size(), 0U); - EXPECT_TRUE(ParseDictionaryFile("#zzzz a b c d\n", &Units)); - EXPECT_EQ(Units.size(), 0U); - EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units)); - EXPECT_EQ(Units.size(), 0U); - EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units)); - EXPECT_EQ(Units.size(), 0U); - EXPECT_TRUE(ParseDictionaryFile(" #zzzz\naaa=\"aa\"", &Units)); - EXPECT_EQ(Units, std::vector({Unit({'a', 'a'})})); - EXPECT_TRUE( - ParseDictionaryFile(" #zzzz\naaa=\"aa\"\n\nabc=\"abc\"", &Units)); - EXPECT_EQ(Units, - std::vector({Unit({'a', 'a'}), Unit({'a', 'b', 'c'})})); -} - -TEST(FuzzerUtil, Base64) { - EXPECT_EQ("", Base64({})); - EXPECT_EQ("YQ==", Base64({'a'})); - EXPECT_EQ("eA==", Base64({'x'})); - EXPECT_EQ("YWI=", Base64({'a', 'b'})); - EXPECT_EQ("eHk=", Base64({'x', 'y'})); - EXPECT_EQ("YWJj", Base64({'a', 'b', 'c'})); - EXPECT_EQ("eHl6", Base64({'x', 'y', 'z'})); - EXPECT_EQ("YWJjeA==", Base64({'a', 'b', 'c', 'x'})); - EXPECT_EQ("YWJjeHk=", Base64({'a', 'b', 'c', 'x', 'y'})); - EXPECT_EQ("YWJjeHl6", Base64({'a', 'b', 'c', 'x', 'y', 'z'})); -} - -TEST(Corpus, Distribution) { - Random Rand(0); - std::unique_ptr C(new InputCorpus("")); - size_t N = 10; - size_t TriesPerUnit = 1<<16; - for (size_t i = 0; i < N; i++) - C->AddToCorpus(Unit{ static_cast(i) }, 1, false, {}); - - std::vector Hist(N); - for (size_t i = 0; i < N * TriesPerUnit; i++) { - Hist[C->ChooseUnitIdxToMutate(Rand)]++; - } - for (size_t i = 0; i < N; i++) { - // A weak sanity check that every unit gets invoked. - EXPECT_GT(Hist[i], TriesPerUnit / N / 3); - } -} - -TEST(Merge, Bad) { - const char *kInvalidInputs[] = { - "", - "x", - "3\nx", - "2\n3", - "2\n2", - "2\n2\nA\n", - "2\n2\nA\nB\nC\n", - "0\n0\n", - "1\n1\nA\nDONE 0", - "1\n1\nA\nSTARTED 1", - }; - Merger M; - for (auto S : kInvalidInputs) { - // fprintf(stderr, "TESTING:\n%s\n", S); - EXPECT_FALSE(M.Parse(S, false)); - } -} - -void EQ(const std::vector &A, const std::vector &B) { - EXPECT_EQ(A, B); -} - -void EQ(const std::vector &A, const std::vector &B) { - std::set a(A.begin(), A.end()); - std::set b(B.begin(), B.end()); - EXPECT_EQ(a, b); -} - -static void Merge(const std::string &Input, - const std::vector Result, - size_t NumNewFeatures) { - Merger M; - std::vector NewFiles; - EXPECT_TRUE(M.Parse(Input, true)); - std::stringstream SS; - M.PrintSummary(SS); - EXPECT_EQ(NumNewFeatures, M.Merge(&NewFiles)); - EXPECT_EQ(M.AllFeatures(), M.ParseSummary(SS)); - EQ(NewFiles, Result); -} - -TEST(Merge, Good) { - Merger M; - - EXPECT_TRUE(M.Parse("1\n0\nAA\n", false)); - EXPECT_EQ(M.Files.size(), 1U); - EXPECT_EQ(M.NumFilesInFirstCorpus, 0U); - EXPECT_EQ(M.Files[0].Name, "AA"); - EXPECT_TRUE(M.LastFailure.empty()); - EXPECT_EQ(M.FirstNotProcessedFile, 0U); - - EXPECT_TRUE(M.Parse("2\n1\nAA\nBB\nSTARTED 0 42\n", false)); - EXPECT_EQ(M.Files.size(), 2U); - EXPECT_EQ(M.NumFilesInFirstCorpus, 1U); - EXPECT_EQ(M.Files[0].Name, "AA"); - EXPECT_EQ(M.Files[1].Name, "BB"); - EXPECT_EQ(M.LastFailure, "AA"); - EXPECT_EQ(M.FirstNotProcessedFile, 1U); - - EXPECT_TRUE(M.Parse("3\n1\nAA\nBB\nC\n" - "STARTED 0 1000\n" - "DONE 0 1 2 3\n" - "STARTED 1 1001\n" - "DONE 1 4 5 6 \n" - "STARTED 2 1002\n" - "", true)); - EXPECT_EQ(M.Files.size(), 3U); - EXPECT_EQ(M.NumFilesInFirstCorpus, 1U); - EXPECT_EQ(M.Files[0].Name, "AA"); - EXPECT_EQ(M.Files[0].Size, 1000U); - EXPECT_EQ(M.Files[1].Name, "BB"); - EXPECT_EQ(M.Files[1].Size, 1001U); - EXPECT_EQ(M.Files[2].Name, "C"); - EXPECT_EQ(M.Files[2].Size, 1002U); - EXPECT_EQ(M.LastFailure, "C"); - EXPECT_EQ(M.FirstNotProcessedFile, 3U); - EQ(M.Files[0].Features, {1, 2, 3}); - EQ(M.Files[1].Features, {4, 5, 6}); - - - std::vector NewFiles; - - EXPECT_TRUE(M.Parse("3\n2\nAA\nBB\nC\n" - "STARTED 0 1000\nDONE 0 1 2 3\n" - "STARTED 1 1001\nDONE 1 4 5 6 \n" - "STARTED 2 1002\nDONE 2 6 1 3 \n" - "", true)); - EXPECT_EQ(M.Files.size(), 3U); - EXPECT_EQ(M.NumFilesInFirstCorpus, 2U); - EXPECT_TRUE(M.LastFailure.empty()); - EXPECT_EQ(M.FirstNotProcessedFile, 3U); - EQ(M.Files[0].Features, {1, 2, 3}); - EQ(M.Files[1].Features, {4, 5, 6}); - EQ(M.Files[2].Features, {1, 3, 6}); - EXPECT_EQ(0U, M.Merge(&NewFiles)); - EQ(NewFiles, {}); - - EXPECT_TRUE(M.Parse("3\n1\nA\nB\nC\n" - "STARTED 0 1000\nDONE 0 1 2 3\n" - "STARTED 1 1001\nDONE 1 4 5 6 \n" - "STARTED 2 1002\nDONE 2 6 1 3\n" - "", true)); - EQ(M.Files[0].Features, {1, 2, 3}); - EQ(M.Files[1].Features, {4, 5, 6}); - EQ(M.Files[2].Features, {1, 3, 6}); - EXPECT_EQ(3U, M.Merge(&NewFiles)); - EQ(NewFiles, {"B"}); - - // Same as the above, but with InitialFeatures. - EXPECT_TRUE(M.Parse("2\n0\nB\nC\n" - "STARTED 0 1001\nDONE 0 4 5 6 \n" - "STARTED 1 1002\nDONE 1 6 1 3\n" - "", true)); - EQ(M.Files[0].Features, {4, 5, 6}); - EQ(M.Files[1].Features, {1, 3, 6}); - EXPECT_EQ(3U, M.Merge({1, 2, 3}, &NewFiles)); - EQ(NewFiles, {"B"}); -} - -TEST(Merge, Merge) { - - Merge("3\n1\nA\nB\nC\n" - "STARTED 0 1000\nDONE 0 1 2 3\n" - "STARTED 1 1001\nDONE 1 4 5 6 \n" - "STARTED 2 1002\nDONE 2 6 1 3 \n", - {"B"}, 3); - - Merge("3\n0\nA\nB\nC\n" - "STARTED 0 2000\nDONE 0 1 2 3\n" - "STARTED 1 1001\nDONE 1 4 5 6 \n" - "STARTED 2 1002\nDONE 2 6 1 3 \n", - {"A", "B", "C"}, 6); - - Merge("4\n0\nA\nB\nC\nD\n" - "STARTED 0 2000\nDONE 0 1 2 3\n" - "STARTED 1 1101\nDONE 1 4 5 6 \n" - "STARTED 2 1102\nDONE 2 6 1 3 100 \n" - "STARTED 3 1000\nDONE 3 1 \n", - {"A", "B", "C", "D"}, 7); - - Merge("4\n1\nA\nB\nC\nD\n" - "STARTED 0 2000\nDONE 0 4 5 6 7 8\n" - "STARTED 1 1100\nDONE 1 1 2 3 \n" - "STARTED 2 1100\nDONE 2 2 3 \n" - "STARTED 3 1000\nDONE 3 1 \n", - {"B", "D"}, 3); -} - -TEST(Fuzzer, ForEachNonZeroByte) { - const size_t N = 64; - alignas(64) uint8_t Ar[N + 8] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 2, 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 5, 0, 6, 0, 0, - 0, 0, 0, 0, 0, 0, 7, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 8, - 9, 9, 9, 9, 9, 9, 9, 9, - }; - typedef std::vector > Vec; - Vec Res, Expected; - auto CB = [&](size_t FirstFeature, size_t Idx, uint8_t V) { - Res.push_back({FirstFeature + Idx, V}); - }; - ForEachNonZeroByte(Ar, Ar + N, 100, CB); - 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); -} Index: lib/fuzzer/test/InitializeTest.cpp =================================================================== --- lib/fuzzer/test/InitializeTest.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Make sure LLVMFuzzerInitialize is called. -#include -#include -#include -#include -#include -#include - -static char *argv0; - -extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { - assert(*argc > 0); - argv0 = **argv; - fprintf(stderr, "LLVMFuzzerInitialize: %s\n", argv0); - return 0; -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size == strlen(argv0) && - !memmem(Data, Size, argv0, Size)) { - fprintf(stderr, "BINGO %s\n", argv0); - exit(1); - } - return 0; -} Index: lib/fuzzer/test/LargeTest.cpp =================================================================== --- lib/fuzzer/test/LargeTest.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// A fuzz target with lots of edges. -#include -#include - -static inline void break_optimization(const void *arg) { - __asm__ __volatile__("" : : "r" (arg) : "memory"); -} - -#define A \ - do { \ - i++; \ - c++; \ - if (Data[(i + __LINE__) % Size] == (c % 256)) \ - break_optimization(Data); \ - else \ - break_optimization(0); \ - } while (0) - -// for (int i = 0, n = Data[(__LINE__ - 1) % Size] % 16; i < n; i++) - -#define B do{A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; }while(0) -#define C do{B; B; B; B; B; B; B; B; B; B; B; B; B; B; B; B; B; B; }while(0) -#define D do{C; C; C; C; C; C; C; C; C; C; C; C; C; C; C; C; C; C; }while(0) -#define E do{D; D; D; D; D; D; D; D; D; D; D; D; D; D; D; D; D; D; }while(0) - -volatile int sink; -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (!Size) return 0; - int c = 0; - int i = 0; - D; - return 0; -} - Index: lib/fuzzer/test/LeakTest.cpp =================================================================== --- lib/fuzzer/test/LeakTest.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Test with a leak. -#include -#include - -static volatile void *Sink; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size > 0 && *Data == 'H') { - Sink = new int; - Sink = nullptr; - } - return 0; -} - Index: lib/fuzzer/test/LeakTimeoutTest.cpp =================================================================== --- lib/fuzzer/test/LeakTimeoutTest.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Test with a leak. -#include -#include - -static volatile int *Sink; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (!Size) return 0; - Sink = new int; - Sink = new int; - while (Sink) *Sink = 0; // Infinite loop. - return 0; -} - Index: lib/fuzzer/test/LoadTest.cpp =================================================================== --- lib/fuzzer/test/LoadTest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer: find interesting value of array index. -#include -#include -#include -#include -#include - -static volatile int Sink; -const int kArraySize = 1234567; -int array[kArraySize]; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < 8) return 0; - uint64_t a = 0; - memcpy(&a, Data, 8); - Sink = array[a % (kArraySize + 1)]; - return 0; -} - Index: lib/fuzzer/test/Memcmp64BytesTest.cpp =================================================================== --- lib/fuzzer/test/Memcmp64BytesTest.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find a particular string. -#include -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - const char kString64Bytes[] = - "123456789 123456789 123456789 123456789 123456789 123456789 1234"; - assert(sizeof(kString64Bytes) == 65); - if (Size >= 64 && memcmp(Data, kString64Bytes, 64) == 0) { - fprintf(stderr, "BINGO\n"); - exit(1); - } - return 0; -} Index: lib/fuzzer/test/MemcmpTest.cpp =================================================================== --- lib/fuzzer/test/MemcmpTest.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find a particular string. -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - // TODO: check other sizes. - if (Size >= 8 && memcmp(Data, "01234567", 8) == 0) { - if (Size >= 12 && memcmp(Data + 8, "ABCD", 4) == 0) { - if (Size >= 14 && memcmp(Data + 12, "XY", 2) == 0) { - if (Size >= 17 && memcmp(Data + 14, "KLM", 3) == 0) { - if (Size >= 27 && memcmp(Data + 17, "ABCDE-GHIJ", 10) == 0){ - fprintf(stderr, "BINGO %zd\n", Size); - for (size_t i = 0; i < Size; i++) { - uint8_t C = Data[i]; - if (C >= 32 && C < 127) - fprintf(stderr, "%c", C); - } - fprintf(stderr, "\n"); - exit(1); - } - } - } - } - } - return 0; -} Index: lib/fuzzer/test/NotinstrumentedTest.cpp =================================================================== --- lib/fuzzer/test/NotinstrumentedTest.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// This test should not be instrumented. -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - return 0; -} - Index: lib/fuzzer/test/NthRunCrashTest.cpp =================================================================== --- lib/fuzzer/test/NthRunCrashTest.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Crash on the N-th execution. -#include -#include -#include -#include - -static int Counter; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Counter++ == 1000) { - std::cout << "BINGO; Found the target, exiting\n" << std::flush; - exit(1); - } - return 0; -} - Index: lib/fuzzer/test/NullDerefOnEmptyTest.cpp =================================================================== --- lib/fuzzer/test/NullDerefOnEmptyTest.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find the empty string. -#include -#include -#include -#include - -static volatile int *Null = 0; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size == 0) { - std::cout << "Found the target, dereferencing NULL\n"; - *Null = 1; - } - return 0; -} - Index: lib/fuzzer/test/NullDerefTest.cpp =================================================================== --- lib/fuzzer/test/NullDerefTest.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find the string "Hi!". -#include -#include -#include -#include - -static volatile int Sink; -static volatile int *Null = 0; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size > 0 && Data[0] == 'H') { - Sink = 1; - if (Size > 1 && Data[1] == 'i') { - Sink = 2; - if (Size > 2 && Data[2] == '!') { - std::cout << "Found the target, dereferencing NULL\n"; - *Null = 1; - } - } - } - return 0; -} - Index: lib/fuzzer/test/OneHugeAllocTest.cpp =================================================================== --- lib/fuzzer/test/OneHugeAllocTest.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Tests OOM handling when there is a single large allocation. -#include -#include -#include -#include -#include -#include - -static volatile char *SinkPtr; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size > 0 && Data[0] == 'H') { - if (Size > 1 && Data[1] == 'i') { - if (Size > 2 && Data[2] == '!') { - size_t kSize = (size_t)1 << 31; - char *p = new char[kSize]; - memset(p, 0, kSize); - SinkPtr = p; - delete [] p; - } - } - } - return 0; -} - Index: lib/fuzzer/test/OutOfMemorySingleLargeMallocTest.cpp =================================================================== --- lib/fuzzer/test/OutOfMemorySingleLargeMallocTest.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Tests OOM handling. -#include -#include -#include -#include -#include -#include - -static volatile char *SinkPtr; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size > 0 && Data[0] == 'H') { - if (Size > 1 && Data[1] == 'i') { - if (Size > 2 && Data[2] == '!') { - size_t kSize = 0x20000000U; - char *p = new char[kSize]; - SinkPtr = p; - delete [] p; - } - } - } - return 0; -} - Index: lib/fuzzer/test/OutOfMemoryTest.cpp =================================================================== --- lib/fuzzer/test/OutOfMemoryTest.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Tests OOM handling. -#include -#include -#include -#include -#include -#include -#include - -static volatile char *SinkPtr; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size > 0 && Data[0] == 'H') { - if (Size > 1 && Data[1] == 'i') { - if (Size > 2 && Data[2] == '!') { - while (true) { - size_t kSize = 1 << 28; - char *p = new char[kSize]; - memset(p, 0, kSize); - SinkPtr = p; - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - } - } - } - return 0; -} - Index: lib/fuzzer/test/OverwriteInputTest.cpp =================================================================== --- lib/fuzzer/test/OverwriteInputTest.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. Make sure we abort if Data is overwritten. -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size) - *const_cast(Data) = 1; - return 0; -} - Index: lib/fuzzer/test/RepeatedBytesTest.cpp =================================================================== --- lib/fuzzer/test/RepeatedBytesTest.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find repeated bytes. -#include -#include -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - assert(Data); - // Looking for AAAAAAAAAAAAAAAAAAAAAA or some such. - size_t CurA = 0, MaxA = 0; - for (size_t i = 0; i < Size; i++) { - // Make sure there are no conditionals in the loop so that - // coverage can't help the fuzzer. - int EQ = Data[i] == 'A'; - CurA = EQ * (CurA + 1); - int GT = CurA > MaxA; - MaxA = GT * CurA + (!GT) * MaxA; - } - if (MaxA >= 20) { - std::cout << "BINGO; Found the target (Max: " << MaxA << "), exiting\n" - << std::flush; - exit(0); - } - return 0; -} - Index: lib/fuzzer/test/RepeatedMemcmp.cpp =================================================================== --- lib/fuzzer/test/RepeatedMemcmp.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - int Matches1 = 0; - for (size_t i = 0; i + 2 < Size; i += 3) - if (!memcmp(Data + i, "foo", 3)) - Matches1++; - int Matches2 = 0; - for (size_t i = 0; i + 2 < Size; i += 3) - if (!memcmp(Data + i, "bar", 3)) - Matches2++; - - if (Matches1 > 10 && Matches2 > 10) { - fprintf(stderr, "BINGO!\n"); - exit(1); - } - return 0; -} Index: lib/fuzzer/test/ShrinkControlFlowSimpleTest.cpp =================================================================== --- lib/fuzzer/test/ShrinkControlFlowSimpleTest.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Test that we can find the minimal item in the corpus (3 bytes: "FUZ"). -#include -#include -#include -#include -#include - -static volatile int Sink; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < 2) return 0; - if (Data[0] == 'F' && Data[Size / 2] == 'U' && Data[Size - 1] == 'Z') - Sink++; - return 0; -} - Index: lib/fuzzer/test/ShrinkControlFlowTest.cpp =================================================================== --- lib/fuzzer/test/ShrinkControlFlowTest.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Test that we can find the minimal item in the corpus (3 bytes: "FUZ"). -#include -#include -#include -#include -#include - -static volatile int Sink; - -void Foo() { - Sink++; -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - int8_t Ids[256]; - memset(Ids, -1, sizeof(Ids)); - for (size_t i = 0; i < Size; i++) - if (Ids[Data[i]] == -1) - Ids[Data[i]] = i; - int F = Ids[(unsigned char)'F']; - int U = Ids[(unsigned char)'U']; - int Z = Ids[(unsigned char)'Z']; - if (F >= 0 && U > F && Z > U) { - Foo(); - } - return 0; -} - Index: lib/fuzzer/test/ShrinkValueProfileTest.cpp =================================================================== --- lib/fuzzer/test/ShrinkValueProfileTest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Test that we can find the minimal item in the corpus (3 bytes: "FUZ"). -#include -#include -#include -#include -#include - -static volatile uint32_t Sink; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < sizeof(uint32_t)) return 0; - uint32_t X, Y; - size_t Offset = Size < 8 ? 0 : Size / 2; - memcpy(&X, Data + Offset, sizeof(uint32_t)); - memcpy(&Y, "FUZZ", sizeof(uint32_t)); - Sink = X == Y; - return 0; -} - Index: lib/fuzzer/test/SignedIntOverflowTest.cpp =================================================================== --- lib/fuzzer/test/SignedIntOverflowTest.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Test for signed-integer-overflow. -#include -#include -#include -#include -#include -#include - -static volatile int Sink; -static int Large = INT_MAX; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - assert(Data); - if (Size > 0 && Data[0] == 'H') { - Sink = 1; - if (Size > 1 && Data[1] == 'i') { - Sink = 2; - if (Size > 2 && Data[2] == '!') { - Large++; // int overflow. - } - } - } - return 0; -} - Index: lib/fuzzer/test/SimpleCmpTest.cpp =================================================================== --- lib/fuzzer/test/SimpleCmpTest.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find several narrow ranges. -#include -#include -#include -#include - -extern int AllLines[]; - -bool PrintOnce(int Line) { - if (!AllLines[Line]) - fprintf(stderr, "Seen line %d\n", Line); - AllLines[Line] = 1; - return true; -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size != 22) return 0; - uint64_t x = 0; - int64_t y = 0; - int32_t z = 0; - uint16_t a = 0; - memcpy(&x, Data, 8); // 8 - memcpy(&y, Data + 8, 8); // 16 - memcpy(&z, Data + 16, sizeof(z)); // 20 - memcpy(&a, Data + 20, sizeof(a)); // 22 - const bool k32bit = sizeof(void*) == 4; - - if ((k32bit || x > 1234567890) && PrintOnce(__LINE__) && - (k32bit || x < 1234567895) && PrintOnce(__LINE__) && - a == 0x4242 && PrintOnce(__LINE__) && - (k32bit || y >= 987654321) && PrintOnce(__LINE__) && - (k32bit || y <= 987654325) && PrintOnce(__LINE__) && - z < -10000 && PrintOnce(__LINE__) && - z >= -10005 && PrintOnce(__LINE__) && - z != -10003 && PrintOnce(__LINE__) && - true) { - fprintf(stderr, "BINGO; Found the target: size %zd (%zd, %zd, %d, %d), exiting.\n", - Size, x, y, z, a); - exit(1); - } - return 0; -} - -int AllLines[__LINE__ + 1]; // Must be the last line. Index: lib/fuzzer/test/SimpleDictionaryTest.cpp =================================================================== --- lib/fuzzer/test/SimpleDictionaryTest.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. -// The fuzzer must find a string based on dictionary words: -// "Elvis" -// "Presley" -#include -#include -#include -#include -#include -#include - -static volatile int Zero = 0; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - const char *Expected = "ElvisPresley"; - if (Size < strlen(Expected)) return 0; - size_t Match = 0; - for (size_t i = 0; Expected[i]; i++) - if (Expected[i] + Zero == Data[i]) - Match++; - if (Match == strlen(Expected)) { - std::cout << "BINGO; Found the target, exiting\n" << std::flush; - exit(1); - } - return 0; -} - Index: lib/fuzzer/test/SimpleHashTest.cpp =================================================================== --- lib/fuzzer/test/SimpleHashTest.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// This test computes a checksum of the data (all but the last 4 bytes), -// and then compares the last 4 bytes with the computed value. -// A fuzzer with cmp traces is expected to defeat this check. -#include -#include -#include -#include - -// A modified jenkins_one_at_a_time_hash initialized by non-zero, -// so that simple_hash(0) != 0. See also -// https://en.wikipedia.org/wiki/Jenkins_hash_function -static uint32_t simple_hash(const uint8_t *Data, size_t Size) { - uint32_t Hash = 0x12039854; - for (uint32_t i = 0; i < Size; i++) { - Hash += Data[i]; - Hash += (Hash << 10); - Hash ^= (Hash >> 6); - } - Hash += (Hash << 3); - Hash ^= (Hash >> 11); - Hash += (Hash << 15); - return Hash; -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < 14) - return 0; - - uint32_t Hash = simple_hash(&Data[0], Size - 4); - uint32_t Want = reinterpret_cast(&Data[Size - 4])[0]; - if (Hash != Want) - return 0; - fprintf(stderr, "BINGO; simple_hash defeated: %x == %x\n", (unsigned int)Hash, - (unsigned int)Want); - exit(1); - return 0; -} Index: lib/fuzzer/test/SimpleTest.cpp =================================================================== --- lib/fuzzer/test/SimpleTest.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find the string "Hi!". -#include -#include -#include -#include -#include -#include - -static volatile int Sink; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - assert(Data); - if (Size > 0 && Data[0] == 'H') { - Sink = 1; - if (Size > 1 && Data[1] == 'i') { - Sink = 2; - if (Size > 2 && Data[2] == '!') { - std::cout << "BINGO; Found the target, exiting\n" << std::flush; - exit(0); - } - } - } - return 0; -} - Index: lib/fuzzer/test/SimpleThreadedTest.cpp =================================================================== --- lib/fuzzer/test/SimpleThreadedTest.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Threaded test for a fuzzer. The fuzzer should find "H" -#include -#include -#include -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - auto C = [&] { - if (Size >= 2 && Data[0] == 'H') { - std::cout << "BINGO; Found the target, exiting\n" << std::flush; - abort(); - } - }; - 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; -} - Index: lib/fuzzer/test/SingleByteInputTest.cpp =================================================================== --- lib/fuzzer/test/SingleByteInputTest.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer, need just one byte to crash. -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size > 0 && Data[Size/2] == 42) { - fprintf(stderr, "BINGO\n"); - abort(); - } - return 0; -} - Index: lib/fuzzer/test/SingleMemcmpTest.cpp =================================================================== --- lib/fuzzer/test/SingleMemcmpTest.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find a particular string. -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - const char *S = (const char*)Data; - if (Size >= 6 && !memcmp(S, "qwerty", 6)) { - fprintf(stderr, "BINGO\n"); - exit(1); - } - return 0; -} Index: lib/fuzzer/test/SingleStrcmpTest.cpp =================================================================== --- lib/fuzzer/test/SingleStrcmpTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find a particular string. -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size >= 7) { - char Copy[7]; - memcpy(Copy, Data, 6); - Copy[6] = 0; - if (!strcmp(Copy, "qwerty")) { - fprintf(stderr, "BINGO\n"); - exit(1); - } - } - return 0; -} Index: lib/fuzzer/test/SingleStrncmpTest.cpp =================================================================== --- lib/fuzzer/test/SingleStrncmpTest.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find a particular string. -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - const char *S = (const char*)Data; - volatile auto Strncmp = &(strncmp); // Make sure strncmp is not inlined. - if (Size >= 6 && !Strncmp(S, "qwerty", 6)) { - fprintf(stderr, "BINGO\n"); - exit(1); - } - return 0; -} Index: lib/fuzzer/test/SpamyTest.cpp =================================================================== --- lib/fuzzer/test/SpamyTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// The test spams to stderr and stdout. -#include -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - assert(Data); - printf("PRINTF_STDOUT\n"); - fflush(stdout); - fprintf(stderr, "PRINTF_STDERR\n"); - std::cout << "STREAM_COUT\n"; - std::cout.flush(); - std::cerr << "STREAM_CERR\n"; - return 0; -} - Index: lib/fuzzer/test/StrcmpTest.cpp =================================================================== --- lib/fuzzer/test/StrcmpTest.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Break through a series of strcmp. -#include -#include -#include -#include -#include - -bool Eq(const uint8_t *Data, size_t Size, const char *Str) { - char Buff[1024]; - size_t Len = strlen(Str); - if (Size < Len) return false; - if (Len >= sizeof(Buff)) return false; - memcpy(Buff, (const char*)Data, Len); - Buff[Len] = 0; - int res = strcmp(Buff, Str); - return res == 0; -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Eq(Data, Size, "ABC") && - Size >= 3 && Eq(Data + 3, Size - 3, "QWER") && - Size >= 7 && Eq(Data + 7, Size - 7, "ZXCVN") && - Size >= 14 && Data[13] == 42 - ) { - fprintf(stderr, "BINGO\n"); - exit(1); - } - return 0; -} Index: lib/fuzzer/test/StrncmpOOBTest.cpp =================================================================== --- lib/fuzzer/test/StrncmpOOBTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Test that libFuzzer itself does not read out of bounds. -#include -#include -#include -#include -#include -#include - -static volatile int Sink; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < 5) return 0; - const char *Ch = reinterpret_cast(Data); - if (Ch[Size - 3] == 'a') - Sink = strncmp(Ch + Size - 3, "abcdefg", 6); - return 0; -} - Index: lib/fuzzer/test/StrncmpTest.cpp =================================================================== --- lib/fuzzer/test/StrncmpTest.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find a particular string. -#include -#include -#include -#include - -static volatile int sink; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - // TODO: check other sizes. - const char *S = (const char*)Data; - if (Size >= 8 && strncmp(S, "123", 8)) - sink = 1; - if (Size >= 8 && strncmp(S, "01234567", 8) == 0) { - if (Size >= 12 && strncmp(S + 8, "ABCD", 4) == 0) { - if (Size >= 14 && strncmp(S + 12, "XY", 2) == 0) { - if (Size >= 17 && strncmp(S + 14, "KLM", 3) == 0) { - fprintf(stderr, "BINGO\n"); - exit(1); - } - } - } - } - return 0; -} Index: lib/fuzzer/test/StrstrTest.cpp =================================================================== --- lib/fuzzer/test/StrstrTest.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Test strstr and strcasestr hooks. -#include -#include -#include -#include -#include - -// Windows does not have strcasestr and memmem, so we are not testing them. -#ifdef _WIN32 -#define strcasestr strstr -#define memmem(a, b, c, d) true -#endif - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < 4) return 0; - std::string s(reinterpret_cast(Data), Size); - if (strstr(s.c_str(), "FUZZ") && - strcasestr(s.c_str(), "aBcD") && - memmem(s.data(), s.size(), "kuku", 4) - ) { - fprintf(stderr, "BINGO\n"); - exit(1); - } - return 0; -} Index: lib/fuzzer/test/SwapCmpTest.cpp =================================================================== --- lib/fuzzer/test/SwapCmpTest.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// The fuzzer must find several constants with swapped bytes. -#include -#include -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < 14) return 0; - uint64_t x = 0; - uint32_t y = 0; - uint16_t z = 0; - memcpy(&x, Data, sizeof(x)); - memcpy(&y, Data + Size / 2, sizeof(y)); - memcpy(&z, Data + Size - sizeof(z), sizeof(z)); - - x = __builtin_bswap64(x); - y = __builtin_bswap32(y); - z = __builtin_bswap16(z); - const bool k32bit = sizeof(void*) == 4; - - if ((k32bit || x == 0x46555A5A5A5A5546ULL) && - z == 0x4F4B && - y == 0x66757A7A && - true - ) { - if (Data[Size - 3] == 'z') { - fprintf(stderr, "BINGO; Found the target\n"); - exit(1); - } - } - return 0; -} Index: lib/fuzzer/test/Switch2Test.cpp =================================================================== --- lib/fuzzer/test/Switch2Test.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find the interesting switch value. -#include -#include -#include -#include -#include - -int Switch(int a) { - switch(a) { - case 100001: return 1; - case 100002: return 2; - case 100003: return 4; - } - return 0; -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - const int N = 3; - if (Size < N * sizeof(int)) return 0; - int Res = 0; - for (int i = 0; i < N; i++) { - int X; - memcpy(&X, Data + i * sizeof(int), sizeof(int)); - Res += Switch(X); - } - if (Res == 5 || Res == 3 || Res == 6 || Res == 7) { - fprintf(stderr, "BINGO; Found the target, exiting; Res=%d\n", Res); - exit(1); - } - return 0; -} - Index: lib/fuzzer/test/SwitchTest.cpp =================================================================== --- lib/fuzzer/test/SwitchTest.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find the interesting switch value. -#include -#include -#include -#include -#include - -static volatile int Sink; - -template -bool Switch(const uint8_t *Data, size_t Size) { - T X; - if (Size < sizeof(X)) return false; - memcpy(&X, Data, sizeof(X)); - switch (X) { - case 1: Sink = __LINE__; break; - case 101: Sink = __LINE__; break; - case 1001: Sink = __LINE__; break; - case 10001: Sink = __LINE__; break; - case 100001: Sink = __LINE__; break; - case 1000001: Sink = __LINE__; break; - case 10000001: Sink = __LINE__; break; - case 100000001: return true; - } - return false; -} - -bool ShortSwitch(const uint8_t *Data, size_t Size) { - short X; - if (Size < sizeof(short)) return false; - memcpy(&X, Data, sizeof(short)); - switch(X) { - case 42: Sink = __LINE__; break; - case 402: Sink = __LINE__; break; - case 4002: Sink = __LINE__; break; - case 5002: Sink = __LINE__; break; - case 7002: Sink = __LINE__; break; - case 9002: Sink = __LINE__; break; - case 14002: Sink = __LINE__; break; - case 21402: return true; - } - return false; -} - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size >= 4 && Switch(Data, Size) && - Size >= 12 && Switch(Data + 4, Size - 4) && - Size >= 14 && ShortSwitch(Data + 12, 2) - ) { - fprintf(stderr, "BINGO; Found the target, exiting\n"); - exit(1); - } - return 0; -} - Index: lib/fuzzer/test/TableLookupTest.cpp =================================================================== --- lib/fuzzer/test/TableLookupTest.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Make sure the fuzzer eventually finds all possible values of a variable -// within a range. -#include -#include -#include -#include -#include -#include - -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 -// * in the section named __libfuzzer_extra_counters. -// The target code may declare more than one such array. -// -// Use either `Counters[Idx] = 1` or `Counters[Idx]++;` -// depending on whether multiple occurrences of the event 'Idx' -// is important to distinguish from one occurrence. -#ifdef __linux__ -__attribute__((section("__libfuzzer_extra_counters"))) -#endif -static uint8_t Counters[N]; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - static std::set SeenIdx; - if (Size != 4) return 0; - uint32_t Idx; - memcpy(&Idx, Data, 4); - Idx %= N; - assert(Counters[Idx] == 0); // libFuzzer should reset these between the runs. - // Or Counters[Idx]=1 if we don't care how many times this happened. - Counters[Idx]++; - SeenIdx.insert(Idx); - if (SeenIdx.size() == N) { - fprintf(stderr, "BINGO: found all values\n"); - abort(); - } - return 0; -} Index: lib/fuzzer/test/ThreadedLeakTest.cpp =================================================================== --- lib/fuzzer/test/ThreadedLeakTest.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// The fuzzer should find a leak in a non-main thread. -#include -#include -#include - -static volatile int *Sink; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size == 0) return 0; - if (Data[0] != 'F') return 0; - std::thread T([&] { Sink = new int; }); - T.join(); - return 0; -} - Index: lib/fuzzer/test/ThreadedTest.cpp =================================================================== --- lib/fuzzer/test/ThreadedTest.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Threaded test for a fuzzer. The fuzzer should not crash. -#include -#include -#include -#include -#include - -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; -} - Index: lib/fuzzer/test/TimeoutEmptyTest.cpp =================================================================== --- lib/fuzzer/test/TimeoutEmptyTest.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find the empty string. -#include -#include - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - static volatile int Zero = 0; - if (!Size) - while(!Zero) - ; - return 0; -} Index: lib/fuzzer/test/TimeoutTest.cpp =================================================================== --- lib/fuzzer/test/TimeoutTest.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. The fuzzer must find the string "Hi!". -#include -#include -#include -#include - -static volatile int Sink; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size > 0 && Data[0] == 'H') { - Sink = 1; - if (Size > 1 && Data[1] == 'i') { - Sink = 2; - if (Size > 2 && Data[2] == '!') { - Sink = 2; - while (Sink) - ; - } - } - } - return 0; -} - Index: lib/fuzzer/test/TraceMallocTest.cpp =================================================================== --- lib/fuzzer/test/TraceMallocTest.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Tests -trace_malloc -#include -#include -#include -#include -#include - -int *Ptr; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (!Size) return 0; - if (*Data == 1) { - delete Ptr; - Ptr = nullptr; - } else if (*Data == 2) { - delete Ptr; - Ptr = new int; - } else if (*Data == 3) { - if (!Ptr) - Ptr = new int; - } - return 0; -} - Index: lib/fuzzer/test/TwoDifferentBugsTest.cpp =================================================================== --- lib/fuzzer/test/TwoDifferentBugsTest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Simple test for a fuzzer. This test may trigger two different bugs. -#include -#include -#include -#include - -static volatile int *Null = 0; - -void Foo() { Null[1] = 0; } -void Bar() { Null[2] = 0; } - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < 10 && Data[0] == 'H') - Foo(); - if (Size >= 10 && Data[0] == 'H') - Bar(); - return 0; -} - Index: lib/fuzzer/test/afl-driver-extra-stats.test =================================================================== --- lib/fuzzer/test/afl-driver-extra-stats.test +++ /dev/null @@ -1,30 +0,0 @@ -RUN: %no_fuzzer_cpp_compiler -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard %S/AFLDriverTest.cpp %S/../afl/afl_driver.cpp -o %t-AFLDriverTest - -; Test that not specifying an extra stats file isn't broken. -RUN: unset AFL_DRIVER_EXTRA_STATS_FILENAME -RUN: %t-AFLDriverTest - -; Test that specifying an invalid extra stats file causes a crash. -RUN: ASAN_OPTIONS= AFL_DRIVER_EXTRA_STATS_FILENAME=%T not --crash %t-AFLDriverTest - -; Test that specifying a corrupted stats file causes a crash. -echo "peak_rss_mb :0" > %t -ASAN_OPTIONS= AFL_DRIVER_EXTRA_STATS_FILENAME=%t not --crash %t-AFLDriverTest - -; Test that specifying a valid nonexistent stats file works. -RUN: rm -f %t -RUN: AFL_DRIVER_EXTRA_STATS_FILENAME=%t %t-AFLDriverTest -RUN: [[ $(grep "peak_rss_mb\|slowest_unit_time_sec" %t | wc -l) -eq 2 ]] - -; Test that specifying a valid preexisting stats file works. -RUN: printf "peak_rss_mb : 0\nslowest_unit_time_sec: 0\n" > %t -RUN: AFL_DRIVER_EXTRA_STATS_FILENAME=%t %t-AFLDriverTest -; Check that both lines were printed. -RUN: [[ $(grep "peak_rss_mb\|slowest_unit_time_sec" %t | wc -l) -eq 2 ]] - -; Test that peak_rss_mb and slowest_unit_time_in_secs are only updated when necessary. -; Check that both lines have 9999 since there's no way we have exceeded that -; amount of time or virtual memory. -RUN: printf "peak_rss_mb : 9999\nslowest_unit_time_sec: 9999\n" > %t -RUN: AFL_DRIVER_EXTRA_STATS_FILENAME=%t %t-AFLDriverTest -RUN: [[ $(grep "9999" %t | wc -l) -eq 2 ]] Index: lib/fuzzer/test/afl-driver-stderr.test =================================================================== --- lib/fuzzer/test/afl-driver-stderr.test +++ /dev/null @@ -1,12 +0,0 @@ -RUN: %no_fuzzer_cpp_compiler -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard %S/AFLDriverTest.cpp %S/../afl/afl_driver.cpp -o %t-AFLDriverTest - -; Test that not specifying a stderr file isn't broken. -RUN: unset AFL_DRIVER_STDERR_DUPLICATE_FILENAME -RUN: %t-AFLDriverTest - -; Test that specifying an invalid file causes a crash. -RUN: ASAN_OPTIONS= AFL_DRIVER_STDERR_DUPLICATE_FILENAME="%T" not --crash %t-AFLDriverTest - -; Test that a file is created when specified as the duplicate stderr. -RUN: AFL_DRIVER_STDERR_DUPLICATE_FILENAME=%t %t-AFLDriverTest -RUN: stat %t Index: lib/fuzzer/test/afl-driver.test =================================================================== --- lib/fuzzer/test/afl-driver.test +++ /dev/null @@ -1,29 +0,0 @@ -REQUIRES: linux - -RUN: %no_fuzzer_cpp_compiler -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard %S/AFLDriverTest.cpp %S/../afl/afl_driver.cpp -o %t-AFLDriverTest - -RUN: echo -n "abc" > %t.file3 -RUN: echo -n "abcd" > %t.file4 - -RUN: %t-AFLDriverTest < %t.file3 2>&1 | FileCheck %s --check-prefix=CHECK1 -CHECK1: __afl_persistent_loop calle, Count = 1000 -CHECK1: LLVMFuzzerTestOneInput called; Size = 3 - - -RUN: %t-AFLDriverTest < %t.file3 -42 2>&1 | FileCheck %s --check-prefix=CHECK2 -CHECK2: __afl_persistent_loop calle, Count = 42 -CHECK2: LLVMFuzzerTestOneInput called; Size = 3 - - -RUN: %t-AFLDriverTest < %t.file3 666 2>&1 | FileCheck %s --check-prefix=CHECK3 -CHECK3: WARNING: using the deprecated call style -CHECK3: __afl_persistent_loop calle, Count = 666 -CHECK3: LLVMFuzzerTestOneInput called; Size = 3 - - -RUN: %t-AFLDriverTest %t.file3 2>&1 | FileCheck %s --check-prefix=CHECK4 -CHECK4: LLVMFuzzerTestOneInput called; Size = 3 - -RUN: %t-AFLDriverTest %t.file3 %t.file4 2>&1 | FileCheck %s --check-prefix=CHECK5 -CHECK5: LLVMFuzzerTestOneInput called; Size = 3 -CHECK5: LLVMFuzzerTestOneInput called; Size = 4 Index: lib/fuzzer/test/bad-strcmp.test =================================================================== --- lib/fuzzer/test/bad-strcmp.test +++ /dev/null @@ -1,2 +0,0 @@ -RUN: %cpp_compiler %S/BadStrcmpTest.cpp -o %t-BadStrcmpTest -RUN: %t-BadStrcmpTest -runs=100000 Index: lib/fuzzer/test/caller-callee.test =================================================================== --- lib/fuzzer/test/caller-callee.test +++ /dev/null @@ -1,3 +0,0 @@ -RUN: %cpp_compiler %S/CallerCalleeTest.cpp -o %t-CallerCalleeTest -CHECK: BINGO -RUN: not %t-CallerCalleeTest -use_value_profile=1 -cross_over=0 -seed=1 -runs=10000000 2>&1 | FileCheck %s Index: lib/fuzzer/test/cleanse.test =================================================================== --- lib/fuzzer/test/cleanse.test +++ /dev/null @@ -1,4 +0,0 @@ -RUN: %cpp_compiler %S/CleanseTest.cpp -o %t-CleanseTest -RUN: echo -n 0123456789ABCDEFGHIZ > %t-in -RUN: %t-CleanseTest -cleanse_crash=1 %t-in -exact_artifact_path=%t-out -RUN: echo -n ' 1 5 A Z' | diff - %t-out Index: lib/fuzzer/test/coverage.test =================================================================== --- lib/fuzzer/test/coverage.test +++ /dev/null @@ -1,21 +0,0 @@ -RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/NullDerefTest.cpp -o %t-NullDerefTest -RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSO1.cpp -fPIC -shared -o %t-DSO1.so -RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSO2.cpp -fPIC -shared -o %t-DSO2.so -RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSOTestMain.cpp %S/DSOTestExtra.cpp -L. %t-DSO1.so %t-DSO2.so -o %t-DSOTest - -CHECK: COVERAGE: -CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:13 -CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:14 -CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:16 -RUN: not %t-NullDerefTest -print_coverage=1 2>&1 | FileCheck %s - -RUN: %t-DSOTest -print_coverage=1 -runs=0 2>&1 | FileCheck %s --check-prefix=DSO -DSO: COVERAGE: -DSO-DAG: COVERED:{{.*}}DSO1{{.*}}DSO1.cpp -DSO-DAG: COVERED:{{.*}}DSO2{{.*}}DSO2.cpp -DSO-DAG: COVERED:{{.*}}LLVMFuzzerTestOneInput{{.*}}DSOTestMain -DSO-DAG: UNCOVERED_LINE:{{.*}}DSO1{{.*}}DSO1.cpp -DSO-DAG: UNCOVERED_LINE:{{.*}}DSO2{{.*}}DSO2.cpp -DSO-DAG: UNCOVERED_FUNC: in Uncovered1 -DSO-DAG: UNCOVERED_FUNC: in Uncovered2 -DSO-DAG: UNCOVERED_LINE: in LLVMFuzzerTestOneInput Index: lib/fuzzer/test/cxxstring.test =================================================================== --- lib/fuzzer/test/cxxstring.test +++ /dev/null @@ -1,6 +0,0 @@ -UNSUPPORTED: windows - -RUN: %cpp_compiler %S/CxxStringEqTest.cpp -o %t-CxxStringEqTest - -RUN: not %t-CxxStringEqTest -seed=1 -runs=1000000 2>&1 | FileCheck %s -CHECK: BINGO Index: lib/fuzzer/test/dict1.txt =================================================================== --- lib/fuzzer/test/dict1.txt +++ /dev/null @@ -1,4 +0,0 @@ -# Dictionary for SimpleDictionaryTest - -a="Elvis" -b="Presley" Index: lib/fuzzer/test/disable-leaks.test =================================================================== --- lib/fuzzer/test/disable-leaks.test +++ /dev/null @@ -1,5 +0,0 @@ -REQUIRES: lsan -RUN: %cpp_compiler %S/AccumulateAllocationsTest.cpp -o %t-AccumulateAllocationsTest -RUN: %t-AccumulateAllocationsTest -detect_leaks=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=ACCUMULATE_ALLOCS -ACCUMULATE_ALLOCS: INFO: libFuzzer disabled leak detection after every mutation - Index: lib/fuzzer/test/dump_coverage.test =================================================================== --- lib/fuzzer/test/dump_coverage.test +++ /dev/null @@ -1,20 +0,0 @@ -RUN: %cpp_compiler %S/DSO1.cpp -fPIC -shared -o %t-DSO1.so -RUN: %cpp_compiler %S/DSO2.cpp -fPIC -shared -o %t-DSO2.so -RUN: %cpp_compiler %S/DSOTestMain.cpp %S/DSOTestExtra.cpp -L. %t-DSO1.so %t-DSO2.so -o %t-DSOTest - -RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest - -RUN: rm -rf %t_workdir && mkdir -p %t_workdir -RUN: env ASAN_OPTIONS=coverage_dir='"%t_workdir"' not %t-NullDerefTest -dump_coverage=1 2>&1 | FileCheck %s -RUN: sancov -covered-functions %t-NullDerefTest* %t_workdir/*.sancov | FileCheck %s --check-prefix=SANCOV -RUN: env ASAN_OPTIONS=coverage_dir='"%t_workdir"' %t-DSOTest -dump_coverage=1 -runs=0 2>&1 | FileCheck %s --check-prefix=DSO -RUN: env ASAN_OPTIONS=coverage_dir='"%t_workdir"' not %t-NullDerefTest -dump_coverage=0 2>&1 | FileCheck %s --check-prefix=NOCOV - -CHECK: SanitizerCoverage: {{.*}}NullDerefTest.{{.*}}.sancov: {{.*}} PCs written -SANCOV: LLVMFuzzerTestOneInput - -DSO: SanitizerCoverage: {{.*}}DSOTest.{{.*}}.sancov: {{.*}} PCs written -DSO-DAG: SanitizerCoverage: {{.*}}DSO1.{{.*}}.sancov: {{.*}} PCs written -DSO-DAG: SanitizerCoverage: {{.*}}DSO2.{{.*}}.sancov: {{.*}} PCs written - -NOCOV-NOT: SanitizerCoverage: {{.*}} PCs written Index: lib/fuzzer/test/equivalence-signals.test =================================================================== --- lib/fuzzer/test/equivalence-signals.test +++ /dev/null @@ -1,9 +0,0 @@ -# Run EquivalenceATest against itself with a small timeout -# to stress the signal handling and ensure that shmem doesn't mind -# the signals. - -RUN: %cpp_compiler %S/EquivalenceATest.cpp -o %t-EquivalenceATest -RUN: %t-EquivalenceATest -timeout=1 -run_equivalence_server=EQUIV_SIG_TEST & export APID=$! -RUN: sleep 3 -RUN: %t-EquivalenceATest -timeout=1 -use_equivalence_server=EQUIV_SIG_TEST -runs=500000 2>&1 -RUN: kill -9 $APID Index: lib/fuzzer/test/equivalence.test =================================================================== --- lib/fuzzer/test/equivalence.test +++ /dev/null @@ -1,9 +0,0 @@ -RUN: %cpp_compiler %S/EquivalenceATest.cpp -o %t-EquivalenceATest -RUN: %cpp_compiler %S/EquivalenceBTest.cpp -o %t-EquivalenceBTest - -RUN: %t-EquivalenceATest -run_equivalence_server=EQUIV_TEST & export APID=$! -RUN: sleep 3 -RUN: not %t-EquivalenceBTest -use_equivalence_server=EQUIV_TEST -max_len=4096 2>&1 | FileCheck %s -CHECK: ERROR: libFuzzer: equivalence-mismatch. Sizes: {{.*}}; offset 2 -CHECK: SUMMARY: libFuzzer: equivalence-mismatch -RUN: kill -9 $APID Index: lib/fuzzer/test/exit-report.test =================================================================== --- lib/fuzzer/test/exit-report.test +++ /dev/null @@ -1,6 +0,0 @@ -RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest -RUN: not %t-SimpleTest 2>&1 | FileCheck %s - -CHECK: ERROR: libFuzzer: fuzz target exited -CHECK: SUMMARY: libFuzzer: fuzz target exited -CHECK: Test unit written to Index: lib/fuzzer/test/exit_on_src_pos.test =================================================================== --- lib/fuzzer/test/exit_on_src_pos.test +++ /dev/null @@ -1,8 +0,0 @@ -# Temporary use -mllvm -use-unknown-locations=Disable so that -# all instructions have debug info (file line numbers) attached. -RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest -mllvm -use-unknown-locations=Disable -RUN: %cpp_compiler %S/ShrinkControlFlowTest.cpp -o %t-ShrinkControlFlowTest - -RUN: %t-SimpleTest -exit_on_src_pos=SimpleTest.cpp:18 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS -RUN: %t-ShrinkControlFlowTest -exit_on_src_pos=Foo 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS -EXIT_ON_SRC_POS: INFO: found line matching '{{.*}}', exiting. Index: lib/fuzzer/test/extra-counters.test =================================================================== --- lib/fuzzer/test/extra-counters.test +++ /dev/null @@ -1,7 +0,0 @@ -REQUIRES: linux - -RUN: %cpp_compiler %S/TableLookupTest.cpp -o %t-TableLookupTest -RUN: not %t-TableLookupTest -print_final_stats=1 2>&1 | FileCheck %s -CHECK: BINGO -// Expecting >= 4096 new_units_added -CHECK: stat::new_units_added:{{.*[4][0-9][0-9][0-9]}} Index: lib/fuzzer/test/fuzzer-customcrossover.test =================================================================== --- lib/fuzzer/test/fuzzer-customcrossover.test +++ /dev/null @@ -1,12 +0,0 @@ -RUN: %cpp_compiler %S/CustomCrossOverTest.cpp -o %t-CustomCrossOverTest - -RUN: rm -rf %t/CustomCrossover -RUN: mkdir -p %t/CustomCrossover -RUN: echo "0123456789" > %t/CustomCrossover/digits -RUN: echo "abcdefghij" > %t/CustomCrossover/chars -RUN: not %t-CustomCrossOverTest -seed=1 -runs=100000 %t/CustomCrossover 2>&1 | FileCheck %s --check-prefix=LLVMFuzzerCustomCrossover -RUN: rm -rf %t/CustomCrossover - -LLVMFuzzerCustomCrossover: In LLVMFuzzerCustomCrossover -LLVMFuzzerCustomCrossover: BINGO - Index: lib/fuzzer/test/fuzzer-customcrossoverandmutate.test =================================================================== --- lib/fuzzer/test/fuzzer-customcrossoverandmutate.test +++ /dev/null @@ -1,2 +0,0 @@ -RUN: %cpp_compiler %S/CustomCrossOverAndMutateTest.cpp -o %t-CustomCrossOverAndMutateTest -RUN: %t-CustomCrossOverAndMutateTest -seed=1 -runs=100000 Index: lib/fuzzer/test/fuzzer-custommutator.test =================================================================== --- lib/fuzzer/test/fuzzer-custommutator.test +++ /dev/null @@ -1,5 +0,0 @@ -RUN: %cpp_compiler %S/CustomMutatorTest.cpp -o %t-CustomMutatorTest -RUN: not %t-CustomMutatorTest 2>&1 | FileCheck %s --check-prefix=LLVMFuzzerCustomMutator -LLVMFuzzerCustomMutator: In LLVMFuzzerCustomMutator -LLVMFuzzerCustomMutator: BINGO - Index: lib/fuzzer/test/fuzzer-dict.test =================================================================== --- lib/fuzzer/test/fuzzer-dict.test +++ /dev/null @@ -1,8 +0,0 @@ -RUN: %cpp_compiler %S/SimpleDictionaryTest.cpp -o %t-SimpleDictionaryTest - -CHECK: BINGO -Done1000000: Done 1000000 runs in - -RUN: not %t-SimpleDictionaryTest -dict=%S/dict1.txt -seed=1 -runs=1000003 2>&1 | FileCheck %s -RUN: %t-SimpleDictionaryTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 - Index: lib/fuzzer/test/fuzzer-dirs.test =================================================================== --- lib/fuzzer/test/fuzzer-dirs.test +++ /dev/null @@ -1,21 +0,0 @@ -RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest - -RUN: rm -rf %t/SUB1 -RUN: mkdir -p %t/SUB1/SUB2/SUB3 -RUN: echo a > %t/SUB1/a -RUN: echo b > %t/SUB1/SUB2/b -RUN: echo c > %t/SUB1/SUB2/SUB3/c -RUN: %t-SimpleTest %t/SUB1 -runs=0 2>&1 | FileCheck %s --check-prefix=SUBDIRS -SUBDIRS: READ units: 3 -RUN: echo -n zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz > %t/SUB1/f64 -RUN: cat %t/SUB1/f64 %t/SUB1/f64 %t/SUB1/f64 %t/SUB1/f64 > %t/SUB1/f256 -RUN: cat %t/SUB1/f256 %t/SUB1/f256 %t/SUB1/f256 %t/SUB1/f256 > %t/SUB1/f1024 -RUN: cat %t/SUB1/f1024 %t/SUB1/f1024 %t/SUB1/f1024 %t/SUB1/f1024 > %t/SUB1/f4096 -RUN: cat %t/SUB1/f4096 %t/SUB1/f4096 > %t/SUB1/f8192 -RUN: %t-SimpleTest %t/SUB1 -runs=0 2>&1 | FileCheck %s --check-prefix=LONG -LONG: INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 8192 bytes -RUN: rm -rf %t/SUB1 - -RUN: not %t-SimpleTest NONEXISTENT_DIR 2>&1 | FileCheck %s --check-prefix=NONEXISTENT_DIR -NONEXISTENT_DIR: No such directory: NONEXISTENT_DIR; exiting - Index: lib/fuzzer/test/fuzzer-fdmask.test =================================================================== --- lib/fuzzer/test/fuzzer-fdmask.test +++ /dev/null @@ -1,32 +0,0 @@ -RUN: %cpp_compiler %S/SpamyTest.cpp -o %t-SpamyTest - -RUN: %t-SpamyTest -runs=1 2>&1 | FileCheck %s --check-prefix=FD_MASK_0 -RUN: %t-SpamyTest -runs=1 -close_fd_mask=0 2>&1 | FileCheck %s --check-prefix=FD_MASK_0 -RUN: %t-SpamyTest -runs=1 -close_fd_mask=1 2>&1 | FileCheck %s --check-prefix=FD_MASK_1 -RUN: %t-SpamyTest -runs=1 -close_fd_mask=2 2>&1 | FileCheck %s --check-prefix=FD_MASK_2 -RUN: %t-SpamyTest -runs=1 -close_fd_mask=3 2>&1 | FileCheck %s --check-prefix=FD_MASK_3 - -FD_MASK_0: PRINTF_STDOUT -FD_MASK_0: PRINTF_STDERR -FD_MASK_0: STREAM_COUT -FD_MASK_0: STREAM_CERR -FD_MASK_0: INITED - -FD_MASK_1-NOT: PRINTF_STDOUT -FD_MASK_1: PRINTF_STDERR -FD_MASK_1-NOT: STREAM_COUT -FD_MASK_1: STREAM_CERR -FD_MASK_1: INITED - -FD_MASK_2: PRINTF_STDOUT -FD_MASK_2-NOT: PRINTF_STDERR -FD_MASK_2: STREAM_COUT -FD_MASK_2-NOTE: STREAM_CERR -FD_MASK_2: INITED - -FD_MASK_3-NOT: PRINTF_STDOUT -FD_MASK_3-NOT: PRINTF_STDERR -FD_MASK_3-NOT: STREAM_COUT -FD_MASK_3-NOT: STREAM_CERR -FD_MASK_3: INITED - Index: lib/fuzzer/test/fuzzer-finalstats.test =================================================================== --- lib/fuzzer/test/fuzzer-finalstats.test +++ /dev/null @@ -1,12 +0,0 @@ -RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest -RUN: %t-SimpleTest -seed=1 -runs=77 -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=FINAL_STATS -FINAL_STATS: stat::number_of_executed_units: 77 -FINAL_STATS: stat::average_exec_per_sec: 0 -FINAL_STATS: stat::new_units_added: -FINAL_STATS: stat::slowest_unit_time_sec: 0 -FINAL_STATS: stat::peak_rss_mb: - -RUN: %t-SimpleTest %S/dict1.txt -runs=33 -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=FINAL_STATS1 -FINAL_STATS1: stat::number_of_executed_units: 33 -FINAL_STATS1: stat::peak_rss_mb: - Index: lib/fuzzer/test/fuzzer-flags.test =================================================================== --- lib/fuzzer/test/fuzzer-flags.test +++ /dev/null @@ -1,19 +0,0 @@ -RUN: %cpp_compiler %S/FlagsTest.cpp -o %t-FlagsTest -RUN: not %t-FlagsTest -foo_bar=1 2>&1 | FileCheck %s --check-prefix=FOO_BAR -FOO_BAR: WARNING: unrecognized flag '-foo_bar=1'; use -help=1 to list all flags -FOO_BAR: BINGO - -RUN: not %t-FlagsTest -runs=10 --max_len=100 2>&1 | FileCheck %s --check-prefix=DASH_DASH -DASH_DASH: WARNING: did you mean '-max_len=100' (single dash)? -DASH_DASH: INFO: A corpus is not provided, starting from an empty corpus - -RUN: %t-FlagsTest -help=1 2>&1 | FileCheck %s --check-prefix=NO_INTERNAL -NO_INTERNAL-NOT: internal flag - -RUN: not %t-FlagsTest --foo-bar -runs=10 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU -PASSTHRU: BINGO --foo-bar --baz -help=1 test - -RUN: mkdir -p %t/T0 %t/T1 -RUN: touch %t/T1/empty -RUN: not %t-FlagsTest --foo-bar -merge=1 %t/T0 %t/T1 -ignore_remaining_args=1 --baz -help=1 test 2>&1 | FileCheck %s --check-prefix=PASSTHRU-MERGE -PASSTHRU-MERGE: BINGO --foo-bar --baz -help=1 test Index: lib/fuzzer/test/fuzzer-leak.test =================================================================== --- lib/fuzzer/test/fuzzer-leak.test +++ /dev/null @@ -1,37 +0,0 @@ -REQUIRES: lsan -RUN: %cpp_compiler %S/LeakTest.cpp -o %t-LeakTest -RUN: %cpp_compiler %S/ThreadedLeakTest.cpp -o %t-ThreadedLeakTest -RUN: %cpp_compiler %S/LeakTimeoutTest.cpp -o %t-LeakTimeoutTest - -RUN: not %t-LeakTest -runs=100000 -detect_leaks=1 2>&1 | FileCheck %s --check-prefix=LEAK_DURING -LEAK_DURING: ERROR: LeakSanitizer: detected memory leaks -LEAK_DURING: Direct leak of 4 byte(s) in 1 object(s) allocated from: -LEAK_DURING: INFO: to ignore leaks on libFuzzer side use -detect_leaks=0 -LEAK_DURING: Test unit written to ./leak- -LEAK_DURING-NOT: DONE -LEAK_DURING-NOT: Done - -RUN: not %t-LeakTest -runs=0 -detect_leaks=1 %S 2>&1 | FileCheck %s --check-prefix=LEAK_IN_CORPUS -LEAK_IN_CORPUS: ERROR: LeakSanitizer: detected memory leaks -LEAK_IN_CORPUS: INFO: a leak has been found in the initial corpus. - -RUN: not %t-LeakTest -runs=100000000 %S/hi.txt 2>&1 | FileCheck %s --check-prefix=MULTI_RUN_LEAK -MULTI_RUN_LEAK-NOT: pulse -MULTI_RUN_LEAK: LeakSanitizer: detected memory leaks - -RUN: not %t-LeakTest -runs=100000 -detect_leaks=0 2>&1 | FileCheck %s --check-prefix=LEAK_AFTER -RUN: not %t-LeakTest -runs=100000 2>&1 | FileCheck %s --check-prefix=LEAK_DURING -RUN: not %t-ThreadedLeakTest -runs=100000 -detect_leaks=0 2>&1 | FileCheck %s --check-prefix=LEAK_AFTER -RUN: not %t-ThreadedLeakTest -runs=100000 2>&1 | FileCheck %s --check-prefix=LEAK_DURING -LEAK_AFTER: Done 100000 runs in -LEAK_AFTER: ERROR: LeakSanitizer: detected memory leaks - -RUN: not %t-LeakTest -runs=100000 -max_len=1 2>&1 | FileCheck %s --check-prefix=MAX_LEN_1 -MAX_LEN_1: Test unit written to ./leak-7cf184f4c67ad58283ecb19349720b0cae756829 - -RUN: not %t-LeakTimeoutTest -timeout=1 2>&1 | FileCheck %s --check-prefix=LEAK_TIMEOUT -LEAK_TIMEOUT: ERROR: libFuzzer: timeout after -LEAK_TIMEOUT-NOT: LeakSanitizer - - -RUN: %t-LeakTest -error_exitcode=0 Index: lib/fuzzer/test/fuzzer-oom-with-profile.test =================================================================== --- lib/fuzzer/test/fuzzer-oom-with-profile.test +++ /dev/null @@ -1,7 +0,0 @@ -REQUIRES: linux -RUN: %cpp_compiler %S/OutOfMemoryTest.cpp -o %t-OutOfMemoryTest -RUN: not %t-OutOfMemoryTest -rss_limit_mb=300 2>&1 | FileCheck %s -CHECK: ERROR: libFuzzer: out-of-memory (used: {{.*}}; limit: 300Mb) -CHECK: Live Heap Allocations -CHECK: Test unit written to ./oom- -SUMMARY: libFuzzer: out-of-memory Index: lib/fuzzer/test/fuzzer-oom.test =================================================================== --- lib/fuzzer/test/fuzzer-oom.test +++ /dev/null @@ -1,20 +0,0 @@ -RUN: %cpp_compiler %S/OutOfMemoryTest.cpp -o %t-OutOfMemoryTest -RUN: %cpp_compiler %S/OutOfMemorySingleLargeMallocTest.cpp -o %t-OutOfMemorySingleLargeMallocTest -RUN: %cpp_compiler %S/AccumulateAllocationsTest.cpp -o %t-AccumulateAllocationsTest - -RUN: not %t-OutOfMemoryTest -rss_limit_mb=300 2>&1 | FileCheck %s - -CHECK: ERROR: libFuzzer: out-of-memory (used: {{.*}}; limit: 300Mb) -CHECK: Test unit written to ./oom- -SUMMARY: libFuzzer: out-of-memory - -RUN: not %t-OutOfMemorySingleLargeMallocTest -rss_limit_mb=300 2>&1 | FileCheck %s --check-prefix=SINGLE_LARGE_MALLOC - -We used to check for "out-of-memory (malloc(53{{.*}}))", but that would fail -sometimes, so now we accept any OOM message. - -SINGLE_LARGE_MALLOC: libFuzzer: out-of-memory -SINGLE_LARGE_MALLOC: in LLVMFuzzerTestOneInput - -# Check that -rss_limit_mb=0 means no limit. -RUN: %t-AccumulateAllocationsTest -runs=1000 -rss_limit_mb=0 Index: lib/fuzzer/test/fuzzer-printcovpcs.test =================================================================== --- lib/fuzzer/test/fuzzer-printcovpcs.test +++ /dev/null @@ -1,9 +0,0 @@ -RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest -RUN: not %t-SimpleTest -print_pcs=1 -seed=1 2>&1 | FileCheck %s --check-prefix=PCS -PCS-NOT: NEW_PC -PCS:INITED -PCS:NEW_PC: {{0x[a-f0-9]+}} -PCS:NEW_PC: {{0x[a-f0-9]+}} -PCS:NEW -PCS:BINGO - Index: lib/fuzzer/test/fuzzer-runs.test =================================================================== --- lib/fuzzer/test/fuzzer-runs.test +++ /dev/null @@ -1,9 +0,0 @@ -RUN: mkdir -p %t -RUN: %cpp_compiler %S/NthRunCrashTest.cpp -o %t-NthRunCrashTest -RUN: echo abcd > %t/NthRunCrashTest.in -RUN: %t-NthRunCrashTest %t/NthRunCrashTest.in -RUN: %t-NthRunCrashTest %t/NthRunCrashTest.in -runs=10 -RUN: not %t-NthRunCrashTest %t/NthRunCrashTest.in -runs=10000 2>&1 | FileCheck %s -RUN: rm %t/NthRunCrashTest.in -CHECK: BINGO - Index: lib/fuzzer/test/fuzzer-seed.test =================================================================== --- lib/fuzzer/test/fuzzer-seed.test +++ /dev/null @@ -1,4 +0,0 @@ -RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-SimpleCmpTest -RUN: %t-SimpleCmpTest -seed=-1 -runs=0 2>&1 | FileCheck %s --check-prefix=CHECK_SEED_MINUS_ONE -CHECK_SEED_MINUS_ONE: Seed: 4294967295 - Index: lib/fuzzer/test/fuzzer-segv.test =================================================================== --- lib/fuzzer/test/fuzzer-segv.test +++ /dev/null @@ -1,8 +0,0 @@ -RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest -RUN: env ASAN_OPTIONS=handle_segv=0 not %t-NullDerefTest 2>&1 | FileCheck %s --check-prefix=LIBFUZZER_OWN_SEGV_HANDLER -LIBFUZZER_OWN_SEGV_HANDLER: == ERROR: libFuzzer: deadly signal -LIBFUZZER_OWN_SEGV_HANDLER: SUMMARY: libFuzzer: deadly signal -LIBFUZZER_OWN_SEGV_HANDLER: Test unit written to ./crash- - -RUN: env ASAN_OPTIONS=handle_segv=1 not %t-NullDerefTest 2>&1 | FileCheck %s --check-prefix=LIBFUZZER_ASAN_SEGV_HANDLER -LIBFUZZER_ASAN_SEGV_HANDLER: ERROR: AddressSanitizer: {{SEGV|access-violation}} on unknown address Index: lib/fuzzer/test/fuzzer-singleinputs.test =================================================================== --- lib/fuzzer/test/fuzzer-singleinputs.test +++ /dev/null @@ -1,19 +0,0 @@ -RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest -RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest - -RUN: not %t-NullDerefTest %S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInput -SingleInput-NOT: Test unit written to ./crash- - -RUN: rm -rf %tmp/SINGLE_INPUTS -RUN: mkdir -p %tmp/SINGLE_INPUTS -RUN: echo aaa > %tmp/SINGLE_INPUTS/aaa -RUN: echo bbb > %tmp/SINGLE_INPUTS/bbb -RUN: %t-SimpleTest %tmp/SINGLE_INPUTS/aaa %tmp/SINGLE_INPUTS/bbb 2>&1 | FileCheck %s --check-prefix=SINGLE_INPUTS -RUN: %t-SimpleTest -max_len=2 %tmp/SINGLE_INPUTS/aaa %tmp/SINGLE_INPUTS/bbb 2>&1 | FileCheck %s --check-prefix=SINGLE_INPUTS -RUN: rm -rf %tmp/SINGLE_INPUTS -SINGLE_INPUTS: SimpleTest{{.*}}: Running 2 inputs 1 time(s) each. -SINGLE_INPUTS: aaa in -SINGLE_INPUTS: bbb in -SINGLE_INPUTS: NOTE: fuzzing was not performed, you have only -SINGLE_INPUTS: executed the target code on a fixed set of inputs. - Index: lib/fuzzer/test/fuzzer-threaded.test =================================================================== --- lib/fuzzer/test/fuzzer-threaded.test +++ /dev/null @@ -1,8 +0,0 @@ -CHECK: Done 1000 runs in -RUN: %cpp_compiler %S/ThreadedTest.cpp -o %t-ThreadedTest - -RUN: %t-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s -RUN: %t-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s -RUN: %t-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s -RUN: %t-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s - Index: lib/fuzzer/test/fuzzer-timeout.test =================================================================== --- lib/fuzzer/test/fuzzer-timeout.test +++ /dev/null @@ -1,21 +0,0 @@ -RUN: %cpp_compiler %S/TimeoutTest.cpp -o %t-TimeoutTest -RUN: %cpp_compiler %S/TimeoutEmptyTest.cpp -o %t-TimeoutEmptyTest -RUN: not %t-TimeoutTest -timeout=1 2>&1 | FileCheck %s --check-prefix=TimeoutTest -TimeoutTest: ALARM: working on the last Unit for -TimeoutTest: Test unit written to ./timeout- -TimeoutTest: == ERROR: libFuzzer: timeout after -TimeoutTest: #0 -TimeoutTest: #1 -TimeoutTest: #2 -TimeoutTest: SUMMARY: libFuzzer: timeout - -RUN: not %t-TimeoutTest -timeout=1 %S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInputTimeoutTest -SingleInputTimeoutTest: ALARM: working on the last Unit for {{[1-3]}} seconds -SingleInputTimeoutTest-NOT: Test unit written to ./timeout- - -RUN: %t-TimeoutTest -timeout=1 -timeout_exitcode=0 - -RUN: not %t-TimeoutEmptyTest -timeout=1 2>&1 | FileCheck %s --check-prefix=TimeoutEmptyTest -TimeoutEmptyTest: ALARM: working on the last Unit for -TimeoutEmptyTest: == ERROR: libFuzzer: timeout after -TimeoutEmptyTest: SUMMARY: libFuzzer: timeout Index: lib/fuzzer/test/fuzzer-ubsan.test =================================================================== --- lib/fuzzer/test/fuzzer-ubsan.test +++ /dev/null @@ -1,5 +0,0 @@ -RUN: %cpp_compiler -fsanitize=undefined -fno-sanitize-recover=all %S/SignedIntOverflowTest.cpp -o %t-SignedIntOverflowTest-Ubsan -RUN: not %t-SignedIntOverflowTest-Ubsan 2>&1 | FileCheck %s -CHECK: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' -CHECK: Test unit written to ./crash- - Index: lib/fuzzer/test/fuzzer.test =================================================================== --- lib/fuzzer/test/fuzzer.test +++ /dev/null @@ -1,70 +0,0 @@ -CHECK: BINGO -Done1000000: Done 1000000 runs in -RUN: %cpp_compiler %S/BogusInitializeTest.cpp -o %t-BogusInitializeTest -RUN: %cpp_compiler %S/BufferOverflowOnInput.cpp -o %t-BufferOverflowOnInput -RUN: %cpp_compiler %S/CounterTest.cpp -o %t-CounterTest -RUN: %cpp_compiler %S/DSO1.cpp -fPIC -shared -o %t-DSO1.so -RUN: %cpp_compiler %S/DSO2.cpp -fPIC -shared -o %t-DSO2.so -RUN: %cpp_compiler %S/DSOTestMain.cpp %S/DSOTestExtra.cpp -L. %t-DSO1.so %t-DSO2.so -o %t-DSOTest -RUN: %cpp_compiler %S/FullCoverageSetTest.cpp -o %t-FullCoverageSetTest -RUN: %cpp_compiler %S/InitializeTest.cpp -o %t-InitializeTest -RUN: %cpp_compiler %S/NotinstrumentedTest.cpp -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard -o %t-NotinstrumentedTest-NoCoverage -RUN: %cpp_compiler %S/NullDerefOnEmptyTest.cpp -o %t-NullDerefOnEmptyTest -RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest -RUN: %cpp_compiler %S/SimpleCmpTest.cpp -o %t-SimpleCmpTest -RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest -RUN: %cpp_compiler %S/StrncmpOOBTest.cpp -o %t-StrncmpOOBTest - -RUN: not %t-SimpleTest 2>&1 | FileCheck %s - -# only_ascii mode. Will perform some minimal self-validation. -RUN: not %t-SimpleTest -only_ascii=1 2>&1 - -RUN: %t-SimpleCmpTest -max_total_time=1 -use_cmp=0 2>&1 | FileCheck %s --check-prefix=MaxTotalTime -MaxTotalTime: Done {{.*}} runs in {{.}} second(s) - -RUN: not %t-NullDerefTest 2>&1 | FileCheck %s --check-prefix=NullDerefTest -RUN: not %t-NullDerefTest -close_fd_mask=3 2>&1 | FileCheck %s --check-prefix=NullDerefTest -NullDerefTest: ERROR: AddressSanitizer: {{SEGV|access-violation}} on unknown address -NullDerefTest: Test unit written to ./crash- -RUN: not %t-NullDerefTest -artifact_prefix=ZZZ 2>&1 | FileCheck %s --check-prefix=NullDerefTestPrefix -NullDerefTestPrefix: Test unit written to ZZZcrash- -RUN: not %t-NullDerefTest -artifact_prefix=ZZZ -exact_artifact_path=FOOBAR 2>&1 | FileCheck %s --check-prefix=NullDerefTestExactPath -NullDerefTestExactPath: Test unit written to FOOBAR - -RUN: not %t-NullDerefOnEmptyTest -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=NULL_DEREF_ON_EMPTY -NULL_DEREF_ON_EMPTY: stat::number_of_executed_units: - -#not %t-FullCoverageSetTest -timeout=15 -seed=1 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s - -RUN: not %t-CounterTest -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s --check-prefix=COUNTERS - -COUNTERS: INITED {{.*}} {{bits:|ft:}} -COUNTERS: NEW {{.*}} {{bits:|ft:}} {{[1-9]*}} -COUNTERS: NEW {{.*}} {{bits:|ft:}} {{[1-9]*}} -COUNTERS: BINGO - -# Don't run UninstrumentedTest for now since we build libFuzzer itself with asan. -DISABLED: not %t-UninstrumentedTest-Uninstrumented 2>&1 | FileCheck %s --check-prefix=UNINSTRUMENTED -UNINSTRUMENTED: ERROR: __sanitizer_set_death_callback is not defined. Exiting. - -RUN: not %t-NotinstrumentedTest-NoCoverage 2>&1 | FileCheck %s --check-prefix=NO_COVERAGE -NO_COVERAGE: ERROR: no interesting inputs were found. Is the code instrumented for coverage? Exiting - -RUN: not %t-BufferOverflowOnInput 2>&1 | FileCheck %s --check-prefix=OOB -OOB: AddressSanitizer: heap-buffer-overflow -OOB: is located 0 bytes to the right of 3-byte region - -RUN: not %t-InitializeTest -use_value_profile=1 2>&1 | FileCheck %s - -RUN: not %t-DSOTest 2>&1 | FileCheck %s --check-prefix=DSO -DSO: INFO: Loaded 3 modules -DSO: BINGO - -RUN: env ASAN_OPTIONS=strict_string_checks=1 not %t-StrncmpOOBTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=STRNCMP -STRNCMP: AddressSanitizer: heap-buffer-overflow -STRNCMP-NOT: __sanitizer_weak_hook_strncmp -STRNCMP: in LLVMFuzzerTestOneInput - -RUN: not %t-BogusInitializeTest 2>&1 | FileCheck %s --check-prefix=BOGUS_INITIALIZE -BOGUS_INITIALIZE: argv[0] has been modified in LLVMFuzzerInitialize Index: lib/fuzzer/test/hi.txt =================================================================== --- lib/fuzzer/test/hi.txt +++ /dev/null @@ -1 +0,0 @@ -Hi! \ No newline at end of file Index: lib/fuzzer/test/inline-8bit-counters.test =================================================================== --- lib/fuzzer/test/inline-8bit-counters.test +++ /dev/null @@ -1,5 +0,0 @@ -REQUIRES: linux -RUN: %cpp_compiler %S/SimpleTest.cpp -fno-sanitize-coverage=trace-pc-guard -fsanitize-coverage=inline-8bit-counters -o %t-SimpleTest-Inline8bitCounters -CHECK: INFO: Loaded 1 modules ({{.*}} inline 8-bit counters) -CHECK: BINGO -RUN: not %t-SimpleTest-Inline8bitCounters -runs=1000000 -seed=1 2>&1 | FileCheck %s Index: lib/fuzzer/test/lit.cfg =================================================================== --- lib/fuzzer/test/lit.cfg +++ /dev/null @@ -1,83 +0,0 @@ -import lit.formats -import sys - -config.name = "LLVMFuzzer" -config.test_format = lit.formats.ShTest(True) -config.suffixes = ['.test'] -config.test_source_root = os.path.dirname(__file__) - -# Choose between lit's internal shell pipeline runner and a real shell. If -# LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override. -use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL") -if use_lit_shell: - # 0 is external, "" is default, and everything else is internal. - execute_external = (use_lit_shell == "0") -else: - # Otherwise we default to internal on Windows and external elsewhere, as - # bash on Windows is usually very slow. - execute_external = (not sys.platform in ['win32']) - -# testFormat: The test format to use to interpret tests. -# -# For now we require '&&' between commands, until they get globally killed and -# the test runner updated. -config.test_format = lit.formats.ShTest(execute_external) - -# Tweak PATH to include llvm tools dir and current exec dir. -llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) -if (not llvm_tools_dir) or (not os.path.exists(llvm_tools_dir)): - lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % llvm_tools_dir) -path = os.path.pathsep.join((llvm_tools_dir, config.test_exec_root, - config.environment['PATH'])) -config.environment['PATH'] = path - -if config.has_lsan: - lit_config.note('lsan feature available') - config.available_features.add('lsan') -else: - lit_config.note('lsan feature unavailable') - -if sys.platform.startswith('win') or sys.platform.startswith('cygwin'): - config.available_features.add('windows') - -if sys.platform.startswith('darwin'): - config.available_features.add('darwin') - -if sys.platform.startswith('linux'): - # Note the value of ``sys.platform`` is not consistent - # between python 2 and 3, hence the use of ``.startswith()``. - lit_config.note('linux feature available') - config.available_features.add('linux') -else: - lit_config.note('linux feature unavailable') - -config.substitutions.append(('%build_dir', config.cmake_binary_dir)) - -def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True): - compiler_cmd = config.cpp_compiler if is_cpp else config.c_compiler - std_cmd = '-std=c++11' if is_cpp else '' - sanitizers = ['address'] - if fuzzer_enabled: - sanitizers.append('fuzzer') - sanitizers_cmd = ('-fsanitize=%s' % ','.join(sanitizers)) - isysroot_cmd = ('-isysroot %s' % config.osx_sysroot - ) if 'darwin' in config.target_triple else '' - include_cmd = '-I%s/../.' % config.test_source_root - return '%s %s -gline-tables-only %s %s %s' % ( - compiler_cmd, std_cmd, isysroot_cmd, sanitizers_cmd, include_cmd) - -config.substitutions.append(('%cpp_compiler', - generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True) - )) - -config.substitutions.append(('%c_compiler', - generate_compiler_cmd(is_cpp=False, fuzzer_enabled=True) - )) - -config.substitutions.append(('%no_fuzzer_cpp_compiler', - generate_compiler_cmd(is_cpp=True, fuzzer_enabled=False) - )) - -config.substitutions.append(('%no_fuzzer_c_compiler', - generate_compiler_cmd(is_cpp=False, fuzzer_enabled=False) - )) Index: lib/fuzzer/test/lit.site.cfg.in =================================================================== --- lib/fuzzer/test/lit.site.cfg.in +++ /dev/null @@ -1,9 +0,0 @@ -config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" -config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" -config.has_lsan = True if @HAS_LSAN@ == 1 else False -config.cpp_compiler = "@LIBFUZZER_TEST_CXX_COMPILER@" -config.c_compiler = "@LIBFUZZER_TEST_COMPILER@" -config.osx_sysroot = "@CMAKE_OSX_SYSROOT@" -config.cmake_binary_dir = "@CMAKE_BINARY_DIR@" -config.target_triple = "@TARGET_TRIPLE@" -lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg") Index: lib/fuzzer/test/memcmp.test =================================================================== --- lib/fuzzer/test/memcmp.test +++ /dev/null @@ -1,3 +0,0 @@ -RUN: %cpp_compiler %S/MemcmpTest.cpp -o %t-MemcmpTest -RUN: not %t-MemcmpTest -seed=1 -runs=10000000 2>&1 | FileCheck %s -CHECK: BINGO Index: lib/fuzzer/test/memcmp64.test =================================================================== --- lib/fuzzer/test/memcmp64.test +++ /dev/null @@ -1,3 +0,0 @@ -RUN: %cpp_compiler %S/Memcmp64BytesTest.cpp -o %t-Memcmp64BytesTest -RUN: not %t-Memcmp64BytesTest -seed=1 -runs=1000000 2>&1 | FileCheck %s -CHECK: BINGO Index: lib/fuzzer/test/merge-posix.test =================================================================== --- lib/fuzzer/test/merge-posix.test +++ /dev/null @@ -1,23 +0,0 @@ -RUN: %cpp_compiler %S/FullCoverageSetTest.cpp -o %t-FullCoverageSetTest - -RUN: rm -rf %tmp/T1 %tmp/T2 -RUN: mkdir -p %tmp/T1 %tmp/T2 - -RUN: echo F..... > %tmp/T1/1 -RUN: echo .U.... > %tmp/T1/2 -RUN: echo ..Z... > %tmp/T1/3 - -RUN: echo .....F > %tmp/T2/1 -RUN: echo ....U. > %tmp/T2/2 -RUN: echo ...Z.. > %tmp/T2/3 -RUN: echo ...Z.. > %tmp/T2/4 -RUN: echo ....E. > %tmp/T2/5 -RUN: echo .....R > %tmp/T2/6 - -# Check that we can report an error if file size exceeded -RUN: (ulimit -f 1; not %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=SIGXFSZ) -SIGXFSZ: ERROR: libFuzzer: file size exceeded - -# Check that we honor TMPDIR -RUN: TMPDIR=DIR_DOES_NOT_EXIST not %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=TMPDIR -TMPDIR: MERGE-OUTER: failed to write to the control file: DIR_DOES_NOT_EXIST/libFuzzerTemp Index: lib/fuzzer/test/merge-summary.test =================================================================== --- lib/fuzzer/test/merge-summary.test +++ /dev/null @@ -1,17 +0,0 @@ -RUN: %cpp_compiler %S/FullCoverageSetTest.cpp -o %t-FullCoverageSetTest - -RUN: rm -rf %t/T1 %t/T2 -RUN: mkdir -p %t/T0 %t/T1 %t/T2 -RUN: echo ...Z.. > %t/T2/1 -RUN: echo ....E. > %t/T2/2 -RUN: echo .....R > %t/T2/3 -RUN: echo F..... > %t/T2/a -RUN: echo .U.... > %t/T2/b -RUN: echo ..Z... > %t/T2/c - -RUN: %t-FullCoverageSetTest -merge=1 %t/T1 %t/T2 -save_coverage_summary=%t/SUMMARY 2>&1 | FileCheck %s --check-prefix=SAVE_SUMMARY -SAVE_SUMMARY: MERGE-OUTER: writing coverage summary for 6 files to {{.*}}SUMMARY -RUN: rm %t/T1/* -RUN: %t-FullCoverageSetTest -merge=1 %t/T1 %t/T2 -load_coverage_summary=%t/SUMMARY 2>&1 | FileCheck %s --check-prefix=LOAD_SUMMARY -LOAD_SUMMARY: MERGE-OUTER: coverage summary loaded from {{.*}}SUMMAR -LOAD_SUMMARY: MERGE-OUTER: 0 new files with 0 new features added Index: lib/fuzzer/test/merge.test =================================================================== --- lib/fuzzer/test/merge.test +++ /dev/null @@ -1,55 +0,0 @@ -CHECK: BINGO - -RUN: %cpp_compiler %S/FullCoverageSetTest.cpp -o %t-FullCoverageSetTest - -RUN: rm -rf %tmp/T0 %tmp/T1 %tmp/T2 -RUN: mkdir -p %tmp/T0 %tmp/T1 %tmp/T2 -RUN: echo F..... > %tmp/T0/1 -RUN: echo .U.... > %tmp/T0/2 -RUN: echo ..Z... > %tmp/T0/3 - -# T1 has 3 elements, T2 is empty. -RUN: cp %tmp/T0/* %tmp/T1/ -RUN: %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK1 -CHECK1: MERGE-OUTER: 3 files, 3 in the initial corpus -CHECK1: MERGE-OUTER: 0 new files with 0 new features added - -RUN: echo ...Z.. > %tmp/T2/1 -RUN: echo ....E. > %tmp/T2/2 -RUN: echo .....R > %tmp/T2/3 -RUN: echo F..... > %tmp/T2/a -RUN: echo .U.... > %tmp/T2/b -RUN: echo ..Z... > %tmp/T2/c - -# T1 has 3 elements, T2 has 6 elements, only 3 are new. -RUN: %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK2 -CHECK2: MERGE-OUTER: 9 files, 3 in the initial corpus -CHECK2: MERGE-OUTER: 3 new files with 3 new features added - -# Now, T1 has 6 units and T2 has no new interesting units. -RUN: %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK3 -CHECK3: MERGE-OUTER: 12 files, 6 in the initial corpus -CHECK3: MERGE-OUTER: 0 new files with 0 new features added - -# Check that we respect max_len during the merge and don't crash. -RUN: rm %tmp/T1/* -RUN: cp %tmp/T0/* %tmp/T1/ -RUN: echo looooooooong > %tmp/T2/looooooooong -RUN: %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 -max_len=6 2>&1 | FileCheck %s --check-prefix=MAX_LEN -MAX_LEN: MERGE-OUTER: 3 new files - -# Check that merge tolerates failures. -RUN: rm %tmp/T1/* -RUN: cp %tmp/T0/* %tmp/T1/ -RUN: echo 'FUZZER' > %tmp/T2/FUZZER -RUN: %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=MERGE_WITH_CRASH -MERGE_WITH_CRASH: MERGE-OUTER: succesfull in 2 attempt(s) -MERGE_WITH_CRASH: MERGE-OUTER: 3 new files - -# Check that we actually limit the size with max_len -RUN: %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 -max_len=5 2>&1 | FileCheck %s --check-prefix=MERGE_LEN5 -MERGE_LEN5: MERGE-OUTER: succesfull in 1 attempt(s) - -RUN: rm -rf %tmp/T1/* %tmp/T2/* -RUN: not %t-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=EMPTY -EMPTY: MERGE-OUTER: zero succesfull attempts, exiting Index: lib/fuzzer/test/minimize_crash.test =================================================================== --- lib/fuzzer/test/minimize_crash.test +++ /dev/null @@ -1,16 +0,0 @@ -RUN: %cpp_compiler %S/NullDerefTest.cpp -o %t-NullDerefTest -RUN: %cpp_compiler %S/SingleByteInputTest.cpp -o %t-SingleByteInputTest - -RUN: echo 'Hi!rv349f34t3gg' > not_minimal_crash -RUN: %t-NullDerefTest -minimize_crash=1 not_minimal_crash -max_total_time=2 2>&1 | FileCheck %s -CHECK: CRASH_MIN: failed to minimize beyond ./minimized-from-{{.*}} (3 bytes), exiting -RUN: %t-NullDerefTest -minimize_crash=1 not_minimal_crash -max_total_time=2 -exact_artifact_path=exact_minimized_path 2>&1 | FileCheck %s --check-prefix=CHECK_EXACT -CHECK_EXACT: CRASH_MIN: failed to minimize beyond exact_minimized_path (3 bytes), exiting -RUN: rm not_minimal_crash minimized-from-* exact_minimized_path - -RUN: echo -n 'abcd*xyz' > not_minimal_crash -RUN: %t-SingleByteInputTest -minimize_crash=1 not_minimal_crash -exact_artifact_path=exact_minimized_path 2>&1 | FileCheck %s --check-prefix=MIN1 -MIN1: Test unit written to exact_minimized_path -MIN1: Test unit written to exact_minimized_path -MIN1: INFO: The input is small enough, exiting -MIN1: CRASH_MIN: failed to minimize beyond exact_minimized_path (1 bytes), exiting Index: lib/fuzzer/test/minimize_two_crashes.test =================================================================== --- lib/fuzzer/test/minimize_two_crashes.test +++ /dev/null @@ -1,18 +0,0 @@ -# Test that the minimizer stops when it sees a differe bug. - -RUN: %cpp_compiler %S/TwoDifferentBugsTest.cpp -o %t-TwoDifferentBugsTest - -RUN: rm -rf %t && mkdir %t -RUN: echo H12345678901234667888090 > %t/long_crash -RUN: env ASAN_OPTIONS=dedup_token_length=3 %t-TwoDifferentBugsTest -seed=1 -minimize_crash=1 %t/long_crash -exact_artifact_path=%t/result 2>&1 | FileCheck %s - -CHECK: DedupToken1: DEDUP_TOKEN: Bar -CHECK: DedupToken2: DEDUP_TOKEN: Bar -CHECK: DedupToken1: DEDUP_TOKEN: Bar -CHECK: DedupToken2: DEDUP_TOKEN: Foo -CHECK: CRASH_MIN: mismatch in dedup tokens - -RUN: not %t-TwoDifferentBugsTest %t/result 2>&1 | FileCheck %s --check-prefix=VERIFY - -VERIFY: ERROR: AddressSanitizer: -VERIFY: in Bar Index: lib/fuzzer/test/overwrite-input.test =================================================================== --- lib/fuzzer/test/overwrite-input.test +++ /dev/null @@ -1,3 +0,0 @@ -RUN: %cpp_compiler %S/OverwriteInputTest.cpp -o %t-OverwriteInputTest -RUN: not %t-OverwriteInputTest 2>&1 | FileCheck %s -CHECK: ERROR: libFuzzer: fuzz target overwrites it's const input Index: lib/fuzzer/test/recommended-dictionary.test =================================================================== --- lib/fuzzer/test/recommended-dictionary.test +++ /dev/null @@ -1,6 +0,0 @@ -RUN: %cpp_compiler %S/RepeatedMemcmp.cpp -o %t-RepeatedMemcmp -RUN: %t-RepeatedMemcmp -seed=11 -runs=100000 -max_len=20 2>&1 | FileCheck %s --check-prefix=RECOMMENDED_DICT -RECOMMENDED_DICT:###### Recommended dictionary. ###### -RECOMMENDED_DICT-DAG: "foo" -RECOMMENDED_DICT-DAG: "bar" -RECOMMENDED_DICT:###### End of recommended dictionary. ###### Index: lib/fuzzer/test/reduce_inputs.test =================================================================== --- lib/fuzzer/test/reduce_inputs.test +++ /dev/null @@ -1,16 +0,0 @@ -# Test -reduce_inputs=1 - -RUN: rm -rf %t/C -RUN: mkdir -p %t/C -RUN: %cpp_compiler %S/ShrinkControlFlowSimpleTest.cpp -o %t-ShrinkControlFlowSimpleTest -RUN: %cpp_compiler %S/ShrinkControlFlowTest.cpp -o %t-ShrinkControlFlowTest -RUN: %t-ShrinkControlFlowSimpleTest -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000 %t/C 2>&1 | FileCheck %s -CHECK: INFO: found item with checksum '0eb8e4ed029b774d80f2b66408203801cb982a60' - -# Test that reduce_inputs deletes redundant files in the corpus. -RUN: %t-ShrinkControlFlowSimpleTest -runs=0 %t/C 2>&1 | FileCheck %s --check-prefix=COUNT -COUNT: READ units: 4 - -# a bit longer test -RUN: %t-ShrinkControlFlowTest -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -seed=1 -runs=1000000 2>&1 | FileCheck %s - Index: lib/fuzzer/test/repeated-bytes.test =================================================================== --- lib/fuzzer/test/repeated-bytes.test +++ /dev/null @@ -1,3 +0,0 @@ -RUN: %cpp_compiler %S/RepeatedBytesTest.cpp -o %t-RepeatedBytesTest -CHECK: BINGO -RUN: not %t-RepeatedBytesTest -seed=1 -runs=1000000 2>&1 | FileCheck %s Index: lib/fuzzer/test/shrink.test =================================================================== --- lib/fuzzer/test/shrink.test +++ /dev/null @@ -1,10 +0,0 @@ -RUN: %cpp_compiler %S/ShrinkControlFlowTest.cpp -o %t-ShrinkControlFlowTest -RUN: %cpp_compiler %S/ShrinkValueProfileTest.cpp -o %t-ShrinkValueProfileTest -RUN: %t-ShrinkControlFlowTest -seed=1 -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000 -shrink=1 -reduce_inputs=0 2>&1 | FileCheck %s --check-prefix=SHRINK1 -# Limit max_len to run this negative test faster. -RUN: %t-ShrinkControlFlowTest -seed=1 -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000 -shrink=0 -reduce_inputs=0 -max_len=64 2>&1 | FileCheck %s --check-prefix=SHRINK0 -RUN: %t-ShrinkValueProfileTest -seed=1 -exit_on_item=aea2e3923af219a8956f626558ef32f30a914ebc -runs=100000 -shrink=1 -reduce_inputs=0 -use_value_profile=1 2>&1 | FileCheck %s --check-prefix=SHRINK1_VP - -SHRINK0: Done 1000000 runs in -SHRINK1: INFO: found item with checksum '0eb8e4ed029b774d80f2b66408203801cb982a60', exiting. -SHRINK1_VP: INFO: found item with checksum 'aea2e3923af219a8956f626558ef32f30a914ebc', exiting Index: lib/fuzzer/test/simple-cmp.test =================================================================== --- lib/fuzzer/test/simple-cmp.test +++ /dev/null @@ -1,3 +0,0 @@ -RUN: %cpp_compiler %S/SimpleCmpTest.cpp -o %t-SimpleCmpTest -CHECK: BINGO -RUN: not %t-SimpleCmpTest -seed=1 -runs=100000000 2>&1 | FileCheck %s Index: lib/fuzzer/test/standalone.test =================================================================== --- lib/fuzzer/test/standalone.test +++ /dev/null @@ -1,8 +0,0 @@ -RUN: %no_fuzzer_c_compiler %S/../standalone/StandaloneFuzzTargetMain.c -c -o %t_1.o -RUN: %no_fuzzer_cpp_compiler %S/InitializeTest.cpp -c -o %t_2.o - -RUN: %no_fuzzer_cpp_compiler %t_1.o %t_2.o %build_dir/lib/libLLVMFuzzerNoMain.a -o %t-StandaloneInitializeTest -RUN: %t-StandaloneInitializeTest %S/hi.txt %S/dict1.txt 2>&1 | FileCheck %s -CHECK: StandaloneFuzzTargetMain: running 2 inputs -CHECK: Done: {{.*}}hi.txt: (3 bytes) -CHECK: Done: {{.*}}dict1.txt: (61 bytes) Index: lib/fuzzer/test/strcmp.test =================================================================== --- lib/fuzzer/test/strcmp.test +++ /dev/null @@ -1,4 +0,0 @@ -RUN: %cpp_compiler %S/StrcmpTest.cpp -o %t-StrcmpTest -RUN: not %t-StrcmpTest -seed=1 -runs=2000000 2>&1 | FileCheck %s -CHECK: BINGO - Index: lib/fuzzer/test/strncmp.test =================================================================== --- lib/fuzzer/test/strncmp.test +++ /dev/null @@ -1,4 +0,0 @@ -RUN: %cpp_compiler %S/StrncmpTest.cpp -o %t-StrncmpTest -RUN: not %t-StrncmpTest -seed=2 -runs=10000000 2>&1 | FileCheck %s -CHECK: BINGO - Index: lib/fuzzer/test/strstr.test =================================================================== --- lib/fuzzer/test/strstr.test +++ /dev/null @@ -1,4 +0,0 @@ -RUN: %cpp_compiler %S/StrstrTest.cpp -o %t-StrstrTest -RUN: not %t-StrstrTest -seed=1 -runs=2000000 2>&1 | FileCheck %s -CHECK: BINGO - Index: lib/fuzzer/test/swap-cmp.test =================================================================== --- lib/fuzzer/test/swap-cmp.test +++ /dev/null @@ -1,3 +0,0 @@ -RUN: %cpp_compiler %S/SwapCmpTest.cpp -o %t-SwapCmpTest -CHECK: BINGO -RUN: not %t-SwapCmpTest -seed=1 -runs=10000000 2>&1 | FileCheck %s Index: lib/fuzzer/test/trace-malloc-2.test =================================================================== --- lib/fuzzer/test/trace-malloc-2.test +++ /dev/null @@ -1,10 +0,0 @@ -// FIXME: This test infinite loops on darwin because it crashes -// printing a stack trace repeatedly -UNSUPPORTED: darwin - -RUN: %cpp_compiler %S/TraceMallocTest.cpp -o %t-TraceMallocTest - -RUN: %t-TraceMallocTest -seed=1 -trace_malloc=2 -runs=1000 2>&1 | FileCheck %s --check-prefix=TRACE2 -TRACE2-DAG: FREE[0] -TRACE2-DAG: MALLOC[0] -TRACE2-DAG: in LLVMFuzzerTestOneInput Index: lib/fuzzer/test/trace-malloc.test =================================================================== --- lib/fuzzer/test/trace-malloc.test +++ /dev/null @@ -1,7 +0,0 @@ -RUN: %cpp_compiler %S/TraceMallocTest.cpp -o %t-TraceMallocTest - -RUN: %t-TraceMallocTest -seed=1 -trace_malloc=1 -runs=10000 2>&1 | FileCheck %s -CHECK-DAG: MallocFreeTracer: STOP 0 0 (same) -CHECK-DAG: MallocFreeTracer: STOP 0 1 (DIFFERENT) -CHECK-DAG: MallocFreeTracer: STOP 1 0 (DIFFERENT) -CHECK-DAG: MallocFreeTracer: STOP 1 1 (same) Index: lib/fuzzer/test/trace-pc.test =================================================================== --- lib/fuzzer/test/trace-pc.test +++ /dev/null @@ -1,3 +0,0 @@ -RUN: %cpp_compiler %S/SimpleTest.cpp -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard -fsanitize-coverage=trace-pc -o %t-SimpleTest-TracePC -CHECK: BINGO -RUN: not %t-SimpleTest-TracePC -runs=1000000 -seed=1 2>&1 | FileCheck %s Index: lib/fuzzer/test/ulimit.test =================================================================== --- lib/fuzzer/test/ulimit.test +++ /dev/null @@ -1,3 +0,0 @@ -RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest -RUN: ulimit -s 1000 -RUN: not %t-SimpleTest Index: lib/fuzzer/test/unit/lit.cfg =================================================================== --- lib/fuzzer/test/unit/lit.cfg +++ /dev/null @@ -1,7 +0,0 @@ -import lit.formats - -config.name = "LLVMFuzzer-Unittest" -print config.test_exec_root -config.test_format = lit.formats.GoogleTest(".", "Unittest") -config.suffixes = [] -config.test_source_root = config.test_exec_root Index: lib/fuzzer/test/unit/lit.site.cfg.in =================================================================== --- lib/fuzzer/test/unit/lit.site.cfg.in +++ /dev/null @@ -1,2 +0,0 @@ -config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" -lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/unit/lit.cfg") Index: lib/fuzzer/test/value-profile-cmp.test =================================================================== --- lib/fuzzer/test/value-profile-cmp.test +++ /dev/null @@ -1,3 +0,0 @@ -CHECK: BINGO -RUN: %cpp_compiler %S/SimpleCmpTest.cpp -o %t-SimpleCmpTest -RUN: not %t-SimpleCmpTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s Index: lib/fuzzer/test/value-profile-cmp2.test =================================================================== --- lib/fuzzer/test/value-profile-cmp2.test +++ /dev/null @@ -1,3 +0,0 @@ -CHECK: BINGO -RUN: %cpp_compiler %S/SimpleHashTest.cpp -o %t-SimpleHashTest -RUN: not %t-SimpleHashTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 -max_len=64 2>&1 | FileCheck %s Index: lib/fuzzer/test/value-profile-cmp3.test =================================================================== --- lib/fuzzer/test/value-profile-cmp3.test +++ /dev/null @@ -1,3 +0,0 @@ -CHECK: BINGO -RUN: %cpp_compiler %S/AbsNegAndConstantTest.cpp -o %t-AbsNegAndConstantTest -RUN: not %t-AbsNegAndConstantTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s Index: lib/fuzzer/test/value-profile-cmp4.test =================================================================== --- lib/fuzzer/test/value-profile-cmp4.test +++ /dev/null @@ -1,3 +0,0 @@ -CHECK: BINGO -RUN: %cpp_compiler %S/AbsNegAndConstant64Test.cpp -o %t-AbsNegAndConstant64Test -RUN: not %t-AbsNegAndConstant64Test -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s Index: lib/fuzzer/test/value-profile-div.test =================================================================== --- lib/fuzzer/test/value-profile-div.test +++ /dev/null @@ -1,4 +0,0 @@ -CHECK: AddressSanitizer: {{FPE|int-divide-by-zero}} -RUN: %cpp_compiler %S/DivTest.cpp -fsanitize-coverage=trace-div -o %t-DivTest -RUN: not %t-DivTest -seed=1 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s - Index: lib/fuzzer/test/value-profile-load.test =================================================================== --- lib/fuzzer/test/value-profile-load.test +++ /dev/null @@ -1,3 +0,0 @@ -CHECK: AddressSanitizer: global-buffer-overflow -RUN: %cpp_compiler %S/LoadTest.cpp -fsanitize-coverage=trace-pc-guard,indirect-calls,trace-gep,trace-div,trace-cmp -o %t-LoadTest -RUN: not %t-LoadTest -seed=2 -use_cmp=0 -use_value_profile=1 -runs=20000000 2>&1 | FileCheck %s Index: lib/fuzzer/test/value-profile-mem.test =================================================================== --- lib/fuzzer/test/value-profile-mem.test +++ /dev/null @@ -1,3 +0,0 @@ -CHECK: BINGO -RUN: %cpp_compiler %S/SingleMemcmpTest.cpp -o %t-SingleMemcmpTest -RUN: not %t-SingleMemcmpTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s Index: lib/fuzzer/test/value-profile-set.test =================================================================== --- lib/fuzzer/test/value-profile-set.test +++ /dev/null @@ -1,4 +0,0 @@ -CHECK: BINGO -RUN: %cpp_compiler %S/FourIndependentBranchesTest.cpp -o %t-FourIndependentBranchesTest -RUN: not %t-FourIndependentBranchesTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s - Index: lib/fuzzer/test/value-profile-strcmp.test =================================================================== --- lib/fuzzer/test/value-profile-strcmp.test +++ /dev/null @@ -1,3 +0,0 @@ -CHECK: BINGO -RUN: %cpp_compiler %S/SingleStrcmpTest.cpp -o %t-SingleStrcmpTest -RUN: not %t-SingleStrcmpTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s Index: lib/fuzzer/test/value-profile-strncmp.test =================================================================== --- lib/fuzzer/test/value-profile-strncmp.test +++ /dev/null @@ -1,3 +0,0 @@ -CHECK: BINGO -RUN: %cpp_compiler %S/SingleStrncmpTest.cpp -o %t-SingleStrncmpTest -RUN: not %t-SingleStrncmpTest -seed=1 -use_cmp=0 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s Index: lib/fuzzer/test/value-profile-switch.test =================================================================== --- lib/fuzzer/test/value-profile-switch.test +++ /dev/null @@ -1,5 +0,0 @@ -CHECK: BINGO -RUN: %cpp_compiler %S/SwitchTest.cpp -o %t-SwitchTest -RUN: %cpp_compiler %S/Switch2Test.cpp -o %t-Switch2Test -RUN: not %t-SwitchTest -use_cmp=0 -use_value_profile=1 -runs=100000000 -seed=1 2>&1 | FileCheck %s -RUN: not %t-Switch2Test -use_cmp=0 -use_value_profile=1 -runs=100000000 -seed=1 2>&1 | FileCheck %s