├── Fuzzer ├── CMakeLists.txt ├── FuzzerCorpus.h ├── FuzzerCrossOver.cpp ├── FuzzerDefs.h ├── FuzzerDictionary.h ├── FuzzerDriver.cpp ├── FuzzerExtFunctions.def ├── FuzzerExtFunctions.h ├── FuzzerExtFunctionsDlsym.cpp ├── FuzzerExtFunctionsWeak.cpp ├── FuzzerFlags.def ├── FuzzerFnAdapter.h ├── FuzzerIO.cpp ├── FuzzerInterface.h ├── FuzzerInternal.h ├── FuzzerLoop.cpp ├── FuzzerMain.cpp ├── FuzzerMutate.cpp ├── FuzzerMutate.h ├── FuzzerOptions.h ├── FuzzerRandom.h ├── FuzzerSHA1.cpp ├── FuzzerTracePC.cpp ├── FuzzerTracePC.h ├── FuzzerTraceState.cpp ├── FuzzerUtil.cpp ├── FuzzerUtilDarwin.cpp ├── FuzzerUtilLinux.cpp ├── FuzzerValueBitMap.h ├── README.txt ├── afl │ └── afl_driver.cpp ├── build.sh ├── cxx.dict ├── standalone │ └── StandaloneFuzzTargetMain.c └── test │ ├── AFLDriverTest.cpp │ ├── AbsNegAndConstant64Test.cpp │ ├── AbsNegAndConstantTest.cpp │ ├── AccumulateAllocationsTest.cpp │ ├── BufferOverflowOnInput.cpp │ ├── CMakeLists.txt │ ├── CallerCalleeTest.cpp │ ├── CounterTest.cpp │ ├── CustomCrossOverTest.cpp │ ├── CustomMutatorTest.cpp │ ├── DSO1.cpp │ ├── DSO2.cpp │ ├── DSOTestExtra.cpp │ ├── DSOTestMain.cpp │ ├── DivTest.cpp │ ├── EmptyTest.cpp │ ├── FourIndependentBranchesTest.cpp │ ├── FullCoverageSetTest.cpp │ ├── FuzzerFnAdapterUnittest.cpp │ ├── FuzzerUnittest.cpp │ ├── InitializeTest.cpp │ ├── LeakTest.cpp │ ├── LeakTimeoutTest.cpp │ ├── LoadTest.cpp │ ├── MemcmpTest.cpp │ ├── NthRunCrashTest.cpp │ ├── NullDerefOnEmptyTest.cpp │ ├── NullDerefTest.cpp │ ├── OneHugeAllocTest.cpp │ ├── OutOfMemoryTest.cpp │ ├── RepeatedBytesTest.cpp │ ├── RepeatedMemcmp.cpp │ ├── ShrinkControlFlowTest.cpp │ ├── ShrinkValueProfileTest.cpp │ ├── SignedIntOverflowTest.cpp │ ├── SimpleCmpTest.cpp │ ├── SimpleDictionaryTest.cpp │ ├── SimpleFnAdapterTest.cpp │ ├── SimpleHashTest.cpp │ ├── SimpleTest.cpp │ ├── SimpleThreadedTest.cpp │ ├── SingleMemcmpTest.cpp │ ├── SingleStrcmpTest.cpp │ ├── SingleStrncmpTest.cpp │ ├── SpamyTest.cpp │ ├── StrcmpTest.cpp │ ├── StrncmpOOBTest.cpp │ ├── StrncmpTest.cpp │ ├── StrstrTest.cpp │ ├── SwapCmpTest.cpp │ ├── Switch2Test.cpp │ ├── SwitchTest.cpp │ ├── ThreadedLeakTest.cpp │ ├── ThreadedTest.cpp │ ├── TimeoutTest.cpp │ ├── TraceMallocTest.cpp │ ├── UninstrumentedTest.cpp │ ├── afl-driver-extra-stats.test │ ├── afl-driver-stderr.test │ ├── coverage.test │ ├── dict1.txt │ ├── fuzzer-customcrossover.test │ ├── fuzzer-custommutator.test │ ├── fuzzer-dict.test │ ├── fuzzer-dirs.test │ ├── fuzzer-fdmask.test │ ├── fuzzer-finalstats.test │ ├── fuzzer-flags.test │ ├── fuzzer-fn-adapter.test │ ├── fuzzer-jobs.test │ ├── fuzzer-leak.test │ ├── fuzzer-oom-with-profile.test │ ├── fuzzer-oom.test │ ├── fuzzer-printcovpcs.test │ ├── fuzzer-runs.test │ ├── fuzzer-seed.test │ ├── fuzzer-segv.test │ ├── fuzzer-singleinputs.test │ ├── fuzzer-threaded.test │ ├── fuzzer-timeout.test │ ├── fuzzer-traces-hooks.test │ ├── fuzzer-ubsan.test │ ├── fuzzer.test │ ├── hi.txt │ ├── lit.cfg │ ├── lit.site.cfg.in │ ├── merge.test │ ├── minimize_crash.test │ ├── no-coverage │ └── CMakeLists.txt │ ├── repeated-bytes.test │ ├── shrink.test │ ├── simple-cmp.test │ ├── standalone.test │ ├── swap-cmp.test │ ├── trace-bb │ └── CMakeLists.txt │ ├── trace-malloc.test │ ├── trace-pc │ └── CMakeLists.txt │ ├── ubsan │ └── CMakeLists.txt │ ├── uninstrumented │ └── CMakeLists.txt │ ├── unit │ ├── lit.cfg │ └── lit.site.cfg.in │ ├── value-profile-cmp.test │ ├── value-profile-div.test │ ├── value-profile-load.test │ ├── value-profile-mem.test │ ├── value-profile-set.test │ └── value-profile-switch.test ├── Makefile ├── fail_pg.c ├── fuzz-functions.py ├── make.sh ├── test_function.c ├── test_harness.cpp ├── test_main.c ├── test_pg.c └── test_pg_simple.c /Fuzzer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LIBFUZZER_FLAGS_BASE "${CMAKE_CXX_FLAGS}") 2 | # Disable the coverage and sanitizer instrumentation for the fuzzer itself. 3 | set(CMAKE_CXX_FLAGS "${LIBFUZZER_FLAGS_BASE} -fno-sanitize=all -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters -Werror") 4 | #if( LLVM_USE_SANITIZE_COVERAGE ) 5 | if(NOT "${LLVM_USE_SANITIZER}" STREQUAL "Address") 6 | message(FATAL_ERROR 7 | "LibFuzzer and its tests require LLVM_USE_SANITIZER=Address and " 8 | "LLVM_USE_SANITIZE_COVERAGE=YES to be set." 9 | ) 10 | endif() 11 | add_library(LLVMFuzzerNoMainObjects OBJECT 12 | FuzzerCrossOver.cpp 13 | FuzzerTraceState.cpp 14 | FuzzerDriver.cpp 15 | FuzzerExtFunctionsDlsym.cpp 16 | FuzzerExtFunctionsWeak.cpp 17 | FuzzerIO.cpp 18 | FuzzerLoop.cpp 19 | FuzzerMutate.cpp 20 | FuzzerSHA1.cpp 21 | FuzzerTracePC.cpp 22 | FuzzerUtil.cpp 23 | FuzzerUtilDarwin.cpp 24 | FuzzerUtilLinux.cpp 25 | ) 26 | add_library(LLVMFuzzerNoMain STATIC 27 | $ 28 | ) 29 | target_link_libraries(LLVMFuzzerNoMain ${PTHREAD_LIB}) 30 | add_library(LLVMFuzzer STATIC 31 | FuzzerMain.cpp 32 | $ 33 | ) 34 | target_link_libraries(LLVMFuzzer ${PTHREAD_LIB}) 35 | 36 | # if( LLVM_INCLUDE_TESTS ) 37 | # add_subdirectory(test) 38 | # endif() 39 | #endif() 40 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerCorpus.h: -------------------------------------------------------------------------------- 1 | //===- FuzzerCorpus.h - Internal header for the Fuzzer ----------*- C++ -* ===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // fuzzer::InputCorpus 10 | //===----------------------------------------------------------------------===// 11 | 12 | #ifndef LLVM_FUZZER_CORPUS 13 | #define LLVM_FUZZER_CORPUS 14 | 15 | #include 16 | #include 17 | 18 | #include "FuzzerDefs.h" 19 | #include "FuzzerRandom.h" 20 | #include "FuzzerTracePC.h" 21 | 22 | namespace fuzzer { 23 | 24 | struct InputInfo { 25 | Unit U; // The actual input data. 26 | uint8_t Sha1[kSHA1NumBytes]; // Checksum. 27 | // Number of features that this input has and no smaller input has. 28 | size_t NumFeatures = 0; 29 | size_t Tmp = 0; // Used by ValidateFeatureSet. 30 | // Stats. 31 | size_t NumExecutedMutations = 0; 32 | size_t NumSuccessfullMutations = 0; 33 | bool MayDeleteFile = false; 34 | }; 35 | 36 | class InputCorpus { 37 | public: 38 | static const size_t kFeatureSetSize = 1 << 16; 39 | InputCorpus(const std::string &OutputCorpus) : OutputCorpus(OutputCorpus) { 40 | memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature)); 41 | memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature)); 42 | } 43 | ~InputCorpus() { 44 | for (auto II : Inputs) 45 | delete II; 46 | } 47 | size_t size() const { return Inputs.size(); } 48 | size_t SizeInBytes() const { 49 | size_t Res = 0; 50 | for (auto II : Inputs) 51 | Res += II->U.size(); 52 | return Res; 53 | } 54 | size_t NumActiveUnits() const { 55 | size_t Res = 0; 56 | for (auto II : Inputs) 57 | Res += !II->U.empty(); 58 | return Res; 59 | } 60 | bool empty() const { return Inputs.empty(); } 61 | const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; } 62 | void AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile = false) { 63 | assert(!U.empty()); 64 | uint8_t Hash[kSHA1NumBytes]; 65 | if (FeatureDebug) 66 | Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures); 67 | ComputeSHA1(U.data(), U.size(), Hash); 68 | Hashes.insert(Sha1ToString(Hash)); 69 | Inputs.push_back(new InputInfo()); 70 | InputInfo &II = *Inputs.back(); 71 | II.U = U; 72 | II.NumFeatures = NumFeatures; 73 | II.MayDeleteFile = MayDeleteFile; 74 | memcpy(II.Sha1, Hash, kSHA1NumBytes); 75 | UpdateCorpusDistribution(); 76 | ValidateFeatureSet(); 77 | } 78 | 79 | bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); } 80 | bool HasUnit(const std::string &H) { return Hashes.count(H); } 81 | InputInfo &ChooseUnitToMutate(Random &Rand) { 82 | InputInfo &II = *Inputs[ChooseUnitIdxToMutate(Rand)]; 83 | assert(!II.U.empty()); 84 | return II; 85 | }; 86 | 87 | // Returns an index of random unit from the corpus to mutate. 88 | // Hypothesis: units added to the corpus last are more likely to be 89 | // interesting. This function gives more weight to the more recent units. 90 | size_t ChooseUnitIdxToMutate(Random &Rand) { 91 | size_t Idx = static_cast(CorpusDistribution(Rand.Get_mt19937())); 92 | assert(Idx < Inputs.size()); 93 | return Idx; 94 | } 95 | 96 | void PrintStats() { 97 | for (size_t i = 0; i < Inputs.size(); i++) { 98 | const auto &II = *Inputs[i]; 99 | Printf(" [%zd %s]\tsz: %zd\truns: %zd\tsucc: %zd\n", i, 100 | Sha1ToString(II.Sha1).c_str(), II.U.size(), 101 | II.NumExecutedMutations, II.NumSuccessfullMutations); 102 | } 103 | } 104 | 105 | void PrintFeatureSet() { 106 | for (size_t i = 0; i < kFeatureSetSize; i++) { 107 | if(size_t Sz = GetFeature(i)) 108 | Printf("[%zd: id %zd sz%zd] ", i, SmallestElementPerFeature[i], Sz); 109 | } 110 | Printf("\n\t"); 111 | for (size_t i = 0; i < Inputs.size(); i++) 112 | if (size_t N = Inputs[i]->NumFeatures) 113 | Printf(" %zd=>%zd ", i, N); 114 | Printf("\n"); 115 | } 116 | 117 | void DeleteInput(size_t Idx) { 118 | InputInfo &II = *Inputs[Idx]; 119 | if (!OutputCorpus.empty() && II.MayDeleteFile) 120 | DeleteFile(DirPlusFile(OutputCorpus, Sha1ToString(II.Sha1))); 121 | Unit().swap(II.U); 122 | if (FeatureDebug) 123 | Printf("EVICTED %zd\n", Idx); 124 | } 125 | 126 | bool AddFeature(size_t Idx, uint32_t NewSize, bool Shrink) { 127 | assert(NewSize); 128 | Idx = Idx % kFeatureSetSize; 129 | uint32_t OldSize = GetFeature(Idx); 130 | if (OldSize == 0 || (Shrink && OldSize > NewSize)) { 131 | if (OldSize > 0) { 132 | size_t OldIdx = SmallestElementPerFeature[Idx]; 133 | InputInfo &II = *Inputs[OldIdx]; 134 | assert(II.NumFeatures > 0); 135 | II.NumFeatures--; 136 | if (II.NumFeatures == 0) 137 | DeleteInput(OldIdx); 138 | } 139 | if (FeatureDebug) 140 | Printf("ADD FEATURE %zd sz %d\n", Idx, NewSize); 141 | SmallestElementPerFeature[Idx] = Inputs.size(); 142 | InputSizesPerFeature[Idx] = NewSize; 143 | CountingFeatures = true; 144 | return true; 145 | } 146 | return false; 147 | } 148 | 149 | size_t NumFeatures() const { 150 | size_t Res = 0; 151 | for (size_t i = 0; i < kFeatureSetSize; i++) 152 | Res += GetFeature(i) != 0; 153 | return Res; 154 | } 155 | 156 | void ResetFeatureSet() { 157 | assert(Inputs.empty()); 158 | memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature)); 159 | memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature)); 160 | } 161 | 162 | private: 163 | 164 | static const bool FeatureDebug = false; 165 | 166 | size_t GetFeature(size_t Idx) const { return InputSizesPerFeature[Idx]; } 167 | 168 | void ValidateFeatureSet() { 169 | if (!CountingFeatures) return; 170 | if (FeatureDebug) 171 | PrintFeatureSet(); 172 | for (size_t Idx = 0; Idx < kFeatureSetSize; Idx++) 173 | if (GetFeature(Idx)) 174 | Inputs[SmallestElementPerFeature[Idx]]->Tmp++; 175 | for (auto II: Inputs) { 176 | if (II->Tmp != II->NumFeatures) 177 | Printf("ZZZ %zd %zd\n", II->Tmp, II->NumFeatures); 178 | assert(II->Tmp == II->NumFeatures); 179 | II->Tmp = 0; 180 | } 181 | } 182 | 183 | // Updates the probability distribution for the units in the corpus. 184 | // Must be called whenever the corpus or unit weights are changed. 185 | void UpdateCorpusDistribution() { 186 | size_t N = Inputs.size(); 187 | Intervals.resize(N + 1); 188 | Weights.resize(N); 189 | std::iota(Intervals.begin(), Intervals.end(), 0); 190 | if (CountingFeatures) 191 | for (size_t i = 0; i < N; i++) 192 | Weights[i] = Inputs[i]->NumFeatures * (i + 1); 193 | else 194 | std::iota(Weights.begin(), Weights.end(), 1); 195 | CorpusDistribution = std::piecewise_constant_distribution( 196 | Intervals.begin(), Intervals.end(), Weights.begin()); 197 | } 198 | std::piecewise_constant_distribution CorpusDistribution; 199 | 200 | std::vector Intervals; 201 | std::vector Weights; 202 | 203 | std::unordered_set Hashes; 204 | std::vector Inputs; 205 | 206 | bool CountingFeatures = false; 207 | uint32_t InputSizesPerFeature[kFeatureSetSize]; 208 | uint32_t SmallestElementPerFeature[kFeatureSetSize]; 209 | 210 | std::string OutputCorpus; 211 | }; 212 | 213 | } // namespace fuzzer 214 | 215 | #endif // LLVM_FUZZER_CORPUS 216 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerCrossOver.cpp: -------------------------------------------------------------------------------- 1 | //===- FuzzerCrossOver.cpp - Cross over two test inputs -------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // Cross over test inputs. 10 | //===----------------------------------------------------------------------===// 11 | 12 | #include 13 | 14 | #include "FuzzerDefs.h" 15 | #include "FuzzerMutate.h" 16 | #include "FuzzerRandom.h" 17 | 18 | namespace fuzzer { 19 | 20 | // Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out. 21 | size_t MutationDispatcher::CrossOver(const uint8_t *Data1, size_t Size1, 22 | const uint8_t *Data2, size_t Size2, 23 | uint8_t *Out, size_t MaxOutSize) { 24 | assert(Size1 || Size2); 25 | MaxOutSize = Rand(MaxOutSize) + 1; 26 | size_t OutPos = 0; 27 | size_t Pos1 = 0; 28 | size_t Pos2 = 0; 29 | size_t *InPos = &Pos1; 30 | size_t InSize = Size1; 31 | const uint8_t *Data = Data1; 32 | bool CurrentlyUsingFirstData = true; 33 | while (OutPos < MaxOutSize && (Pos1 < Size1 || Pos2 < Size2)) { 34 | // Merge a part of Data into Out. 35 | size_t OutSizeLeft = MaxOutSize - OutPos; 36 | if (*InPos < InSize) { 37 | size_t InSizeLeft = InSize - *InPos; 38 | size_t MaxExtraSize = std::min(OutSizeLeft, InSizeLeft); 39 | size_t ExtraSize = Rand(MaxExtraSize) + 1; 40 | memcpy(Out + OutPos, Data + *InPos, ExtraSize); 41 | OutPos += ExtraSize; 42 | (*InPos) += ExtraSize; 43 | } 44 | // Use the other input data on the next iteration. 45 | InPos = CurrentlyUsingFirstData ? &Pos2 : &Pos1; 46 | InSize = CurrentlyUsingFirstData ? Size2 : Size1; 47 | Data = CurrentlyUsingFirstData ? Data2 : Data1; 48 | CurrentlyUsingFirstData = !CurrentlyUsingFirstData; 49 | } 50 | return OutPos; 51 | } 52 | 53 | } // namespace fuzzer 54 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerDefs.h: -------------------------------------------------------------------------------- 1 | //===- FuzzerDefs.h - Internal header for the Fuzzer ------------*- C++ -* ===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // Basic definitions. 10 | //===----------------------------------------------------------------------===// 11 | #ifndef LLVM_FUZZER_DEFS_H 12 | #define LLVM_FUZZER_DEFS_H 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | // Platform detection. 22 | #ifdef __linux__ 23 | #define LIBFUZZER_LINUX 1 24 | #define LIBFUZZER_APPLE 0 25 | #elif __APPLE__ 26 | #define LIBFUZZER_LINUX 0 27 | #define LIBFUZZER_APPLE 1 28 | #else 29 | #error "Support for your platform has not been implemented" 30 | #endif 31 | 32 | #ifdef __x86_64 33 | #define ATTRIBUTE_TARGET_POPCNT __attribute__((target("popcnt"))) 34 | #else 35 | #define ATTRIBUTE_TARGET_POPCNT 36 | #endif 37 | 38 | namespace fuzzer { 39 | 40 | template T Min(T a, T b) { return a < b ? a : b; } 41 | template T Max(T a, T b) { return a > b ? a : b; } 42 | 43 | class Random; 44 | class Dictionary; 45 | class DictionaryEntry; 46 | class MutationDispatcher; 47 | struct FuzzingOptions; 48 | class InputCorpus; 49 | struct InputInfo; 50 | struct ExternalFunctions; 51 | 52 | // Global interface to functions that may or may not be available. 53 | extern ExternalFunctions *EF; 54 | 55 | typedef std::vector Unit; 56 | typedef std::vector UnitVector; 57 | typedef int (*UserCallback)(const uint8_t *Data, size_t Size); 58 | int FuzzerDriver(int *argc, char ***argv, UserCallback Callback); 59 | 60 | bool IsFile(const std::string &Path); 61 | long GetEpoch(const std::string &Path); 62 | std::string FileToString(const std::string &Path); 63 | Unit FileToVector(const std::string &Path, size_t MaxSize = 0, 64 | bool ExitOnError = true); 65 | void ReadDirToVectorOfUnits(const char *Path, std::vector *V, 66 | long *Epoch, size_t MaxSize, bool ExitOnError); 67 | void WriteToFile(const Unit &U, const std::string &Path); 68 | void CopyFileToErr(const std::string &Path); 69 | void DeleteFile(const std::string &Path); 70 | // Returns "Dir/FileName" or equivalent for the current OS. 71 | std::string DirPlusFile(const std::string &DirPath, 72 | const std::string &FileName); 73 | 74 | void DupAndCloseStderr(); 75 | void CloseStdout(); 76 | void Printf(const char *Fmt, ...); 77 | void PrintHexArray(const Unit &U, const char *PrintAfter = ""); 78 | void PrintHexArray(const uint8_t *Data, size_t Size, 79 | const char *PrintAfter = ""); 80 | void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = ""); 81 | void PrintASCII(const Unit &U, const char *PrintAfter = ""); 82 | 83 | void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC); 84 | std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC); 85 | std::string Hash(const Unit &U); 86 | void SetTimer(int Seconds); 87 | void SetSigSegvHandler(); 88 | void SetSigBusHandler(); 89 | void SetSigAbrtHandler(); 90 | void SetSigIllHandler(); 91 | void SetSigFpeHandler(); 92 | void SetSigIntHandler(); 93 | void SetSigTermHandler(); 94 | std::string Base64(const Unit &U); 95 | int ExecuteCommand(const std::string &Command); 96 | bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out); 97 | 98 | size_t GetPeakRSSMb(); 99 | 100 | // Private copy of SHA1 implementation. 101 | static const int kSHA1NumBytes = 20; 102 | // Computes SHA1 hash of 'Len' bytes in 'Data', writes kSHA1NumBytes to 'Out'. 103 | void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out); 104 | std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]); 105 | 106 | // Changes U to contain only ASCII (isprint+isspace) characters. 107 | // Returns true iff U has been changed. 108 | bool ToASCII(uint8_t *Data, size_t Size); 109 | bool IsASCII(const Unit &U); 110 | bool IsASCII(const uint8_t *Data, size_t Size); 111 | 112 | int NumberOfCpuCores(); 113 | int GetPid(); 114 | void SleepSeconds(int Seconds); 115 | 116 | 117 | struct ScopedDoingMyOwnMemmem { 118 | ScopedDoingMyOwnMemmem(); 119 | ~ScopedDoingMyOwnMemmem(); 120 | }; 121 | 122 | inline uint8_t Bswap(uint8_t x) { return x; } 123 | inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); } 124 | inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); } 125 | inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); } 126 | 127 | } // namespace fuzzer 128 | #endif // LLVM_FUZZER_DEFS_H 129 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerDictionary.h: -------------------------------------------------------------------------------- 1 | //===- FuzzerDictionary.h - Internal header for the Fuzzer ------*- C++ -* ===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // fuzzer::Dictionary 10 | //===----------------------------------------------------------------------===// 11 | 12 | #ifndef LLVM_FUZZER_DICTIONARY_H 13 | #define LLVM_FUZZER_DICTIONARY_H 14 | 15 | #include 16 | #include 17 | 18 | #include "FuzzerDefs.h" 19 | 20 | namespace fuzzer { 21 | // A simple POD sized array of bytes. 22 | template class FixedWord { 23 | public: 24 | FixedWord() {} 25 | FixedWord(const uint8_t *B, uint8_t S) { Set(B, S); } 26 | 27 | void Set(const uint8_t *B, uint8_t S) { 28 | assert(S <= kMaxSize); 29 | memcpy(Data, B, S); 30 | Size = S; 31 | } 32 | 33 | bool operator==(const FixedWord &w) const { 34 | return Size == w.Size && 0 == memcmp(Data, w.Data, Size); 35 | } 36 | 37 | bool operator<(const FixedWord &w) const { 38 | if (Size != w.Size) 39 | return Size < w.Size; 40 | return memcmp(Data, w.Data, Size) < 0; 41 | } 42 | 43 | static size_t GetMaxSize() { return kMaxSize; } 44 | const uint8_t *data() const { return Data; } 45 | uint8_t size() const { return Size; } 46 | 47 | private: 48 | uint8_t Size = 0; 49 | uint8_t Data[kMaxSize]; 50 | }; 51 | 52 | typedef FixedWord<27> Word; // 28 bytes. 53 | 54 | class DictionaryEntry { 55 | public: 56 | DictionaryEntry() {} 57 | DictionaryEntry(Word W) : W(W) {} 58 | DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {} 59 | const Word &GetW() const { return W; } 60 | 61 | bool HasPositionHint() const { return PositionHint != std::numeric_limits::max(); } 62 | size_t GetPositionHint() const { 63 | assert(HasPositionHint()); 64 | return PositionHint; 65 | } 66 | void IncUseCount() { UseCount++; } 67 | void IncSuccessCount() { SuccessCount++; } 68 | size_t GetUseCount() const { return UseCount; } 69 | size_t GetSuccessCount() const {return SuccessCount; } 70 | 71 | void Print(const char *PrintAfter = "\n") { 72 | PrintASCII(W.data(), W.size()); 73 | if (HasPositionHint()) 74 | Printf("@%zd", GetPositionHint()); 75 | Printf("%s", PrintAfter); 76 | } 77 | 78 | private: 79 | Word W; 80 | size_t PositionHint = std::numeric_limits::max(); 81 | size_t UseCount = 0; 82 | size_t SuccessCount = 0; 83 | }; 84 | 85 | class Dictionary { 86 | public: 87 | static const size_t kMaxDictSize = 1 << 14; 88 | 89 | bool ContainsWord(const Word &W) const { 90 | return std::any_of(begin(), end(), [&](const DictionaryEntry &DE) { 91 | return DE.GetW() == W; 92 | }); 93 | } 94 | const DictionaryEntry *begin() const { return &DE[0]; } 95 | const DictionaryEntry *end() const { return begin() + Size; } 96 | DictionaryEntry & operator[] (size_t Idx) { 97 | assert(Idx < Size); 98 | return DE[Idx]; 99 | } 100 | void push_back(DictionaryEntry DE) { 101 | if (Size < kMaxDictSize) 102 | this->DE[Size++] = DE; 103 | } 104 | void clear() { Size = 0; } 105 | bool empty() const { return Size == 0; } 106 | size_t size() const { return Size; } 107 | 108 | private: 109 | DictionaryEntry DE[kMaxDictSize]; 110 | size_t Size = 0; 111 | }; 112 | 113 | // Parses one dictionary entry. 114 | // If successfull, write the enty to Unit and returns true, 115 | // otherwise returns false. 116 | bool ParseOneDictionaryEntry(const std::string &Str, Unit *U); 117 | // Parses the dictionary file, fills Units, returns true iff all lines 118 | // were parsed succesfully. 119 | bool ParseDictionaryFile(const std::string &Text, std::vector *Units); 120 | 121 | } // namespace fuzzer 122 | 123 | #endif // LLVM_FUZZER_DICTIONARY_H 124 | 125 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerExtFunctions.def: -------------------------------------------------------------------------------- 1 | //===- FuzzerExtFunctions.def - External functions --------------*- C++ -* ===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // This defines the external function pointers that 10 | // ``fuzzer::ExternalFunctions`` should contain and try to initialize. The 11 | // EXT_FUNC macro must be defined at the point of inclusion. The signature of 12 | // the macro is: 13 | // 14 | // EXT_FUNC(, , , ) 15 | //===----------------------------------------------------------------------===// 16 | 17 | // Optional user functions 18 | EXT_FUNC(LLVMFuzzerInitialize, int, (int *argc, char ***argv), false); 19 | EXT_FUNC(LLVMFuzzerCustomMutator, size_t, 20 | (uint8_t * Data, size_t Size, size_t MaxSize, unsigned int Seed), 21 | false); 22 | EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t, 23 | (const uint8_t * Data1, size_t Size1, 24 | const uint8_t * Data2, size_t Size2, 25 | uint8_t * Out, size_t MaxOutSize, unsigned int Seed), 26 | false); 27 | 28 | // Sanitizer functions 29 | EXT_FUNC(__lsan_enable, void, (), false); 30 | EXT_FUNC(__lsan_disable, void, (), false); 31 | EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false); 32 | EXT_FUNC(__sanitizer_get_number_of_counters, size_t, (), false); 33 | EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int, 34 | (void (*malloc_hook)(const volatile void *, size_t), 35 | void (*free_hook)(const volatile void *)), 36 | false); 37 | EXT_FUNC(__sanitizer_get_total_unique_caller_callee_pairs, size_t, (), false); 38 | EXT_FUNC(__sanitizer_get_total_unique_coverage, size_t, (), true); 39 | EXT_FUNC(__sanitizer_print_memory_profile, int, (size_t), false); 40 | EXT_FUNC(__sanitizer_print_stack_trace, void, (), true); 41 | EXT_FUNC(__sanitizer_symbolize_pc, void, 42 | (void *, const char *fmt, char *out_buf, size_t out_buf_size), false); 43 | EXT_FUNC(__sanitizer_reset_coverage, void, (), true); 44 | EXT_FUNC(__sanitizer_set_death_callback, void, (void (*)(void)), true); 45 | EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false); 46 | EXT_FUNC(__sanitizer_update_counter_bitset_and_clear_counters, uintptr_t, 47 | (uint8_t*), false); 48 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerExtFunctions.h: -------------------------------------------------------------------------------- 1 | //===- FuzzerExtFunctions.h - Interface to external functions ---*- C++ -* ===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // Defines an interface to (possibly optional) functions. 10 | //===----------------------------------------------------------------------===// 11 | #ifndef LLVM_FUZZER_EXT_FUNCTIONS_H 12 | #define LLVM_FUZZER_EXT_FUNCTIONS_H 13 | 14 | #include 15 | #include 16 | 17 | namespace fuzzer { 18 | 19 | struct ExternalFunctions { 20 | // Initialize function pointers. Functions that are not available will be set 21 | // to nullptr. Do not call this constructor before ``main()`` has been 22 | // entered. 23 | ExternalFunctions(); 24 | 25 | #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ 26 | RETURN_TYPE(*NAME) FUNC_SIG = nullptr 27 | 28 | #include "FuzzerExtFunctions.def" 29 | 30 | #undef EXT_FUNC 31 | }; 32 | } // namespace fuzzer 33 | #endif 34 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerExtFunctionsDlsym.cpp: -------------------------------------------------------------------------------- 1 | //===- FuzzerExtFunctionsDlsym.cpp - Interface to external functions ------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // Implementation for operating systems that support dlsym(). We only use it on 10 | // Apple platforms for now. We don't use this approach on Linux because it 11 | // requires that clients of LibFuzzer pass ``--export-dynamic`` to the linker. 12 | // That is a complication we don't wish to expose to clients right now. 13 | //===----------------------------------------------------------------------===// 14 | #include "FuzzerDefs.h" 15 | #if LIBFUZZER_APPLE 16 | 17 | #include "FuzzerExtFunctions.h" 18 | #include 19 | 20 | using namespace fuzzer; 21 | 22 | template 23 | static T GetFnPtr(const char *FnName, bool WarnIfMissing) { 24 | dlerror(); // Clear any previous errors. 25 | void *Fn = dlsym(RTLD_DEFAULT, FnName); 26 | if (Fn == nullptr) { 27 | if (WarnIfMissing) { 28 | const char *ErrorMsg = dlerror(); 29 | Printf("WARNING: Failed to find function \"%s\".", FnName); 30 | if (ErrorMsg) 31 | Printf(" Reason %s.", ErrorMsg); 32 | Printf("\n"); 33 | } 34 | } 35 | return reinterpret_cast(Fn); 36 | } 37 | 38 | namespace fuzzer { 39 | 40 | ExternalFunctions::ExternalFunctions() { 41 | #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ 42 | this->NAME = GetFnPtr(#NAME, WARN) 43 | 44 | #include "FuzzerExtFunctions.def" 45 | 46 | #undef EXT_FUNC 47 | } 48 | } // namespace fuzzer 49 | #endif // LIBFUZZER_APPLE 50 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerExtFunctionsWeak.cpp: -------------------------------------------------------------------------------- 1 | //===- FuzzerExtFunctionsWeak.cpp - Interface to external functions -------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // Implementation for Linux. This relies on the linker's support for weak 10 | // symbols. We don't use this approach on Apple platforms because it requires 11 | // clients of LibFuzzer to pass ``-U _`` to the linker to allow 12 | // weak symbols to be undefined. That is a complication we don't want to expose 13 | // to clients right now. 14 | //===----------------------------------------------------------------------===// 15 | #include "FuzzerDefs.h" 16 | #if LIBFUZZER_LINUX 17 | 18 | #include "FuzzerExtFunctions.h" 19 | 20 | extern "C" { 21 | // Declare these symbols as weak to allow them to be optionally defined. 22 | #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ 23 | __attribute__((weak)) RETURN_TYPE NAME FUNC_SIG 24 | 25 | #include "FuzzerExtFunctions.def" 26 | 27 | #undef EXT_FUNC 28 | } 29 | 30 | using namespace fuzzer; 31 | 32 | static void CheckFnPtr(void *FnPtr, const char *FnName, bool WarnIfMissing) { 33 | if (FnPtr == nullptr && WarnIfMissing) { 34 | Printf("WARNING: Failed to find function \"%s\".\n", FnName); 35 | } 36 | } 37 | 38 | namespace fuzzer { 39 | 40 | ExternalFunctions::ExternalFunctions() { 41 | #define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ 42 | this->NAME = ::NAME; \ 43 | CheckFnPtr((void *)::NAME, #NAME, WARN); 44 | 45 | #include "FuzzerExtFunctions.def" 46 | 47 | #undef EXT_FUNC 48 | } 49 | } // namespace fuzzer 50 | #endif // LIBFUZZER_LINUX 51 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerFlags.def: -------------------------------------------------------------------------------- 1 | //===- FuzzerFlags.def - Run-time flags -------------------------*- C++ -* ===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // Flags. FUZZER_FLAG_INT/FUZZER_FLAG_STRING macros should be defined at the 10 | // point of inclusion. We are not using any flag parsing library for better 11 | // portability and independence. 12 | //===----------------------------------------------------------------------===// 13 | FUZZER_FLAG_INT(verbosity, 1, "Verbosity level.") 14 | FUZZER_FLAG_UNSIGNED(seed, 0, "Random seed. If 0, seed is generated.") 15 | FUZZER_FLAG_INT(runs, -1, 16 | "Number of individual test runs (-1 for infinite runs).") 17 | FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. " 18 | "If 0, libFuzzer tries to guess a good value based on the corpus " 19 | "and reports it. ") 20 | FUZZER_FLAG_INT(cross_over, 1, "If 1, cross over inputs.") 21 | FUZZER_FLAG_INT(mutate_depth, 5, 22 | "Apply this number of consecutive mutations to each input.") 23 | FUZZER_FLAG_INT(shuffle, 1, "Shuffle inputs at startup") 24 | FUZZER_FLAG_INT(prefer_small, 1, 25 | "If 1, always prefer smaller inputs during the corpus shuffle.") 26 | FUZZER_FLAG_INT( 27 | timeout, 1200, 28 | "Timeout in seconds (if positive). " 29 | "If one unit runs more than this number of seconds the process will abort.") 30 | FUZZER_FLAG_INT(timeout_exitcode, 77, 31 | "Unless abort_on_timeout is set, use this exitcode on timeout.") 32 | FUZZER_FLAG_INT(error_exit_code, 77, "When libFuzzer's signal handlers are in " 33 | "use exit with this exitcode after catching a deadly signal.") 34 | FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total " 35 | "time in seconds to run the fuzzer.") 36 | FUZZER_FLAG_INT(help, 0, "Print help.") 37 | FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be " 38 | "merged into the 1-st corpus. Only interesting units will be taken. " 39 | "This flag can be used to minimize a corpus.") 40 | FUZZER_FLAG_INT(minimize_crash, 0, "If 1, minimizes the provided" 41 | " crash input. Use with -runs=N or -max_total_time=N to limit " 42 | "the number attempts") 43 | FUZZER_FLAG_INT(minimize_crash_internal_step, 0, "internal flag") 44 | FUZZER_FLAG_INT(use_counters, 1, "Use coverage counters") 45 | FUZZER_FLAG_INT(use_indir_calls, 1, "Use indirect caller-callee counters") 46 | FUZZER_FLAG_INT(use_memcmp, 1, 47 | "Use hints from intercepting memcmp, strcmp, etc") 48 | FUZZER_FLAG_INT(use_memmem, 1, 49 | "Use hints from intercepting memmem, strstr, etc") 50 | FUZZER_FLAG_INT(use_value_profile, 0, 51 | "Experimental. Use value profile to guide fuzzing.") 52 | FUZZER_FLAG_INT(use_cmp, 0, "Experimenta. Use CMP traces to guide mutations") 53 | FUZZER_FLAG_INT(shrink, 0, "Experimental. Try to shrink corpus elements.") 54 | FUZZER_FLAG_INT(jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn" 55 | " this number of jobs in separate worker processes" 56 | " with stdout/stderr redirected to fuzz-JOB.log.") 57 | FUZZER_FLAG_INT(workers, 0, 58 | "Number of simultaneous worker processes to run the jobs." 59 | " If zero, \"min(jobs,NumberOfCpuCores()/2)\" is used.") 60 | FUZZER_FLAG_INT(reload, 1, 61 | "Reload the main corpus every seconds to get new units" 62 | " discovered by other processes. If 0, disabled") 63 | FUZZER_FLAG_INT(report_slow_units, 10, 64 | "Report slowest units if they run for more than this number of seconds.") 65 | FUZZER_FLAG_INT(only_ascii, 0, 66 | "If 1, generate only ASCII (isprint+isspace) inputs.") 67 | FUZZER_FLAG_STRING(dict, "Experimental. Use the dictionary file.") 68 | FUZZER_FLAG_STRING(artifact_prefix, "Write fuzzing artifacts (crash, " 69 | "timeout, or slow inputs) as " 70 | "$(artifact_prefix)file") 71 | FUZZER_FLAG_STRING(exact_artifact_path, 72 | "Write the single artifact on failure (crash, timeout) " 73 | "as $(exact_artifact_path). This overrides -artifact_prefix " 74 | "and will not use checksum in the file name. Do not " 75 | "use the same path for several parallel processes.") 76 | FUZZER_FLAG_INT(output_csv, 0, "Enable pulse output in CSV format.") 77 | FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.") 78 | FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.") 79 | FUZZER_FLAG_INT(print_corpus_stats, 0, 80 | "If 1, print statistics on corpus elements at exit.") 81 | FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information at exit." 82 | " Experimental, only with trace-pc-guard") 83 | FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.") 84 | FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGSEGV.") 85 | FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.") 86 | FUZZER_FLAG_INT(handle_ill, 1, "If 1, try to intercept SIGILL.") 87 | FUZZER_FLAG_INT(handle_fpe, 1, "If 1, try to intercept SIGFPE.") 88 | FUZZER_FLAG_INT(handle_int, 1, "If 1, try to intercept SIGINT.") 89 | FUZZER_FLAG_INT(handle_term, 1, "If 1, try to intercept SIGTERM.") 90 | FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; " 91 | "if 2, close stderr; if 3, close both. " 92 | "Be careful, this will also close e.g. asan's stderr/stdout.") 93 | FUZZER_FLAG_INT(detect_leaks, 1, "If 1, and if LeakSanitizer is enabled " 94 | "try to detect memory leaks during fuzzing (i.e. not only at shut down).") 95 | FUZZER_FLAG_INT(trace_malloc, 0, "If >= 1 will print all mallocs/frees. " 96 | "If >= 2 will also print stack traces.") 97 | FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon" 98 | "reaching this limit of RSS memory usage.") 99 | FUZZER_FLAG_STRING(exit_on_src_pos, "Exit if a newly found PC originates" 100 | " from the given source location. Example: -exit_on_src_pos=foo.cc:123. " 101 | "Used primarily for testing libFuzzer itself.") 102 | FUZZER_FLAG_STRING(exit_on_item, "Exit if an item with a given sha1 sum" 103 | " was added to the corpus. " 104 | "Used primarily for testing libFuzzer itself.") 105 | 106 | FUZZER_DEPRECATED_FLAG(exit_on_first) 107 | FUZZER_DEPRECATED_FLAG(save_minimized_corpus) 108 | FUZZER_DEPRECATED_FLAG(sync_command) 109 | FUZZER_DEPRECATED_FLAG(sync_timeout) 110 | FUZZER_DEPRECATED_FLAG(test_single_input) 111 | FUZZER_DEPRECATED_FLAG(drill) 112 | FUZZER_DEPRECATED_FLAG(truncate_units) 113 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerFnAdapter.h: -------------------------------------------------------------------------------- 1 | //===- FuzzerAdapter.h - Arbitrary function Fuzzer adapter -------*- C++ -*===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // W A R N I N G : E X P E R I M E N T A L. 11 | // 12 | // Defines an adapter to fuzz functions with (almost) arbitrary signatures. 13 | //===----------------------------------------------------------------------===// 14 | 15 | #ifndef LLVM_FUZZER_ADAPTER_H 16 | #define LLVM_FUZZER_ADAPTER_H 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace fuzzer { 27 | 28 | /// Unpacks bytes from \p Data according to \p F argument types 29 | /// and calls the function. 30 | /// Use to automatically adapt LLVMFuzzerTestOneInput interface to 31 | /// a specific function. 32 | /// Supported argument types: primitive types, std::vector. 33 | template bool Adapt(Fn F, const uint8_t *Data, size_t Size); 34 | 35 | // The implementation performs several steps: 36 | // - function argument types are obtained (Args...) 37 | // - data is unpacked into std::tuple one by one 38 | // - function is called with std::tuple containing arguments. 39 | namespace impl { 40 | 41 | // Single argument unpacking. 42 | 43 | template 44 | size_t UnpackPrimitive(const uint8_t *Data, size_t Size, T *Value) { 45 | if (Size < sizeof(T)) 46 | return Size; 47 | *Value = *reinterpret_cast(Data); 48 | return Size - sizeof(T); 49 | } 50 | 51 | /// Unpacks into a given Value and returns the Size - num_consumed_bytes. 52 | /// Return value equal to Size signals inability to unpack the data (typically 53 | /// because there are not enough bytes). 54 | template 55 | size_t UnpackSingle(const uint8_t *Data, size_t Size, T *Value); 56 | 57 | #define UNPACK_SINGLE_PRIMITIVE(Type) \ 58 | template <> \ 59 | size_t UnpackSingle(const uint8_t *Data, size_t Size, Type *Value) { \ 60 | return UnpackPrimitive(Data, Size, Value); \ 61 | } 62 | 63 | UNPACK_SINGLE_PRIMITIVE(char) 64 | UNPACK_SINGLE_PRIMITIVE(signed char) 65 | UNPACK_SINGLE_PRIMITIVE(unsigned char) 66 | 67 | UNPACK_SINGLE_PRIMITIVE(short int) 68 | UNPACK_SINGLE_PRIMITIVE(unsigned short int) 69 | 70 | UNPACK_SINGLE_PRIMITIVE(int) 71 | UNPACK_SINGLE_PRIMITIVE(unsigned int) 72 | 73 | UNPACK_SINGLE_PRIMITIVE(long int) 74 | UNPACK_SINGLE_PRIMITIVE(unsigned long int) 75 | 76 | UNPACK_SINGLE_PRIMITIVE(bool) 77 | UNPACK_SINGLE_PRIMITIVE(wchar_t) 78 | 79 | UNPACK_SINGLE_PRIMITIVE(float) 80 | UNPACK_SINGLE_PRIMITIVE(double) 81 | UNPACK_SINGLE_PRIMITIVE(long double) 82 | 83 | #undef UNPACK_SINGLE_PRIMITIVE 84 | 85 | template <> 86 | size_t UnpackSingle>(const uint8_t *Data, size_t Size, 87 | std::vector *Value) { 88 | if (Size < 1) 89 | return Size; 90 | size_t Len = std::min(static_cast(*Data), Size - 1); 91 | std::vector V(Data + 1, Data + 1 + Len); 92 | Value->swap(V); 93 | return Size - Len - 1; 94 | } 95 | 96 | template <> 97 | size_t UnpackSingle(const uint8_t *Data, size_t Size, 98 | std::string *Value) { 99 | if (Size < 1) 100 | return Size; 101 | size_t Len = std::min(static_cast(*Data), Size - 1); 102 | std::string S(Data + 1, Data + 1 + Len); 103 | Value->swap(S); 104 | return Size - Len - 1; 105 | } 106 | 107 | // Unpacking into arbitrary tuple. 108 | 109 | // Recursion guard. 110 | template 111 | typename std::enable_if::value, bool>::type 112 | UnpackImpl(const uint8_t *Data, size_t Size, TupleT *Tuple) { 113 | return true; 114 | } 115 | 116 | // Unpack tuple elements starting from Nth. 117 | template 118 | typename std::enable_if::value, bool>::type 119 | UnpackImpl(const uint8_t *Data, size_t Size, TupleT *Tuple) { 120 | size_t NewSize = UnpackSingle(Data, Size, &std::get(*Tuple)); 121 | if (NewSize == Size) { 122 | return false; 123 | } 124 | 125 | return UnpackImpl(Data + (Size - NewSize), NewSize, Tuple); 126 | } 127 | 128 | // Unpacks into arbitrary tuple and returns true if successful. 129 | template 130 | bool Unpack(const uint8_t *Data, size_t Size, std::tuple *Tuple) { 131 | return UnpackImpl<0, std::tuple>(Data, Size, Tuple); 132 | } 133 | 134 | // Helper integer sequence templates. 135 | 136 | template struct Seq {}; 137 | 138 | template struct GenSeq : GenSeq {}; 139 | 140 | // GenSeq::type is Seq<0, 1, ..., N-1> 141 | template struct GenSeq<0, S...> { typedef Seq type; }; 142 | 143 | // Function signature introspection. 144 | 145 | template struct FnTraits {}; 146 | 147 | template 148 | struct FnTraits { 149 | enum { Arity = sizeof...(Args) }; 150 | typedef std::tuple ArgsTupleT; 151 | }; 152 | 153 | // Calling a function with arguments in a tuple. 154 | 155 | template 156 | void ApplyImpl(Fn F, const typename FnTraits::ArgsTupleT &Params, 157 | Seq) { 158 | F(std::get(Params)...); 159 | } 160 | 161 | template 162 | void Apply(Fn F, const typename FnTraits::ArgsTupleT &Params) { 163 | // S is Seq<0, ..., Arity-1> 164 | auto S = typename GenSeq::Arity>::type(); 165 | ApplyImpl(F, Params, S); 166 | } 167 | 168 | // Unpacking data into arguments tuple of correct type and calling the function. 169 | template 170 | bool UnpackAndApply(Fn F, const uint8_t *Data, size_t Size) { 171 | typename FnTraits::ArgsTupleT Tuple; 172 | if (!Unpack(Data, Size, &Tuple)) 173 | return false; 174 | 175 | Apply(F, Tuple); 176 | return true; 177 | } 178 | 179 | } // namespace impl 180 | 181 | template bool Adapt(Fn F, const uint8_t *Data, size_t Size) { 182 | return impl::UnpackAndApply(F, Data, Size); 183 | } 184 | 185 | } // namespace fuzzer 186 | 187 | #endif 188 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerIO.cpp: -------------------------------------------------------------------------------- 1 | //===- FuzzerIO.cpp - IO utils. -------------------------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // IO functions. 10 | //===----------------------------------------------------------------------===// 11 | #include "FuzzerExtFunctions.h" 12 | #include "FuzzerDefs.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | namespace fuzzer { 23 | 24 | static FILE *OutputFile = stderr; 25 | 26 | bool IsFile(const std::string &Path) { 27 | struct stat St; 28 | if (stat(Path.c_str(), &St)) 29 | return false; 30 | return S_ISREG(St.st_mode); 31 | } 32 | 33 | long GetEpoch(const std::string &Path) { 34 | struct stat St; 35 | if (stat(Path.c_str(), &St)) 36 | return 0; // Can't stat, be conservative. 37 | return St.st_mtime; 38 | } 39 | 40 | static void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, 41 | std::vector *V, bool TopDir) { 42 | auto E = GetEpoch(Dir); 43 | if (Epoch) 44 | if (E && *Epoch >= E) return; 45 | 46 | DIR *D = opendir(Dir.c_str()); 47 | if (!D) { 48 | Printf("No such directory: %s; exiting\n", Dir.c_str()); 49 | return; 50 | // exit(1); 51 | } 52 | while (auto E = readdir(D)) { 53 | std::string Path = DirPlusFile(Dir, E->d_name); 54 | if (E->d_type == DT_REG || E->d_type == DT_LNK) 55 | V->push_back(Path); 56 | else if (E->d_type == DT_DIR && *E->d_name != '.') 57 | ListFilesInDirRecursive(Path, Epoch, V, false); 58 | } 59 | closedir(D); 60 | if (Epoch && TopDir) 61 | *Epoch = E; 62 | } 63 | 64 | Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) { 65 | std::ifstream T(Path); 66 | if (ExitOnError && !T) { 67 | Printf("No such directory: %s; exiting\n", Path.c_str()); 68 | return Unit(0); 69 | // exit(1); 70 | } 71 | 72 | T.seekg(0, T.end); 73 | size_t FileLen = T.tellg(); 74 | if (MaxSize) 75 | FileLen = std::min(FileLen, MaxSize); 76 | 77 | T.seekg(0, T.beg); 78 | Unit Res(FileLen); 79 | T.read(reinterpret_cast(Res.data()), FileLen); 80 | return Res; 81 | } 82 | 83 | void DeleteFile(const std::string &Path) { 84 | unlink(Path.c_str()); 85 | } 86 | 87 | std::string FileToString(const std::string &Path) { 88 | std::ifstream T(Path); 89 | return std::string((std::istreambuf_iterator(T)), 90 | std::istreambuf_iterator()); 91 | } 92 | 93 | void CopyFileToErr(const std::string &Path) { 94 | Printf("%s", FileToString(Path).c_str()); 95 | } 96 | 97 | void WriteToFile(const Unit &U, const std::string &Path) { 98 | // Use raw C interface because this function may be called from a sig handler. 99 | FILE *Out = fopen(Path.c_str(), "w"); 100 | if (!Out) return; 101 | fwrite(U.data(), sizeof(U[0]), U.size(), Out); 102 | fclose(Out); 103 | } 104 | 105 | void ReadDirToVectorOfUnits(const char *Path, std::vector *V, 106 | long *Epoch, size_t MaxSize, bool ExitOnError) { 107 | long E = Epoch ? *Epoch : 0; 108 | std::vector Files; 109 | ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true); 110 | size_t NumLoaded = 0; 111 | for (size_t i = 0; i < Files.size(); i++) { 112 | auto &X = Files[i]; 113 | if (Epoch && GetEpoch(X) < E) continue; 114 | NumLoaded++; 115 | if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024) 116 | Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path); 117 | auto S = FileToVector(X, MaxSize, ExitOnError); 118 | if (!S.empty()) 119 | V->push_back(S); 120 | } 121 | } 122 | 123 | std::string DirPlusFile(const std::string &DirPath, 124 | const std::string &FileName) { 125 | return DirPath + "/" + FileName; 126 | } 127 | 128 | void DupAndCloseStderr() { 129 | int OutputFd = dup(2); 130 | if (OutputFd > 0) { 131 | FILE *NewOutputFile = fdopen(OutputFd, "w"); 132 | if (NewOutputFile) { 133 | OutputFile = NewOutputFile; 134 | if (EF->__sanitizer_set_report_fd) 135 | EF->__sanitizer_set_report_fd(reinterpret_cast(OutputFd)); 136 | close(2); 137 | } 138 | } 139 | } 140 | 141 | void CloseStdout() { close(1); } 142 | 143 | void Printf(const char *Fmt, ...) { 144 | va_list ap; 145 | va_start(ap, Fmt); 146 | vfprintf(OutputFile, Fmt, ap); 147 | va_end(ap); 148 | fflush(OutputFile); 149 | } 150 | 151 | } // namespace fuzzer 152 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerInterface.h: -------------------------------------------------------------------------------- 1 | //===- FuzzerInterface.h - Interface header for the Fuzzer ------*- C++ -* ===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // Define the interface between libFuzzer and the library being tested. 10 | //===----------------------------------------------------------------------===// 11 | 12 | // NOTE: the libFuzzer interface is thin and in the majority of cases 13 | // you should not include this file into your target. In 95% of cases 14 | // all you need is to define the following function in your file: 15 | // extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); 16 | 17 | // WARNING: keep the interface in C. 18 | 19 | #ifndef LLVM_FUZZER_INTERFACE_H 20 | #define LLVM_FUZZER_INTERFACE_H 21 | 22 | #include 23 | #include 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif // __cplusplus 28 | 29 | // Mandatory user-provided target function. 30 | // Executes the code under test with [Data, Data+Size) as the input. 31 | // libFuzzer will invoke this function *many* times with different inputs. 32 | // Must return 0. 33 | int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); 34 | 35 | // Optional user-provided initialization function. 36 | // If provided, this function will be called by libFuzzer once at startup. 37 | // It may read and modify argc/argv. 38 | // Must return 0. 39 | int LLVMFuzzerInitialize(int *argc, char ***argv); 40 | 41 | // Optional user-provided custom mutator. 42 | // Mutates raw data in [Data, Data+Size) inplace. 43 | // Returns the new size, which is not greater than MaxSize. 44 | // Given the same Seed produces the same mutation. 45 | size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, 46 | unsigned int Seed); 47 | 48 | // Optional user-provided custom cross-over function. 49 | // Combines pieces of Data1 & Data2 together into Out. 50 | // Returns the new size, which is not greater than MaxOutSize. 51 | // Should produce the same mutation given the same Seed. 52 | size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, 53 | const uint8_t *Data2, size_t Size2, 54 | uint8_t *Out, size_t MaxOutSize, 55 | unsigned int Seed); 56 | 57 | // Experimental, may go away in future. 58 | // libFuzzer-provided function to be used inside LLVMFuzzerTestOneInput. 59 | // Mutates raw data in [Data, Data+Size) inplace. 60 | // Returns the new size, which is not greater than MaxSize. 61 | size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); 62 | 63 | #ifdef __cplusplus 64 | } // extern "C" 65 | #endif // __cplusplus 66 | 67 | #endif // LLVM_FUZZER_INTERFACE_H 68 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerInternal.h: -------------------------------------------------------------------------------- 1 | //===- FuzzerInternal.h - Internal header for the Fuzzer --------*- C++ -* ===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // Define the main class fuzzer::Fuzzer and most functions. 10 | //===----------------------------------------------------------------------===// 11 | 12 | #ifndef LLVM_FUZZER_INTERNAL_H 13 | #define LLVM_FUZZER_INTERNAL_H 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "FuzzerDefs.h" 23 | #include "FuzzerExtFunctions.h" 24 | #include "FuzzerInterface.h" 25 | #include "FuzzerOptions.h" 26 | #include "FuzzerValueBitMap.h" 27 | 28 | namespace fuzzer { 29 | 30 | using namespace std::chrono; 31 | 32 | class Fuzzer { 33 | public: 34 | 35 | // Aggregates all available coverage measurements. 36 | struct Coverage { 37 | Coverage() { Reset(); } 38 | 39 | void Reset() { 40 | BlockCoverage = 0; 41 | CallerCalleeCoverage = 0; 42 | CounterBitmapBits = 0; 43 | CounterBitmap.clear(); 44 | VPMap.Reset(); 45 | } 46 | 47 | size_t BlockCoverage; 48 | size_t CallerCalleeCoverage; 49 | // Precalculated number of bits in CounterBitmap. 50 | size_t CounterBitmapBits; 51 | std::vector CounterBitmap; 52 | ValueBitMap VPMap; 53 | }; 54 | 55 | Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, 56 | FuzzingOptions Options); 57 | ~Fuzzer(); 58 | void Loop(); 59 | void MinimizeCrashLoop(const Unit &U); 60 | void ShuffleAndMinimize(UnitVector *V); 61 | void InitializeTraceState(); 62 | void RereadOutputCorpus(size_t MaxSize); 63 | 64 | size_t secondsSinceProcessStartUp() { 65 | return duration_cast(system_clock::now() - ProcessStartTime) 66 | .count(); 67 | } 68 | 69 | bool TimedOut() { 70 | return Options.MaxTotalTimeSec > 0 && 71 | secondsSinceProcessStartUp() > 72 | static_cast(Options.MaxTotalTimeSec); 73 | } 74 | 75 | size_t execPerSec() { 76 | size_t Seconds = secondsSinceProcessStartUp(); 77 | return Seconds ? TotalNumberOfRuns / Seconds : 0; 78 | } 79 | 80 | size_t getTotalNumberOfRuns() { return TotalNumberOfRuns; } 81 | 82 | static void StaticAlarmCallback(); 83 | static void StaticCrashSignalCallback(); 84 | static void StaticInterruptCallback(); 85 | 86 | void ExecuteCallback(const uint8_t *Data, size_t Size); 87 | size_t RunOne(const uint8_t *Data, size_t Size); 88 | 89 | // Merge Corpora[1:] into Corpora[0]. 90 | void Merge(const std::vector &Corpora); 91 | // Returns a subset of 'Extra' that adds coverage to 'Initial'. 92 | UnitVector FindExtraUnits(const UnitVector &Initial, const UnitVector &Extra); 93 | MutationDispatcher &GetMD() { return MD; } 94 | void PrintFinalStats(); 95 | void SetMaxInputLen(size_t MaxInputLen); 96 | void SetMaxMutationLen(size_t MaxMutationLen); 97 | void RssLimitCallback(); 98 | 99 | // Public for tests. 100 | void ResetCoverage(); 101 | 102 | bool InFuzzingThread() const { return IsMyThread; } 103 | size_t GetCurrentUnitInFuzzingThead(const uint8_t **Data) const; 104 | void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, 105 | bool DuringInitialCorpusExecution); 106 | 107 | private: 108 | void AlarmCallback(); 109 | void CrashCallback(); 110 | void InterruptCallback(); 111 | void MutateAndTestOne(); 112 | void ReportNewCoverage(InputInfo *II, const Unit &U); 113 | size_t RunOne(const Unit &U) { return RunOne(U.data(), U.size()); } 114 | void WriteToOutputCorpus(const Unit &U); 115 | void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix); 116 | void PrintStats(const char *Where, const char *End = "\n", size_t Units = 0); 117 | void PrintStatusForNewUnit(const Unit &U); 118 | void ShuffleCorpus(UnitVector *V); 119 | void AddToCorpus(const Unit &U); 120 | void CheckExitOnSrcPosOrItem(); 121 | 122 | // Trace-based fuzzing: we run a unit with some kind of tracing 123 | // enabled and record potentially useful mutations. Then 124 | // We apply these mutations one by one to the unit and run it again. 125 | 126 | // Start tracing; forget all previously proposed mutations. 127 | void StartTraceRecording(); 128 | // Stop tracing. 129 | void StopTraceRecording(); 130 | 131 | void SetDeathCallback(); 132 | static void StaticDeathCallback(); 133 | void DumpCurrentUnit(const char *Prefix); 134 | void DeathCallback(); 135 | 136 | void ResetEdgeCoverage(); 137 | void ResetCounters(); 138 | void PrepareCounters(Fuzzer::Coverage *C); 139 | bool RecordMaxCoverage(Fuzzer::Coverage *C); 140 | 141 | void AllocateCurrentUnitData(); 142 | uint8_t *CurrentUnitData = nullptr; 143 | std::atomic CurrentUnitSize; 144 | uint8_t BaseSha1[kSHA1NumBytes]; // Checksum of the base unit. 145 | 146 | size_t TotalNumberOfRuns = 0; 147 | size_t NumberOfNewUnitsAdded = 0; 148 | 149 | bool HasMoreMallocsThanFrees = false; 150 | size_t NumberOfLeakDetectionAttempts = 0; 151 | 152 | UserCallback CB; 153 | InputCorpus &Corpus; 154 | MutationDispatcher &MD; 155 | FuzzingOptions Options; 156 | 157 | system_clock::time_point ProcessStartTime = system_clock::now(); 158 | system_clock::time_point UnitStartTime, UnitStopTime; 159 | long TimeOfLongestUnitInSeconds = 0; 160 | long EpochOfLastReadOfOutputCorpus = 0; 161 | 162 | // Maximum recorded coverage. 163 | Coverage MaxCoverage; 164 | 165 | size_t MaxInputLen = 0; 166 | size_t MaxMutationLen = 0; 167 | 168 | // Need to know our own thread. 169 | static thread_local bool IsMyThread; 170 | 171 | bool InMergeMode = false; 172 | }; 173 | 174 | }; // namespace fuzzer 175 | 176 | #endif // LLVM_FUZZER_INTERNAL_H 177 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerMain.cpp: -------------------------------------------------------------------------------- 1 | //===- FuzzerMain.cpp - main() function and flags -------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // main() and flags. 10 | //===----------------------------------------------------------------------===// 11 | 12 | #include "FuzzerDefs.h" 13 | 14 | extern "C" { 15 | // This function should be defined by the user. 16 | int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); 17 | } // extern "C" 18 | 19 | int main(int argc, char **argv) { 20 | return fuzzer::FuzzerDriver(&argc, &argv, LLVMFuzzerTestOneInput); 21 | } 22 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerMutate.h: -------------------------------------------------------------------------------- 1 | //===- FuzzerMutate.h - Internal header for the Fuzzer ----------*- C++ -* ===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // fuzzer::MutationDispatcher 10 | //===----------------------------------------------------------------------===// 11 | 12 | #ifndef LLVM_FUZZER_MUTATE_H 13 | #define LLVM_FUZZER_MUTATE_H 14 | 15 | #include "FuzzerDefs.h" 16 | #include "FuzzerDictionary.h" 17 | #include "FuzzerRandom.h" 18 | 19 | namespace fuzzer { 20 | 21 | class MutationDispatcher { 22 | public: 23 | MutationDispatcher(Random &Rand, const FuzzingOptions &Options); 24 | ~MutationDispatcher() {} 25 | /// Indicate that we are about to start a new sequence of mutations. 26 | void StartMutationSequence(); 27 | /// Print the current sequence of mutations. 28 | void PrintMutationSequence(); 29 | /// Indicate that the current sequence of mutations was successfull. 30 | void RecordSuccessfulMutationSequence(); 31 | /// Mutates data by invoking user-provided mutator. 32 | size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize); 33 | /// Mutates data by invoking user-provided crossover. 34 | size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize); 35 | /// Mutates data by shuffling bytes. 36 | size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize); 37 | /// Mutates data by erasing bytes. 38 | size_t Mutate_EraseBytes(uint8_t *Data, size_t Size, size_t MaxSize); 39 | /// Mutates data by inserting a byte. 40 | size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize); 41 | /// Mutates data by inserting several repeated bytes. 42 | size_t Mutate_InsertRepeatedBytes(uint8_t *Data, size_t Size, size_t MaxSize); 43 | /// Mutates data by chanding one byte. 44 | size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize); 45 | /// Mutates data by chanding one bit. 46 | size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize); 47 | /// Mutates data by copying/inserting a part of data into a different place. 48 | size_t Mutate_CopyPart(uint8_t *Data, size_t Size, size_t MaxSize); 49 | 50 | /// Mutates data by adding a word from the manual dictionary. 51 | size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size, 52 | size_t MaxSize); 53 | 54 | /// Mutates data by adding a word from the temporary automatic dictionary. 55 | size_t Mutate_AddWordFromTemporaryAutoDictionary(uint8_t *Data, size_t Size, 56 | size_t MaxSize); 57 | 58 | /// Mutates data by adding a word from the TORC. 59 | size_t Mutate_AddWordFromTORC(uint8_t *Data, size_t Size, size_t MaxSize); 60 | 61 | /// Mutates data by adding a word from the persistent automatic dictionary. 62 | size_t Mutate_AddWordFromPersistentAutoDictionary(uint8_t *Data, size_t Size, 63 | size_t MaxSize); 64 | 65 | /// Tries to find an ASCII integer in Data, changes it to another ASCII int. 66 | size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize); 67 | /// Change a 1-, 2-, 4-, or 8-byte integer in interesting ways. 68 | size_t Mutate_ChangeBinaryInteger(uint8_t *Data, size_t Size, size_t MaxSize); 69 | 70 | /// CrossOver Data with some other element of the corpus. 71 | size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize); 72 | 73 | /// Applies one of the configured mutations. 74 | /// Returns the new size of data which could be up to MaxSize. 75 | size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize); 76 | /// Applies one of the default mutations. Provided as a service 77 | /// to mutation authors. 78 | size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize); 79 | 80 | /// Creates a cross-over of two pieces of Data, returns its size. 81 | size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, 82 | size_t Size2, uint8_t *Out, size_t MaxOutSize); 83 | 84 | void AddWordToManualDictionary(const Word &W); 85 | 86 | void AddWordToAutoDictionary(DictionaryEntry DE); 87 | void ClearAutoDictionary(); 88 | void PrintRecommendedDictionary(); 89 | 90 | void SetCorpus(const InputCorpus *Corpus) { this->Corpus = Corpus; } 91 | 92 | Random &GetRand() { return Rand; } 93 | 94 | private: 95 | 96 | struct Mutator { 97 | size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max); 98 | const char *Name; 99 | }; 100 | 101 | size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, 102 | size_t MaxSize); 103 | size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, 104 | const std::vector &Mutators); 105 | 106 | size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To, 107 | size_t ToSize, size_t MaxToSize); 108 | size_t CopyPartOf(const uint8_t *From, size_t FromSize, uint8_t *To, 109 | size_t ToSize); 110 | size_t ApplyDictionaryEntry(uint8_t *Data, size_t Size, size_t MaxSize, 111 | DictionaryEntry &DE); 112 | 113 | template 114 | DictionaryEntry MakeDictionaryEntryFromCMP(T Arg1, T Arg2, 115 | const uint8_t *Data, size_t Size); 116 | 117 | Random &Rand; 118 | const FuzzingOptions &Options; 119 | 120 | // Dictionary provided by the user via -dict=DICT_FILE. 121 | Dictionary ManualDictionary; 122 | // Temporary dictionary modified by the fuzzer itself, 123 | // recreated periodically. 124 | Dictionary TempAutoDictionary; 125 | // Persistent dictionary modified by the fuzzer, consists of 126 | // entries that led to successfull discoveries in the past mutations. 127 | Dictionary PersistentAutoDictionary; 128 | 129 | std::vector CurrentMutatorSequence; 130 | std::vector CurrentDictionaryEntrySequence; 131 | 132 | static const size_t kCmpDictionaryEntriesDequeSize = 16; 133 | DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize]; 134 | size_t CmpDictionaryEntriesDequeIdx = 0; 135 | 136 | const InputCorpus *Corpus = nullptr; 137 | std::vector MutateInPlaceHere; 138 | 139 | std::vector Mutators; 140 | std::vector DefaultMutators; 141 | }; 142 | 143 | } // namespace fuzzer 144 | 145 | #endif // LLVM_FUZZER_MUTATE_H 146 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerOptions.h: -------------------------------------------------------------------------------- 1 | //===- FuzzerOptions.h - Internal header for the Fuzzer ---------*- C++ -* ===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // fuzzer::FuzzingOptions 10 | //===----------------------------------------------------------------------===// 11 | 12 | #ifndef LLVM_FUZZER_OPTIONS_H 13 | #define LLVM_FUZZER_OPTIONS_H 14 | 15 | #include "FuzzerDefs.h" 16 | 17 | namespace fuzzer { 18 | 19 | struct FuzzingOptions { 20 | int Verbosity = 1; 21 | size_t MaxLen = 0; 22 | int UnitTimeoutSec = 300; 23 | int TimeoutExitCode = 77; 24 | int ErrorExitCode = 77; 25 | int MaxTotalTimeSec = 0; 26 | int RssLimitMb = 0; 27 | bool DoCrossOver = true; 28 | int MutateDepth = 5; 29 | bool UseCounters = false; 30 | bool UseIndirCalls = true; 31 | bool UseMemcmp = true; 32 | bool UseMemmem = true; 33 | bool UseCmp = false; 34 | bool UseValueProfile = false; 35 | bool Shrink = false; 36 | int ReloadIntervalSec = 1; 37 | bool ShuffleAtStartUp = true; 38 | bool PreferSmall = true; 39 | size_t MaxNumberOfRuns = -1L; 40 | int ReportSlowUnits = 10; 41 | bool OnlyASCII = false; 42 | std::string OutputCorpus; 43 | std::string ArtifactPrefix = "./"; 44 | std::string ExactArtifactPath; 45 | std::string ExitOnSrcPos; 46 | std::string ExitOnItem; 47 | bool SaveArtifacts = true; 48 | bool PrintNEW = true; // Print a status line when new units are found; 49 | bool OutputCSV = false; 50 | bool PrintNewCovPcs = false; 51 | bool PrintFinalStats = false; 52 | bool PrintCorpusStats = false; 53 | bool PrintCoverage = false; 54 | bool DetectLeaks = true; 55 | int TraceMalloc = 0; 56 | }; 57 | 58 | } // namespace fuzzer 59 | 60 | #endif // LLVM_FUZZER_OPTIONS_H 61 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerRandom.h: -------------------------------------------------------------------------------- 1 | //===- FuzzerRandom.h - Internal header for the Fuzzer ----------*- C++ -* ===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // fuzzer::Random 10 | //===----------------------------------------------------------------------===// 11 | 12 | #ifndef LLVM_FUZZER_RANDOM_H 13 | #define LLVM_FUZZER_RANDOM_H 14 | 15 | #include 16 | 17 | namespace fuzzer { 18 | class Random { 19 | public: 20 | Random(unsigned int seed) : R(seed) {} 21 | size_t Rand() { return R(); } 22 | size_t RandBool() { return Rand() % 2; } 23 | size_t operator()(size_t n) { return n ? Rand() % n : 0; } 24 | intptr_t operator()(intptr_t From, intptr_t To) { 25 | assert(From < To); 26 | intptr_t RangeSize = To - From + 1; 27 | return operator()(RangeSize) + From; 28 | } 29 | std::mt19937 &Get_mt19937() { return R; } 30 | private: 31 | std::mt19937 R; 32 | }; 33 | 34 | } // namespace fuzzer 35 | 36 | #endif // LLVM_FUZZER_RANDOM_H 37 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerSHA1.cpp: -------------------------------------------------------------------------------- 1 | //===- FuzzerSHA1.h - Private copy of the SHA1 implementation ---*- C++ -* ===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // This code is taken from public domain 10 | // (http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c) 11 | // and modified by adding anonymous namespace, adding an interface 12 | // function fuzzer::ComputeSHA1() and removing unnecessary code. 13 | // 14 | // lib/Fuzzer can not use SHA1 implementation from openssl because 15 | // openssl may not be available and because we may be fuzzing openssl itself. 16 | // For the same reason we do not want to depend on SHA1 from LLVM tree. 17 | //===----------------------------------------------------------------------===// 18 | 19 | #include "FuzzerDefs.h" 20 | 21 | /* This code is public-domain - it is based on libcrypt 22 | * placed in the public domain by Wei Dai and other contributors. 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | namespace { // Added for LibFuzzer 29 | 30 | #ifdef __BIG_ENDIAN__ 31 | # define SHA_BIG_ENDIAN 32 | #elif defined __LITTLE_ENDIAN__ 33 | /* override */ 34 | #elif defined __BYTE_ORDER 35 | # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 36 | # define SHA_BIG_ENDIAN 37 | # endif 38 | #else // ! defined __LITTLE_ENDIAN__ 39 | # include // machine/endian.h 40 | # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 41 | # define SHA_BIG_ENDIAN 42 | # endif 43 | #endif 44 | 45 | 46 | /* header */ 47 | 48 | #define HASH_LENGTH 20 49 | #define BLOCK_LENGTH 64 50 | 51 | typedef struct sha1nfo { 52 | uint32_t buffer[BLOCK_LENGTH/4]; 53 | uint32_t state[HASH_LENGTH/4]; 54 | uint32_t byteCount; 55 | uint8_t bufferOffset; 56 | uint8_t keyBuffer[BLOCK_LENGTH]; 57 | uint8_t innerHash[HASH_LENGTH]; 58 | } sha1nfo; 59 | 60 | /* public API - prototypes - TODO: doxygen*/ 61 | 62 | /** 63 | */ 64 | void sha1_init(sha1nfo *s); 65 | /** 66 | */ 67 | void sha1_writebyte(sha1nfo *s, uint8_t data); 68 | /** 69 | */ 70 | void sha1_write(sha1nfo *s, const char *data, size_t len); 71 | /** 72 | */ 73 | uint8_t* sha1_result(sha1nfo *s); 74 | 75 | 76 | /* code */ 77 | #define SHA1_K0 0x5a827999 78 | #define SHA1_K20 0x6ed9eba1 79 | #define SHA1_K40 0x8f1bbcdc 80 | #define SHA1_K60 0xca62c1d6 81 | 82 | void sha1_init(sha1nfo *s) { 83 | s->state[0] = 0x67452301; 84 | s->state[1] = 0xefcdab89; 85 | s->state[2] = 0x98badcfe; 86 | s->state[3] = 0x10325476; 87 | s->state[4] = 0xc3d2e1f0; 88 | s->byteCount = 0; 89 | s->bufferOffset = 0; 90 | } 91 | 92 | uint32_t sha1_rol32(uint32_t number, uint8_t bits) { 93 | return ((number << bits) | (number >> (32-bits))); 94 | } 95 | 96 | void sha1_hashBlock(sha1nfo *s) { 97 | uint8_t i; 98 | uint32_t a,b,c,d,e,t; 99 | 100 | a=s->state[0]; 101 | b=s->state[1]; 102 | c=s->state[2]; 103 | d=s->state[3]; 104 | e=s->state[4]; 105 | for (i=0; i<80; i++) { 106 | if (i>=16) { 107 | t = s->buffer[(i+13)&15] ^ s->buffer[(i+8)&15] ^ s->buffer[(i+2)&15] ^ s->buffer[i&15]; 108 | s->buffer[i&15] = sha1_rol32(t,1); 109 | } 110 | if (i<20) { 111 | t = (d ^ (b & (c ^ d))) + SHA1_K0; 112 | } else if (i<40) { 113 | t = (b ^ c ^ d) + SHA1_K20; 114 | } else if (i<60) { 115 | t = ((b & c) | (d & (b | c))) + SHA1_K40; 116 | } else { 117 | t = (b ^ c ^ d) + SHA1_K60; 118 | } 119 | t+=sha1_rol32(a,5) + e + s->buffer[i&15]; 120 | e=d; 121 | d=c; 122 | c=sha1_rol32(b,30); 123 | b=a; 124 | a=t; 125 | } 126 | s->state[0] += a; 127 | s->state[1] += b; 128 | s->state[2] += c; 129 | s->state[3] += d; 130 | s->state[4] += e; 131 | } 132 | 133 | void sha1_addUncounted(sha1nfo *s, uint8_t data) { 134 | uint8_t * const b = (uint8_t*) s->buffer; 135 | #ifdef SHA_BIG_ENDIAN 136 | b[s->bufferOffset] = data; 137 | #else 138 | b[s->bufferOffset ^ 3] = data; 139 | #endif 140 | s->bufferOffset++; 141 | if (s->bufferOffset == BLOCK_LENGTH) { 142 | sha1_hashBlock(s); 143 | s->bufferOffset = 0; 144 | } 145 | } 146 | 147 | void sha1_writebyte(sha1nfo *s, uint8_t data) { 148 | ++s->byteCount; 149 | sha1_addUncounted(s, data); 150 | } 151 | 152 | void sha1_write(sha1nfo *s, const char *data, size_t len) { 153 | for (;len--;) sha1_writebyte(s, (uint8_t) *data++); 154 | } 155 | 156 | void sha1_pad(sha1nfo *s) { 157 | // Implement SHA-1 padding (fips180-2 §5.1.1) 158 | 159 | // Pad with 0x80 followed by 0x00 until the end of the block 160 | sha1_addUncounted(s, 0x80); 161 | while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00); 162 | 163 | // Append length in the last 8 bytes 164 | sha1_addUncounted(s, 0); // We're only using 32 bit lengths 165 | sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths 166 | sha1_addUncounted(s, 0); // So zero pad the top bits 167 | sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8 168 | sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as 169 | sha1_addUncounted(s, s->byteCount >> 13); // byte. 170 | sha1_addUncounted(s, s->byteCount >> 5); 171 | sha1_addUncounted(s, s->byteCount << 3); 172 | } 173 | 174 | uint8_t* sha1_result(sha1nfo *s) { 175 | // Pad to complete the last block 176 | sha1_pad(s); 177 | 178 | #ifndef SHA_BIG_ENDIAN 179 | // Swap byte order back 180 | int i; 181 | for (i=0; i<5; i++) { 182 | s->state[i]= 183 | (((s->state[i])<<24)& 0xff000000) 184 | | (((s->state[i])<<8) & 0x00ff0000) 185 | | (((s->state[i])>>8) & 0x0000ff00) 186 | | (((s->state[i])>>24)& 0x000000ff); 187 | } 188 | #endif 189 | 190 | // Return pointer to hash (20 characters) 191 | return (uint8_t*) s->state; 192 | } 193 | 194 | } // namespace; Added for LibFuzzer 195 | 196 | // The rest is added for LibFuzzer 197 | void fuzzer::ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out) { 198 | sha1nfo s; 199 | sha1_init(&s); 200 | sha1_write(&s, (const char*)Data, Len); 201 | memcpy(Out, sha1_result(&s), HASH_LENGTH); 202 | } 203 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerTracePC.h: -------------------------------------------------------------------------------- 1 | //===- FuzzerTracePC.h - Internal header for the Fuzzer ---------*- C++ -* ===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // fuzzer::TracePC 10 | //===----------------------------------------------------------------------===// 11 | 12 | #ifndef LLVM_FUZZER_TRACE_PC 13 | #define LLVM_FUZZER_TRACE_PC 14 | 15 | #include 16 | 17 | #include "FuzzerDefs.h" 18 | #include "FuzzerValueBitMap.h" 19 | 20 | namespace fuzzer { 21 | 22 | // TableOfRecentCompares (TORC) remembers the most recently performed 23 | // comparisons of type T. 24 | // We record the arguments of CMP instructions in this table unconditionally 25 | // because it seems cheaper this way than to compute some expensive 26 | // conditions inside __sanitizer_cov_trace_cmp*. 27 | // After the unit has been executed we may decide to use the contents of 28 | // this table to populate a Dictionary. 29 | template 30 | struct TableOfRecentCompares { 31 | static const size_t kSize = kSizeT; 32 | struct Pair { 33 | T A, B; 34 | }; 35 | void Insert(size_t Idx, T Arg1, T Arg2) { 36 | Idx = Idx % kSize; 37 | Table[Idx].A = Arg1; 38 | Table[Idx].B = Arg2; 39 | } 40 | 41 | Pair Get(size_t I) { return Table[I % kSize]; } 42 | 43 | Pair Table[kSize]; 44 | }; 45 | 46 | class TracePC { 47 | public: 48 | static const size_t kFeatureSetSize = ValueBitMap::kNumberOfItems; 49 | 50 | void HandleTrace(uint32_t *guard, uintptr_t PC); 51 | void HandleInit(uint32_t *start, uint32_t *stop); 52 | void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee); 53 | void HandleValueProfile(size_t Value) { ValueProfileMap.AddValue(Value); } 54 | template void HandleCmp(void *PC, T Arg1, T Arg2); 55 | size_t GetTotalPCCoverage(); 56 | void SetUseCounters(bool UC) { UseCounters = UC; } 57 | void SetUseValueProfile(bool VP) { UseValueProfile = VP; } 58 | void SetPrintNewPCs(bool P) { DoPrintNewPCs = P; } 59 | size_t FinalizeTrace(InputCorpus *C, size_t InputSize, bool Shrink); 60 | bool UpdateValueProfileMap(ValueBitMap *MaxValueProfileMap) { 61 | return UseValueProfile && MaxValueProfileMap->MergeFrom(ValueProfileMap); 62 | } 63 | 64 | void ResetMaps() { 65 | ValueProfileMap.Reset(); 66 | memset(Counters, 0, sizeof(Counters)); 67 | } 68 | 69 | void UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize); 70 | void PrintFeatureSet(); 71 | 72 | void PrintModuleInfo(); 73 | 74 | void PrintCoverage(); 75 | 76 | void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2, 77 | size_t n); 78 | void AddValueForStrcmp(void *caller_pc, const char *s1, const char *s2, 79 | size_t n); 80 | 81 | bool UsingTracePcGuard() const {return NumModules; } 82 | 83 | static const size_t kTORCSize = 1 << 5; 84 | TableOfRecentCompares TORC4; 85 | TableOfRecentCompares TORC8; 86 | 87 | void PrintNewPCs(); 88 | size_t GetNumPCs() const { return Min(kNumPCs, NumGuards + 1); } 89 | uintptr_t GetPC(size_t Idx) { 90 | assert(Idx < GetNumPCs()); 91 | return PCs[Idx]; 92 | } 93 | 94 | private: 95 | bool UseCounters = false; 96 | bool UseValueProfile = false; 97 | bool DoPrintNewPCs = false; 98 | 99 | struct Module { 100 | uint32_t *Start, *Stop; 101 | }; 102 | 103 | Module Modules[4096]; 104 | size_t NumModules = 0; 105 | size_t NumGuards = 0; 106 | 107 | static const size_t kNumCounters = 1 << 14; 108 | alignas(8) uint8_t Counters[kNumCounters]; 109 | 110 | static const size_t kNumPCs = 1 << 24; 111 | uintptr_t PCs[kNumPCs]; 112 | 113 | std::set *PrintedPCs; 114 | 115 | ValueBitMap ValueProfileMap; 116 | }; 117 | 118 | extern TracePC TPC; 119 | 120 | } // namespace fuzzer 121 | 122 | #endif // LLVM_FUZZER_TRACE_PC 123 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerUtil.cpp: -------------------------------------------------------------------------------- 1 | //===- FuzzerUtil.cpp - Misc utils ----------------------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // Misc utils. 10 | //===----------------------------------------------------------------------===// 11 | 12 | #include "FuzzerInternal.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | namespace fuzzer { 30 | 31 | void PrintHexArray(const uint8_t *Data, size_t Size, 32 | const char *PrintAfter) { 33 | for (size_t i = 0; i < Size; i++) 34 | Printf("0x%x,", (unsigned)Data[i]); 35 | Printf("%s", PrintAfter); 36 | } 37 | 38 | void Print(const Unit &v, const char *PrintAfter) { 39 | PrintHexArray(v.data(), v.size(), PrintAfter); 40 | } 41 | 42 | void PrintASCIIByte(uint8_t Byte) { 43 | if (Byte == '\\') 44 | Printf("\\\\"); 45 | else if (Byte == '"') 46 | Printf("\\\""); 47 | else if (Byte >= 32 && Byte < 127) 48 | Printf("%c", Byte); 49 | else 50 | Printf("\\x%02x", Byte); 51 | } 52 | 53 | void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) { 54 | for (size_t i = 0; i < Size; i++) 55 | PrintASCIIByte(Data[i]); 56 | Printf("%s", PrintAfter); 57 | } 58 | 59 | void PrintASCII(const Unit &U, const char *PrintAfter) { 60 | PrintASCII(U.data(), U.size(), PrintAfter); 61 | } 62 | 63 | std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]) { 64 | std::stringstream SS; 65 | for (int i = 0; i < kSHA1NumBytes; i++) 66 | SS << std::hex << std::setfill('0') << std::setw(2) << (unsigned)Sha1[i]; 67 | return SS.str(); 68 | } 69 | 70 | std::string Hash(const Unit &U) { 71 | uint8_t Hash[kSHA1NumBytes]; 72 | ComputeSHA1(U.data(), U.size(), Hash); 73 | return Sha1ToString(Hash); 74 | } 75 | 76 | static void AlarmHandler(int, siginfo_t *, void *) { 77 | Fuzzer::StaticAlarmCallback(); 78 | } 79 | 80 | static void CrashHandler(int, siginfo_t *, void *) { 81 | Fuzzer::StaticCrashSignalCallback(); 82 | } 83 | 84 | static void InterruptHandler(int, siginfo_t *, void *) { 85 | Fuzzer::StaticInterruptCallback(); 86 | } 87 | 88 | static void SetSigaction(int signum, 89 | void (*callback)(int, siginfo_t *, void *)) { 90 | struct sigaction sigact; 91 | memset(&sigact, 0, sizeof(sigact)); 92 | sigact.sa_sigaction = callback; 93 | if (sigaction(signum, &sigact, 0)) { 94 | Printf("libFuzzer: sigaction failed with %d\n", errno); 95 | return; 96 | // exit(1); 97 | } 98 | } 99 | 100 | void SetTimer(int Seconds) { 101 | // struct itimerval T {{Seconds, 0}, {Seconds, 0}}; 102 | // if (setitimer(ITIMER_REAL, &T, nullptr)) { 103 | // Printf("libFuzzer: setitimer failed with %d\n", errno); 104 | // return; 105 | // // exit(1); 106 | // } 107 | // SetSigaction(SIGALRM, AlarmHandler); 108 | 109 | // Hack to use 1s SIGXCPU signal instead of SIGALRM 110 | int Res; 111 | struct rlimit limit = {1, RLIM_INFINITY}; 112 | Res = setrlimit(RLIMIT_CPU, &limit); 113 | assert(Res == 0); 114 | 115 | struct sigaction sigact; 116 | memset(&sigact, 0, sizeof(sigact)); 117 | sigact.sa_sigaction = AlarmHandler; 118 | Res = sigaction(SIGXCPU, &sigact, 0); 119 | assert(Res == 0); 120 | } 121 | 122 | void SetSigSegvHandler() { SetSigaction(SIGSEGV, CrashHandler); } 123 | void SetSigBusHandler() { SetSigaction(SIGBUS, CrashHandler); } 124 | void SetSigAbrtHandler() { SetSigaction(SIGABRT, CrashHandler); } 125 | void SetSigIllHandler() { SetSigaction(SIGILL, CrashHandler); } 126 | void SetSigFpeHandler() { SetSigaction(SIGFPE, CrashHandler); } 127 | void SetSigIntHandler() { SetSigaction(SIGINT, InterruptHandler); } 128 | void SetSigTermHandler() { SetSigaction(SIGTERM, InterruptHandler); } 129 | 130 | int NumberOfCpuCores() { 131 | const char *CmdLine = nullptr; 132 | if (LIBFUZZER_LINUX) { 133 | CmdLine = "nproc"; 134 | } else if (LIBFUZZER_APPLE) { 135 | CmdLine = "sysctl -n hw.ncpu"; 136 | } else { 137 | assert(0 && "NumberOfCpuCores() is not implemented for your platform"); 138 | } 139 | 140 | FILE *F = popen(CmdLine, "r"); 141 | int N = 1; 142 | if (!F || fscanf(F, "%d", &N) != 1) { 143 | Printf("WARNING: Failed to parse output of command \"%s\" in %s(). " 144 | "Assuming CPU count of 1.\n", 145 | CmdLine, __func__); 146 | N = 1; 147 | } 148 | 149 | if (pclose(F)) { 150 | Printf("WARNING: Executing command \"%s\" failed in %s(). " 151 | "Assuming CPU count of 1.\n", 152 | CmdLine, __func__); 153 | N = 1; 154 | } 155 | if (N < 1) { 156 | Printf("WARNING: Reported CPU count (%d) from command \"%s\" was invalid " 157 | "in %s(). Assuming CPU count of 1.\n", 158 | N, CmdLine, __func__); 159 | N = 1; 160 | } 161 | return N; 162 | } 163 | 164 | bool ToASCII(uint8_t *Data, size_t Size) { 165 | bool Changed = false; 166 | for (size_t i = 0; i < Size; i++) { 167 | uint8_t &X = Data[i]; 168 | auto NewX = X; 169 | NewX &= 127; 170 | if (!isspace(NewX) && !isprint(NewX)) 171 | NewX = ' '; 172 | Changed |= NewX != X; 173 | X = NewX; 174 | } 175 | return Changed; 176 | } 177 | 178 | bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); } 179 | 180 | bool IsASCII(const uint8_t *Data, size_t Size) { 181 | for (size_t i = 0; i < Size; i++) 182 | if (!(isprint(Data[i]) || isspace(Data[i]))) return false; 183 | return true; 184 | } 185 | 186 | bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) { 187 | U->clear(); 188 | if (Str.empty()) return false; 189 | size_t L = 0, R = Str.size() - 1; // We are parsing the range [L,R]. 190 | // Skip spaces from both sides. 191 | while (L < R && isspace(Str[L])) L++; 192 | while (R > L && isspace(Str[R])) R--; 193 | if (R - L < 2) return false; 194 | // Check the closing " 195 | if (Str[R] != '"') return false; 196 | R--; 197 | // Find the opening " 198 | while (L < R && Str[L] != '"') L++; 199 | if (L >= R) return false; 200 | assert(Str[L] == '\"'); 201 | L++; 202 | assert(L <= R); 203 | for (size_t Pos = L; Pos <= R; Pos++) { 204 | uint8_t V = (uint8_t)Str[Pos]; 205 | if (!isprint(V) && !isspace(V)) return false; 206 | if (V =='\\') { 207 | // Handle '\\' 208 | if (Pos + 1 <= R && (Str[Pos + 1] == '\\' || Str[Pos + 1] == '"')) { 209 | U->push_back(Str[Pos + 1]); 210 | Pos++; 211 | continue; 212 | } 213 | // Handle '\xAB' 214 | if (Pos + 3 <= R && Str[Pos + 1] == 'x' 215 | && isxdigit(Str[Pos + 2]) && isxdigit(Str[Pos + 3])) { 216 | char Hex[] = "0xAA"; 217 | Hex[2] = Str[Pos + 2]; 218 | Hex[3] = Str[Pos + 3]; 219 | U->push_back(strtol(Hex, nullptr, 16)); 220 | Pos += 3; 221 | continue; 222 | } 223 | return false; // Invalid escape. 224 | } else { 225 | // Any other character. 226 | U->push_back(V); 227 | } 228 | } 229 | return true; 230 | } 231 | 232 | bool ParseDictionaryFile(const std::string &Text, std::vector *Units) { 233 | if (Text.empty()) { 234 | Printf("ParseDictionaryFile: file does not exist or is empty\n"); 235 | return false; 236 | } 237 | std::istringstream ISS(Text); 238 | Units->clear(); 239 | Unit U; 240 | int LineNo = 0; 241 | std::string S; 242 | while (std::getline(ISS, S, '\n')) { 243 | LineNo++; 244 | size_t Pos = 0; 245 | while (Pos < S.size() && isspace(S[Pos])) Pos++; // Skip spaces. 246 | if (Pos == S.size()) continue; // Empty line. 247 | if (S[Pos] == '#') continue; // Comment line. 248 | if (ParseOneDictionaryEntry(S, &U)) { 249 | Units->push_back(U); 250 | } else { 251 | Printf("ParseDictionaryFile: error in line %d\n\t\t%s\n", LineNo, 252 | S.c_str()); 253 | return false; 254 | } 255 | } 256 | return true; 257 | } 258 | 259 | void SleepSeconds(int Seconds) { 260 | sleep(Seconds); // Use C API to avoid coverage from instrumented libc++. 261 | } 262 | 263 | int GetPid() { return getpid(); } 264 | 265 | std::string Base64(const Unit &U) { 266 | static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 267 | "abcdefghijklmnopqrstuvwxyz" 268 | "0123456789+/"; 269 | std::string Res; 270 | size_t i; 271 | for (i = 0; i + 2 < U.size(); i += 3) { 272 | uint32_t x = (U[i] << 16) + (U[i + 1] << 8) + U[i + 2]; 273 | Res += Table[(x >> 18) & 63]; 274 | Res += Table[(x >> 12) & 63]; 275 | Res += Table[(x >> 6) & 63]; 276 | Res += Table[x & 63]; 277 | } 278 | if (i + 1 == U.size()) { 279 | uint32_t x = (U[i] << 16); 280 | Res += Table[(x >> 18) & 63]; 281 | Res += Table[(x >> 12) & 63]; 282 | Res += "=="; 283 | } else if (i + 2 == U.size()) { 284 | uint32_t x = (U[i] << 16) + (U[i + 1] << 8); 285 | Res += Table[(x >> 18) & 63]; 286 | Res += Table[(x >> 12) & 63]; 287 | Res += Table[(x >> 6) & 63]; 288 | Res += "="; 289 | } 290 | return Res; 291 | } 292 | 293 | size_t GetPeakRSSMb() { 294 | struct rusage usage; 295 | if (getrusage(RUSAGE_SELF, &usage)) 296 | return 0; 297 | if (LIBFUZZER_LINUX) { 298 | // ru_maxrss is in KiB 299 | return usage.ru_maxrss >> 10; 300 | } else if (LIBFUZZER_APPLE) { 301 | // ru_maxrss is in bytes 302 | return usage.ru_maxrss >> 20; 303 | } 304 | assert(0 && "GetPeakRSSMb() is not implemented for your platform"); 305 | return 0; 306 | } 307 | 308 | std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) { 309 | if (!EF->__sanitizer_symbolize_pc) return ""; 310 | char PcDescr[1024]; 311 | EF->__sanitizer_symbolize_pc(reinterpret_cast(PC), 312 | SymbolizedFMT, PcDescr, sizeof(PcDescr)); 313 | PcDescr[sizeof(PcDescr) - 1] = 0; // Just in case. 314 | return PcDescr; 315 | } 316 | 317 | void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) { 318 | if (EF->__sanitizer_symbolize_pc) 319 | Printf("%s", DescribePC(SymbolizedFMT, PC).c_str()); 320 | else 321 | Printf(FallbackFMT, PC); 322 | } 323 | 324 | bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out) { 325 | FILE *Pipe = popen(Command.c_str(), "r"); 326 | if (!Pipe) return false; 327 | char Buff[1024]; 328 | size_t N; 329 | while ((N = fread(Buff, 1, sizeof(Buff), Pipe)) > 0) 330 | Out->append(Buff, N); 331 | return true; 332 | } 333 | 334 | } // namespace fuzzer 335 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerUtilDarwin.cpp: -------------------------------------------------------------------------------- 1 | //===- FuzzerUtilDarwin.cpp - Misc utils ----------------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // Misc utils for Darwin. 10 | //===----------------------------------------------------------------------===// 11 | #include "FuzzerDefs.h" 12 | #if LIBFUZZER_APPLE 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | // There is no header for this on macOS so declare here 19 | extern "C" char **environ; 20 | 21 | namespace fuzzer { 22 | 23 | static std::mutex SignalMutex; 24 | // Global variables used to keep track of how signal handling should be 25 | // restored. They should **not** be accessed without holding `SignalMutex`. 26 | static int ActiveThreadCount = 0; 27 | static struct sigaction OldSigIntAction; 28 | static struct sigaction OldSigQuitAction; 29 | static sigset_t OldBlockedSignalsSet; 30 | 31 | // This is a reimplementation of Libc's `system()`. On Darwin the Libc 32 | // implementation contains a mutex which prevents it from being used 33 | // concurrently. This implementation **can** be used concurrently. It sets the 34 | // signal handlers when the first thread enters and restores them when the last 35 | // thread finishes execution of the function and ensures this is not racey by 36 | // using a mutex. 37 | int ExecuteCommand(const std::string &Command) { 38 | posix_spawnattr_t SpawnAttributes; 39 | if (posix_spawnattr_init(&SpawnAttributes)) 40 | return -1; 41 | // Block and ignore signals of the current process when the first thread 42 | // enters. 43 | { 44 | std::lock_guard Lock(SignalMutex); 45 | if (ActiveThreadCount == 0) { 46 | static struct sigaction IgnoreSignalAction; 47 | sigset_t BlockedSignalsSet; 48 | memset(&IgnoreSignalAction, 0, sizeof(IgnoreSignalAction)); 49 | IgnoreSignalAction.sa_handler = SIG_IGN; 50 | 51 | if (sigaction(SIGINT, &IgnoreSignalAction, &OldSigIntAction) == -1) { 52 | Printf("Failed to ignore SIGINT\n"); 53 | (void)posix_spawnattr_destroy(&SpawnAttributes); 54 | return -1; 55 | } 56 | if (sigaction(SIGQUIT, &IgnoreSignalAction, &OldSigQuitAction) == -1) { 57 | Printf("Failed to ignore SIGQUIT\n"); 58 | // Try our best to restore the signal handlers. 59 | (void)sigaction(SIGINT, &OldSigIntAction, NULL); 60 | (void)posix_spawnattr_destroy(&SpawnAttributes); 61 | return -1; 62 | } 63 | 64 | (void)sigemptyset(&BlockedSignalsSet); 65 | (void)sigaddset(&BlockedSignalsSet, SIGCHLD); 66 | if (sigprocmask(SIG_BLOCK, &BlockedSignalsSet, &OldBlockedSignalsSet) == 67 | -1) { 68 | Printf("Failed to block SIGCHLD\n"); 69 | // Try our best to restore the signal handlers. 70 | (void)sigaction(SIGQUIT, &OldSigQuitAction, NULL); 71 | (void)sigaction(SIGINT, &OldSigIntAction, NULL); 72 | (void)posix_spawnattr_destroy(&SpawnAttributes); 73 | return -1; 74 | } 75 | } 76 | ++ActiveThreadCount; 77 | } 78 | 79 | // NOTE: Do not introduce any new `return` statements past this 80 | // point. It is important that `ActiveThreadCount` always be decremented 81 | // when leaving this function. 82 | 83 | // Make sure the child process uses the default handlers for the 84 | // following signals rather than inheriting what the parent has. 85 | sigset_t DefaultSigSet; 86 | (void)sigemptyset(&DefaultSigSet); 87 | (void)sigaddset(&DefaultSigSet, SIGQUIT); 88 | (void)sigaddset(&DefaultSigSet, SIGINT); 89 | (void)posix_spawnattr_setsigdefault(&SpawnAttributes, &DefaultSigSet); 90 | // Make sure the child process doesn't block SIGCHLD 91 | (void)posix_spawnattr_setsigmask(&SpawnAttributes, &OldBlockedSignalsSet); 92 | short SpawnFlags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; 93 | (void)posix_spawnattr_setflags(&SpawnAttributes, SpawnFlags); 94 | 95 | pid_t Pid; 96 | char **Environ = environ; // Read from global 97 | const char *CommandCStr = Command.c_str(); 98 | const char *Argv[] = {"sh", "-c", CommandCStr, NULL}; 99 | int ErrorCode = 0, ProcessStatus = 0; 100 | // FIXME: We probably shouldn't hardcode the shell path. 101 | ErrorCode = posix_spawn(&Pid, "/bin/sh", NULL, &SpawnAttributes, 102 | (char *const *)Argv, Environ); 103 | (void)posix_spawnattr_destroy(&SpawnAttributes); 104 | if (!ErrorCode) { 105 | pid_t SavedPid = Pid; 106 | do { 107 | // Repeat until call completes uninterrupted. 108 | Pid = waitpid(SavedPid, &ProcessStatus, /*options=*/0); 109 | } while (Pid == -1 && errno == EINTR); 110 | if (Pid == -1) { 111 | // Fail for some other reason. 112 | ProcessStatus = -1; 113 | } 114 | } else if (ErrorCode == ENOMEM || ErrorCode == EAGAIN) { 115 | // Fork failure. 116 | ProcessStatus = -1; 117 | } else { 118 | // Shell execution failure. 119 | ProcessStatus = W_EXITCODE(127, 0); 120 | } 121 | 122 | // Restore the signal handlers of the current process when the last thread 123 | // using this function finishes. 124 | { 125 | std::lock_guard Lock(SignalMutex); 126 | --ActiveThreadCount; 127 | if (ActiveThreadCount == 0) { 128 | bool FailedRestore = false; 129 | if (sigaction(SIGINT, &OldSigIntAction, NULL) == -1) { 130 | Printf("Failed to restore SIGINT handling\n"); 131 | FailedRestore = true; 132 | } 133 | if (sigaction(SIGQUIT, &OldSigQuitAction, NULL) == -1) { 134 | Printf("Failed to restore SIGQUIT handling\n"); 135 | FailedRestore = true; 136 | } 137 | if (sigprocmask(SIG_BLOCK, &OldBlockedSignalsSet, NULL) == -1) { 138 | Printf("Failed to unblock SIGCHLD\n"); 139 | FailedRestore = true; 140 | } 141 | if (FailedRestore) 142 | ProcessStatus = -1; 143 | } 144 | } 145 | return ProcessStatus; 146 | } 147 | } 148 | #endif // LIBFUZZER_APPLE 149 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerUtilLinux.cpp: -------------------------------------------------------------------------------- 1 | //===- FuzzerUtilLinux.cpp - Misc utils -----------------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // Misc utils for Linux. 10 | //===----------------------------------------------------------------------===// 11 | #include "FuzzerDefs.h" 12 | #if LIBFUZZER_LINUX 13 | #include 14 | namespace fuzzer { 15 | int ExecuteCommand(const std::string &Command) { 16 | return system(Command.c_str()); 17 | } 18 | } 19 | #endif // LIBFUZZER_LINUX 20 | -------------------------------------------------------------------------------- /Fuzzer/FuzzerValueBitMap.h: -------------------------------------------------------------------------------- 1 | //===- FuzzerValueBitMap.h - INTERNAL - Bit map -----------------*- C++ -* ===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // ValueBitMap. 10 | //===----------------------------------------------------------------------===// 11 | 12 | #ifndef LLVM_FUZZER_VALUE_BIT_MAP_H 13 | #define LLVM_FUZZER_VALUE_BIT_MAP_H 14 | 15 | #include "FuzzerDefs.h" 16 | 17 | namespace fuzzer { 18 | 19 | // A bit map containing kMapSizeInWords bits. 20 | struct ValueBitMap { 21 | static const size_t kMapSizeInBits = 65371; // Prime. 22 | static const size_t kMapSizeInBitsAligned = 65536; // 2^16 23 | static const size_t kBitsInWord = (sizeof(uintptr_t) * 8); 24 | static const size_t kMapSizeInWords = kMapSizeInBitsAligned / kBitsInWord; 25 | public: 26 | static const size_t kNumberOfItems = kMapSizeInBits; 27 | // Clears all bits. 28 | void Reset() { memset(Map, 0, sizeof(Map)); } 29 | 30 | // Computes a hash function of Value and sets the corresponding bit. 31 | // Returns true if the bit was changed from 0 to 1. 32 | inline bool AddValue(uintptr_t Value) { 33 | uintptr_t Idx = Value < kMapSizeInBits ? Value : Value % kMapSizeInBits; 34 | uintptr_t WordIdx = Idx / kBitsInWord; 35 | uintptr_t BitIdx = Idx % kBitsInWord; 36 | uintptr_t Old = Map[WordIdx]; 37 | uintptr_t New = Old | (1UL << BitIdx); 38 | Map[WordIdx] = New; 39 | return New != Old; 40 | } 41 | 42 | inline bool Get(uintptr_t Idx) { 43 | assert(Idx < kMapSizeInBits); 44 | uintptr_t WordIdx = Idx / kBitsInWord; 45 | uintptr_t BitIdx = Idx % kBitsInWord; 46 | return Map[WordIdx] & (1UL << BitIdx); 47 | } 48 | 49 | size_t GetNumBitsSinceLastMerge() const { return NumBits; } 50 | 51 | // Merges 'Other' into 'this', clears 'Other', updates NumBits, 52 | // returns true if new bits were added. 53 | ATTRIBUTE_TARGET_POPCNT 54 | bool MergeFrom(ValueBitMap &Other) { 55 | uintptr_t Res = 0; 56 | size_t OldNumBits = NumBits; 57 | for (size_t i = 0; i < kMapSizeInWords; i++) { 58 | auto O = Other.Map[i]; 59 | auto M = Map[i]; 60 | if (O) { 61 | Map[i] = (M |= O); 62 | Other.Map[i] = 0; 63 | } 64 | if (M) 65 | Res += __builtin_popcountl(M); 66 | } 67 | NumBits = Res; 68 | return OldNumBits < NumBits; 69 | } 70 | 71 | template 72 | void ForEach(Callback CB) { 73 | for (size_t i = 0; i < kMapSizeInWords; i++) 74 | if (uintptr_t M = Map[i]) 75 | for (size_t j = 0; j < sizeof(M) * 8; j++) 76 | if (M & ((uintptr_t)1 << j)) 77 | CB(i * sizeof(M) * 8 + j); 78 | } 79 | 80 | private: 81 | size_t NumBits = 0; 82 | uintptr_t Map[kMapSizeInWords] __attribute__((aligned(512))); 83 | }; 84 | 85 | } // namespace fuzzer 86 | 87 | #endif // LLVM_FUZZER_VALUE_BIT_MAP_H 88 | -------------------------------------------------------------------------------- /Fuzzer/README.txt: -------------------------------------------------------------------------------- 1 | Move to http://llvm.org/docs/LibFuzzer.html 2 | 3 | -------------------------------------------------------------------------------- /Fuzzer/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | LIBFUZZER_SRC_DIR=$(dirname $0) 3 | for f in $LIBFUZZER_SRC_DIR/*.cpp; do 4 | clang -g -O2 -fno-omit-frame-pointer -std=c++11 $f -c & 5 | done 6 | wait 7 | rm -f libFuzzer.a 8 | ar ru libFuzzer.a Fuzzer*.o 9 | rm -f Fuzzer*.o 10 | 11 | -------------------------------------------------------------------------------- /Fuzzer/cxx.dict: -------------------------------------------------------------------------------- 1 | "++" 2 | "--" 3 | "<<" 4 | ">>" 5 | "+=" 6 | "-=" 7 | "*=" 8 | "/=" 9 | ">>=" 10 | "<<=" 11 | "&=" 12 | "|=" 13 | "^=" 14 | "%=" 15 | "!=" 16 | "&&" 17 | "||" 18 | "==" 19 | ">=" 20 | "<=" 21 | "->" 22 | "alignas" 23 | "alignof" 24 | "and" 25 | "and_eq" 26 | "asm" 27 | "auto" 28 | "bitand" 29 | "bitor" 30 | "bool" 31 | "break" 32 | "case" 33 | "catch" 34 | "char" 35 | "char16_t" 36 | "char32_t" 37 | "class" 38 | "compl" 39 | "concept" 40 | "const" 41 | "constexpr" 42 | "const_cast" 43 | "continue" 44 | "decltype" 45 | "default" 46 | "delete" 47 | "do" 48 | "double" 49 | "dynamic_cast" 50 | "else" 51 | "enum" 52 | "explicit" 53 | "export" 54 | "extern" 55 | "false" 56 | "float" 57 | "for" 58 | "friend" 59 | "goto" 60 | "if" 61 | "inline" 62 | "int" 63 | "long" 64 | "mutable" 65 | "namespace" 66 | "new" 67 | "noexcept" 68 | "not" 69 | "not_eq" 70 | "nullptr" 71 | "operator" 72 | "or" 73 | "or_eq" 74 | "private" 75 | "protected" 76 | "public" 77 | "register" 78 | "reinterpret_cast" 79 | "requires" 80 | "return" 81 | "short" 82 | "signed" 83 | "sizeof" 84 | "static" 85 | "static_assert" 86 | "static_cast" 87 | "struct" 88 | "switch" 89 | "template" 90 | "this" 91 | "thread_local" 92 | "throw" 93 | "true" 94 | "try" 95 | "typedef" 96 | "typeid" 97 | "typename" 98 | "union" 99 | "unsigned" 100 | "using" 101 | "virtual" 102 | "void" 103 | "volatile" 104 | "wchar_t" 105 | "while" 106 | "xor" 107 | "xor_eq" 108 | "if" 109 | "elif" 110 | "else" 111 | "endif" 112 | "defined" 113 | "ifdef" 114 | "ifndef" 115 | "define" 116 | "undef" 117 | "include" 118 | "line" 119 | "error" 120 | "pragma" 121 | "override" 122 | "final" 123 | -------------------------------------------------------------------------------- /Fuzzer/standalone/StandaloneFuzzTargetMain.c: -------------------------------------------------------------------------------- 1 | /*===- StandaloneFuzzTargetMain.c - standalone main() for fuzz targets. ---===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // This main() function can be linked to a fuzz target (i.e. a library 10 | // that exports LLVMFuzzerTestOneInput() and possibly LLVMFuzzerInitialize()) 11 | // instead of libFuzzer. This main() function will not perform any fuzzing 12 | // but will simply feed all input files one by one to the fuzz target. 13 | // 14 | // Use this file to provide reproducers for bugs when linking against libFuzzer 15 | // or other fuzzing engine is undesirable. 16 | //===----------------------------------------------------------------------===*/ 17 | #include 18 | #include 19 | #include 20 | 21 | extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size); 22 | __attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv); 23 | int main(int argc, char **argv) { 24 | fprintf(stderr, "StandaloneFuzzTargetMain: running %d inputs\n", argc - 1); 25 | if (LLVMFuzzerInitialize) 26 | LLVMFuzzerInitialize(&argc, &argv); 27 | for (int i = 1; i < argc; i++) { 28 | fprintf(stderr, "Running: %s\n", argv[i]); 29 | FILE *f = fopen(argv[i], "r"); 30 | assert(f); 31 | fseek(f, 0, SEEK_END); 32 | size_t len = ftell(f); 33 | fseek(f, 0, SEEK_SET); 34 | unsigned char *buf = (unsigned char*)malloc(len); 35 | size_t n_read = fread(buf, 1, len, f); 36 | assert(n_read == len); 37 | LLVMFuzzerTestOneInput(buf, len); 38 | free(buf); 39 | fprintf(stderr, "Done: %s: (%zd bytes)\n", argv[i], n_read); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Fuzzer/test/AFLDriverTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Contains dummy functions used to avoid dependency on AFL. 5 | #include 6 | #include 7 | 8 | extern "C" void __afl_manual_init() {} 9 | 10 | extern "C" int __afl_persistent_loop(unsigned int) { 11 | return 0; 12 | } 13 | 14 | // This declaration exists to prevent the Darwin linker 15 | // from complaining about this being a missing weak symbol. 16 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { 17 | return 0; 18 | } 19 | 20 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /Fuzzer/test/AbsNegAndConstant64Test.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // abs(x) < 0 and y == Const puzzle, 64-bit variant. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 12 | if (Size < 16) return 0; 13 | int64_t x; 14 | uint64_t y; 15 | memcpy(&x, Data, sizeof(x)); 16 | memcpy(&y, Data + sizeof(x), sizeof(y)); 17 | if (labs(x) < 0 && y == 0xbaddcafedeadbeefUL) { 18 | printf("BINGO; Found the target, exiting; x = 0x%lx y 0x%lx\n", x, y); 19 | exit(1); 20 | } 21 | return 0; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /Fuzzer/test/AbsNegAndConstantTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // abs(x) < 0 and y == Const puzzle. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 12 | if (Size < 8) return 0; 13 | int x; 14 | unsigned y; 15 | memcpy(&x, Data, sizeof(x)); 16 | memcpy(&y, Data + sizeof(x), sizeof(y)); 17 | if (abs(x) < 0 && y == 0xbaddcafe) { 18 | printf("BINGO; Found the target, exiting; x = 0x%x y 0x%x\n", x, y); 19 | exit(1); 20 | } 21 | return 0; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /Fuzzer/test/AccumulateAllocationsTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Test with a more mallocs than frees, but no leak. 5 | #include 6 | #include 7 | 8 | const int kAllocatedPointersSize = 10000; 9 | int NumAllocatedPointers = 0; 10 | int *AllocatedPointers[kAllocatedPointersSize]; 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 13 | if (NumAllocatedPointers < kAllocatedPointersSize) 14 | AllocatedPointers[NumAllocatedPointers++] = new int; 15 | return 0; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Fuzzer/test/BufferOverflowOnInput.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find the string "Hi!". 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static volatile bool SeedLargeBuffer; 12 | 13 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 14 | assert(Data); 15 | if (Size >= 4) 16 | SeedLargeBuffer = true; 17 | if (Size == 3 && SeedLargeBuffer && Data[3]) { 18 | std::cout << "Woops, reading Data[3] w/o crashing\n"; 19 | exit(1); 20 | } 21 | return 0; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /Fuzzer/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Build all these tests with -O0, otherwise optimizations may merge some 2 | # basic blocks and we'll fail to discover the targets. 3 | # We change the flags for every build type because we might be doing 4 | # a multi-configuration build (e.g. Xcode) where CMAKE_BUILD_TYPE doesn't 5 | # mean anything. 6 | set(variables_to_filter 7 | CMAKE_CXX_FLAGS_RELEASE 8 | CMAKE_CXX_FLAGS_DEBUG 9 | CMAKE_CXX_FLAGS_RELWITHDEBINFO 10 | CMAKE_CXX_FLAGS_MINSIZEREL 11 | LIBFUZZER_FLAGS_BASE 12 | ) 13 | foreach (VARNAME ${variables_to_filter}) 14 | string(REPLACE " " ";" BUILD_FLAGS_AS_LIST "${${VARNAME}}") 15 | set(new_flags "") 16 | foreach (flag ${BUILD_FLAGS_AS_LIST}) 17 | # NOTE: Use of XX here is to avoid a CMake warning due to CMP0054 18 | if (NOT ("XX${flag}" MATCHES "XX-O[0123s]")) 19 | set(new_flags "${new_flags} ${flag}") 20 | else() 21 | set(new_flags "${new_flags} -O0") 22 | endif() 23 | endforeach() 24 | set(${VARNAME} "${new_flags}") 25 | endforeach() 26 | 27 | # Enable the coverage instrumentation (it is disabled for the Fuzzer lib). 28 | #set(CMAKE_CXX_FLAGS "${LIBFUZZER_FLAGS_BASE} -fno-sanitize-coverage=8bit-counters -fsanitize-coverage=edge,indirect-calls,trace-cmp,trace-div,trace-gep,trace-pc-guard -g") 29 | set(CMAKE_CXX_FLAGS "${LIBFUZZER_FLAGS_BASE} -fsanitize-coverage=edge,indirect-calls,trace-cmp,trace-div,trace-gep -g") 30 | 31 | # add_libfuzzer_test( 32 | # SOURCES source0.cpp [source1.cpp ...] 33 | # ) 34 | # 35 | # Declares a LibFuzzer test executable with target name LLVMFuzzer-. 36 | # 37 | # One or more source files to be compiled into the binary must be declared 38 | # after the SOURCES keyword. 39 | function(add_libfuzzer_test name) 40 | set(multi_arg_options "SOURCES") 41 | cmake_parse_arguments( 42 | "add_libfuzzer_test" "" "" "${multi_arg_options}" ${ARGN}) 43 | if ("${add_libfuzzer_test_SOURCES}" STREQUAL "") 44 | message(FATAL_ERROR "Source files must be specified") 45 | endif() 46 | add_executable(LLVMFuzzer-${name} 47 | ${add_libfuzzer_test_SOURCES} 48 | ) 49 | target_link_libraries(LLVMFuzzer-${name} LLVMFuzzer) 50 | # Place binary where llvm-lit expects to find it 51 | set_target_properties(LLVMFuzzer-${name} 52 | PROPERTIES RUNTIME_OUTPUT_DIRECTORY 53 | "${CMAKE_BINARY_DIR}/lib/Fuzzer/test" 54 | ) 55 | set(TestBinaries ${TestBinaries} LLVMFuzzer-${name} PARENT_SCOPE) 56 | endfunction() 57 | 58 | # Variable to keep track of all test targets 59 | set(TestBinaries) 60 | 61 | ############################################################################### 62 | # Basic tests 63 | ############################################################################### 64 | 65 | set(Tests 66 | AbsNegAndConstantTest 67 | AbsNegAndConstant64Test 68 | AccumulateAllocationsTest 69 | BufferOverflowOnInput 70 | CallerCalleeTest 71 | CounterTest 72 | CustomCrossOverTest 73 | CustomMutatorTest 74 | DivTest 75 | EmptyTest 76 | FourIndependentBranchesTest 77 | FullCoverageSetTest 78 | InitializeTest 79 | MemcmpTest 80 | LeakTest 81 | LeakTimeoutTest 82 | LoadTest 83 | NullDerefTest 84 | NullDerefOnEmptyTest 85 | NthRunCrashTest 86 | OneHugeAllocTest 87 | OutOfMemoryTest 88 | RepeatedMemcmp 89 | RepeatedBytesTest 90 | SimpleCmpTest 91 | SimpleDictionaryTest 92 | SimpleFnAdapterTest 93 | SimpleHashTest 94 | SimpleTest 95 | SimpleThreadedTest 96 | SingleMemcmpTest 97 | SingleStrcmpTest 98 | SingleStrncmpTest 99 | SpamyTest 100 | ShrinkControlFlowTest 101 | ShrinkValueProfileTest 102 | StrcmpTest 103 | StrncmpOOBTest 104 | StrncmpTest 105 | StrstrTest 106 | SwapCmpTest 107 | SwitchTest 108 | ThreadedLeakTest 109 | ThreadedTest 110 | TimeoutTest 111 | TraceMallocTest 112 | ) 113 | 114 | if(APPLE) 115 | # LeakSanitizer is not supported on OSX right now 116 | set(HAS_LSAN 0) 117 | message(WARNING "LeakSanitizer is not supported on Apple platforms." 118 | " Building and running LibFuzzer LeakSanitizer tests is disabled." 119 | ) 120 | else() 121 | set(HAS_LSAN 1) 122 | endif() 123 | 124 | foreach(Test ${Tests}) 125 | add_libfuzzer_test(${Test} SOURCES ${Test}.cpp) 126 | endforeach() 127 | 128 | 129 | ############################################################################### 130 | # Unit tests 131 | ############################################################################### 132 | 133 | add_executable(LLVMFuzzer-Unittest 134 | FuzzerUnittest.cpp 135 | FuzzerFnAdapterUnittest.cpp 136 | ) 137 | 138 | add_executable(LLVMFuzzer-StandaloneInitializeTest 139 | InitializeTest.cpp 140 | ../standalone/StandaloneFuzzTargetMain.c 141 | ) 142 | 143 | target_link_libraries(LLVMFuzzer-Unittest 144 | gtest 145 | gtest_main 146 | LLVMFuzzerNoMain 147 | ) 148 | 149 | target_include_directories(LLVMFuzzer-Unittest PRIVATE 150 | "${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include" 151 | ) 152 | 153 | set(TestBinaries ${TestBinaries} LLVMFuzzer-Unittest) 154 | set_target_properties(LLVMFuzzer-Unittest 155 | PROPERTIES RUNTIME_OUTPUT_DIRECTORY 156 | "${CMAKE_CURRENT_BINARY_DIR}" 157 | ) 158 | 159 | set(TestBinaries ${TestBinaries} LLVMFuzzer-StandaloneInitializeTest) 160 | set_target_properties(LLVMFuzzer-StandaloneInitializeTest 161 | PROPERTIES RUNTIME_OUTPUT_DIRECTORY 162 | "${CMAKE_CURRENT_BINARY_DIR}" 163 | ) 164 | 165 | ############################################################################### 166 | # Additional tests 167 | ############################################################################### 168 | 169 | include_directories(..) 170 | 171 | add_subdirectory(uninstrumented) 172 | add_subdirectory(no-coverage) 173 | add_subdirectory(ubsan) 174 | add_subdirectory(trace-bb) 175 | add_subdirectory(trace-pc) 176 | 177 | ############################################################################### 178 | # Configure lit to run the tests 179 | # 180 | # Note this is done after declaring all tests so we can inform lit if any tests 181 | # need to be disabled. 182 | ############################################################################### 183 | 184 | configure_lit_site_cfg( 185 | ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in 186 | ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg 187 | ) 188 | 189 | configure_lit_site_cfg( 190 | ${CMAKE_CURRENT_SOURCE_DIR}/unit/lit.site.cfg.in 191 | ${CMAKE_CURRENT_BINARY_DIR}/unit/lit.site.cfg 192 | ) 193 | 194 | add_lit_testsuite(check-fuzzer "Running Fuzzer tests" 195 | ${CMAKE_CURRENT_BINARY_DIR} 196 | DEPENDS ${TestBinaries} FileCheck not 197 | ) 198 | -------------------------------------------------------------------------------- /Fuzzer/test/CallerCalleeTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. 5 | // Try to find the target using the indirect caller-callee pairs. 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | typedef void (*F)(); 13 | static F t[256]; 14 | 15 | void f34() { 16 | std::cerr << "BINGO\n"; 17 | exit(1); 18 | } 19 | void f23() { t[(unsigned)'d'] = f34;} 20 | void f12() { t[(unsigned)'c'] = f23;} 21 | void f01() { t[(unsigned)'b'] = f12;} 22 | void f00() {} 23 | 24 | static F t0[256] = { 25 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 26 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 27 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 28 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 29 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 30 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 31 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 32 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 33 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 34 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 35 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 36 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 37 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 38 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 39 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 40 | f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, 41 | }; 42 | 43 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 44 | if (Size < 4) return 0; 45 | // Spoof the counters. 46 | for (int i = 0; i < 200; i++) { 47 | f23(); 48 | f12(); 49 | f01(); 50 | } 51 | memcpy(t, t0, sizeof(t)); 52 | t[(unsigned)'a'] = f01; 53 | t[Data[0]](); 54 | t[Data[1]](); 55 | t[Data[2]](); 56 | t[Data[3]](); 57 | return 0; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /Fuzzer/test/CounterTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Test for a fuzzer: must find the case where a particular basic block is 5 | // executed many times. 6 | #include 7 | 8 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 9 | int Num = 0; 10 | for (size_t i = 0; i < Size; i++) 11 | if (Data[i] == 'A' + i) 12 | Num++; 13 | if (Num >= 4) { 14 | std::cerr << "BINGO!\n"; 15 | exit(1); 16 | } 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /Fuzzer/test/CustomCrossOverTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a cutom mutator. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "FuzzerInterface.h" 14 | 15 | static const char *Separator = "-_^_-"; 16 | static const char *Target = "012-_^_-abc"; 17 | 18 | static volatile int sink; 19 | 20 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 21 | assert(Data); 22 | std::string Str(reinterpret_cast(Data), Size); 23 | 24 | // Ensure that two different elements exist in the corpus. 25 | if (Size && Data[0] == '0') sink++; 26 | if (Size && Data[0] == 'a') sink--; 27 | 28 | if (Str.find(Target) != std::string::npos) { 29 | std::cout << "BINGO; Found the target, exiting\n"; 30 | exit(1); 31 | } 32 | return 0; 33 | } 34 | 35 | extern "C" size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, 36 | const uint8_t *Data2, size_t Size2, 37 | uint8_t *Out, size_t MaxOutSize, 38 | unsigned int Seed) { 39 | static bool Printed; 40 | static size_t SeparatorLen = strlen(Separator); 41 | 42 | if (!Printed) { 43 | std::cerr << "In LLVMFuzzerCustomCrossover\n"; 44 | Printed = true; 45 | } 46 | 47 | std::mt19937 R(Seed); 48 | 49 | size_t Offset1 = 0; 50 | size_t Len1 = R() % (Size1 - Offset1); 51 | size_t Offset2 = 0; 52 | size_t Len2 = R() % (Size2 - Offset2); 53 | size_t Size = Len1 + Len2 + SeparatorLen; 54 | 55 | if (Size > MaxOutSize) 56 | return 0; 57 | 58 | memcpy(Out, Data1 + Offset1, Len1); 59 | memcpy(Out + Len1, Separator, SeparatorLen); 60 | memcpy(Out + Len1 + SeparatorLen, Data2 + Offset2, Len2); 61 | 62 | return Len1 + Len2 + SeparatorLen; 63 | } 64 | -------------------------------------------------------------------------------- /Fuzzer/test/CustomMutatorTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a cutom mutator. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "FuzzerInterface.h" 12 | 13 | static volatile int Sink; 14 | 15 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 16 | assert(Data); 17 | if (Size > 0 && Data[0] == 'H') { 18 | Sink = 1; 19 | if (Size > 1 && Data[1] == 'i') { 20 | Sink = 2; 21 | if (Size > 2 && Data[2] == '!') { 22 | std::cout << "BINGO; Found the target, exiting\n"; 23 | exit(1); 24 | } 25 | } 26 | } 27 | return 0; 28 | } 29 | 30 | extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, 31 | size_t MaxSize, unsigned int Seed) { 32 | static bool Printed; 33 | if (!Printed) { 34 | std::cerr << "In LLVMFuzzerCustomMutator\n"; 35 | Printed = true; 36 | } 37 | return LLVMFuzzerMutate(Data, Size, MaxSize); 38 | } 39 | -------------------------------------------------------------------------------- /Fuzzer/test/DSO1.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Source code for a simple DSO. 5 | 6 | int DSO1(int a) { 7 | if (a < 123456) 8 | return 0; 9 | return 1; 10 | } 11 | 12 | void Uncovered1() { } 13 | -------------------------------------------------------------------------------- /Fuzzer/test/DSO2.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Source code for a simple DSO. 5 | 6 | int DSO2(int a) { 7 | if (a < 3598235) 8 | return 0; 9 | return 1; 10 | } 11 | 12 | void Uncovered2() {} 13 | -------------------------------------------------------------------------------- /Fuzzer/test/DSOTestExtra.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Source code for a simple DSO. 5 | 6 | int DSOTestExtra(int a) { 7 | if (a < 452345) 8 | return 0; 9 | return 1; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /Fuzzer/test/DSOTestMain.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Source code for a simple DSO. 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | extern int DSO1(int a); 11 | extern int DSO2(int a); 12 | extern int DSOTestExtra(int a); 13 | 14 | static volatile int *nil = 0; 15 | 16 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 17 | int x, y, z; 18 | if (Size < sizeof(int) * 3) { 19 | x = y = z = 0; 20 | } else { 21 | memcpy(&x, Data + 0 * sizeof(int), sizeof(int)); 22 | memcpy(&y, Data + 1 * sizeof(int), sizeof(int)); 23 | memcpy(&z, Data + 2 * sizeof(int), sizeof(int)); 24 | } 25 | int sum = DSO1(x) + DSO2(y) + (z ? DSOTestExtra(z) : 0); 26 | if (sum == 3) { 27 | fprintf(stderr, "BINGO %d %d %d\n", x, y, z); 28 | *nil = 0; 29 | } 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /Fuzzer/test/DivTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer: find the interesting argument for div. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static volatile int Sink; 12 | 13 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 14 | if (Size < 4) return 0; 15 | int a; 16 | memcpy(&a, Data, 4); 17 | Sink = 12345678 / (987654 - a); 18 | return 0; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /Fuzzer/test/EmptyTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | // 4 | // A fuzzer with empty target function. 5 | 6 | #include 7 | #include 8 | 9 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /Fuzzer/test/FourIndependentBranchesTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find the string "FUZZ". 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 11 | int bits = 0; 12 | if (Size > 0 && Data[0] == 'F') bits |= 1; 13 | if (Size > 1 && Data[1] == 'U') bits |= 2; 14 | if (Size > 2 && Data[2] == 'Z') bits |= 4; 15 | if (Size > 3 && Data[3] == 'Z') bits |= 8; 16 | if (bits == 15) { 17 | std::cerr << "BINGO!\n"; 18 | exit(1); 19 | } 20 | return 0; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Fuzzer/test/FullCoverageSetTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find the string "FUZZER". 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 11 | int bits = 0; 12 | if (Size > 0 && Data[0] == 'F') bits |= 1; 13 | if (Size > 1 && Data[1] == 'U') bits |= 2; 14 | if (Size > 2 && Data[2] == 'Z') bits |= 4; 15 | if (Size > 3 && Data[3] == 'Z') bits |= 8; 16 | if (Size > 4 && Data[4] == 'E') bits |= 16; 17 | if (Size > 5 && Data[5] == 'R') bits |= 32; 18 | if (bits == 63) { 19 | std::cerr << "BINGO!\n"; 20 | exit(1); 21 | } 22 | return 0; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /Fuzzer/test/FuzzerFnAdapterUnittest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | #include "FuzzerFnAdapter.h" 5 | #include "gtest/gtest-spi.h" 6 | #include "gtest/gtest.h" 7 | 8 | namespace fuzzer { 9 | namespace impl { 10 | 11 | template 12 | bool Unpack(std::tuple *Tuple, std::initializer_list data) { 13 | std::vector V(data); 14 | return Unpack(V.data(), V.size(), Tuple); 15 | } 16 | 17 | TEST(Unpack, Bool) { 18 | std::tuple T; 19 | EXPECT_TRUE(Unpack(&T, {1})); 20 | EXPECT_TRUE(std::get<0>(T)); 21 | 22 | EXPECT_TRUE(Unpack(&T, {0})); 23 | EXPECT_FALSE(std::get<0>(T)); 24 | 25 | EXPECT_FALSE(Unpack(&T, {})); 26 | } 27 | 28 | TEST(Unpack, BoolBool) { 29 | std::tuple T; 30 | EXPECT_TRUE(Unpack(&T, {1, 0})); 31 | EXPECT_TRUE(std::get<0>(T)); 32 | EXPECT_FALSE(std::get<1>(T)); 33 | 34 | EXPECT_TRUE(Unpack(&T, {0, 1})); 35 | EXPECT_FALSE(std::get<0>(T)); 36 | EXPECT_TRUE(std::get<1>(T)); 37 | 38 | EXPECT_FALSE(Unpack(&T, {})); 39 | EXPECT_FALSE(Unpack(&T, {10})); 40 | } 41 | 42 | TEST(Unpack, BoolInt) { 43 | std::tuple T; 44 | EXPECT_TRUE(Unpack(&T, {1, 16, 2, 0, 0})); 45 | EXPECT_TRUE(std::get<0>(T)); 46 | EXPECT_EQ(528, std::get<1>(T)); 47 | 48 | EXPECT_FALSE(Unpack(&T, {1, 2})); 49 | } 50 | 51 | TEST(Unpack, Vector) { 52 | std::tuple> T; 53 | const auto &V = std::get<0>(T); 54 | 55 | EXPECT_FALSE(Unpack(&T, {})); 56 | 57 | EXPECT_TRUE(Unpack(&T, {0})); 58 | EXPECT_EQ(0ul, V.size()); 59 | 60 | EXPECT_TRUE(Unpack(&T, {0, 1, 2, 3})); 61 | EXPECT_EQ(0ul, V.size()); 62 | 63 | EXPECT_TRUE(Unpack(&T, {2})); 64 | EXPECT_EQ(0ul, V.size()); 65 | 66 | EXPECT_TRUE(Unpack(&T, {2, 3})); 67 | EXPECT_EQ(1ul, V.size()); 68 | EXPECT_EQ(3, V[0]); 69 | 70 | EXPECT_TRUE(Unpack(&T, {2, 9, 8})); 71 | EXPECT_EQ(2ul, V.size()); 72 | EXPECT_EQ(9, V[0]); 73 | EXPECT_EQ(8, V[1]); 74 | } 75 | 76 | TEST(Unpack, String) { 77 | std::tuple T; 78 | const auto &S = std::get<0>(T); 79 | 80 | EXPECT_TRUE(Unpack(&T, {2, 3})); 81 | EXPECT_EQ(1ul, S.size()); 82 | EXPECT_EQ(3, S[0]); 83 | } 84 | 85 | template 86 | bool UnpackAndApply(Fn F, std::initializer_list Data) { 87 | std::vector V(Data); 88 | return UnpackAndApply(F, V.data(), V.size()); 89 | } 90 | 91 | static void fnBool(bool b) { EXPECT_TRUE(b); } 92 | 93 | TEST(Apply, Bool) { 94 | EXPECT_FALSE(UnpackAndApply(fnBool, {})); 95 | EXPECT_TRUE(UnpackAndApply(fnBool, {1})); 96 | EXPECT_NONFATAL_FAILURE(UnpackAndApply(fnBool, {0}), 97 | "Actual: false\nExpected: true"); 98 | } 99 | 100 | static void fnInt(int i) { EXPECT_EQ(42, i); } 101 | 102 | TEST(Apply, Int) { 103 | EXPECT_FALSE(UnpackAndApply(fnInt, {})); 104 | EXPECT_TRUE(UnpackAndApply(fnInt, {42, 0, 0, 0})); 105 | EXPECT_NONFATAL_FAILURE(UnpackAndApply(fnInt, {10, 0, 0, 0}), 106 | "Actual: 10\nExpected: 42"); 107 | } 108 | 109 | } // namespace impl 110 | } // namespace fuzzer 111 | -------------------------------------------------------------------------------- /Fuzzer/test/InitializeTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Make sure LLVMFuzzerInitialize is called. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static char *argv0; 13 | 14 | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { 15 | assert(*argc > 0); 16 | argv0 = **argv; 17 | fprintf(stderr, "LLVMFuzzerInitialize: %s\n", argv0); 18 | return 0; 19 | } 20 | 21 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 22 | if (Size == strlen(argv0) && 23 | !strncmp(reinterpret_cast(Data), argv0, Size)) { 24 | fprintf(stderr, "BINGO %s\n", argv0); 25 | exit(1); 26 | } 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /Fuzzer/test/LeakTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Test with a leak. 5 | #include 6 | #include 7 | 8 | static volatile void *Sink; 9 | 10 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 11 | if (Size > 0 && *Data == 'H') { 12 | Sink = new int; 13 | Sink = nullptr; 14 | } 15 | return 0; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Fuzzer/test/LeakTimeoutTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Test with a leak. 5 | #include 6 | #include 7 | 8 | static volatile int *Sink; 9 | 10 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 11 | if (!Size) return 0; 12 | Sink = new int; 13 | Sink = new int; 14 | while (Sink) *Sink = 0; // Infinite loop. 15 | return 0; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Fuzzer/test/LoadTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer: find interesting value of array index. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static volatile int Sink; 12 | const int kArraySize = 1234567; 13 | int array[kArraySize]; 14 | 15 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 16 | if (Size < 8) return 0; 17 | size_t a = 0; 18 | memcpy(&a, Data, 8); 19 | Sink = array[a % (kArraySize + 1)]; 20 | return 0; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Fuzzer/test/MemcmpTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find a particular string. 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 11 | // TODO: check other sizes. 12 | if (Size >= 8 && memcmp(Data, "01234567", 8) == 0) { 13 | if (Size >= 12 && memcmp(Data + 8, "ABCD", 4) == 0) { 14 | if (Size >= 14 && memcmp(Data + 12, "XY", 2) == 0) { 15 | if (Size >= 17 && memcmp(Data + 14, "KLM", 3) == 0) { 16 | if (Size >= 27 && memcmp(Data + 17, "ABCDE-GHIJ", 10) == 0){ 17 | fprintf(stderr, "BINGO %zd\n", Size); 18 | for (size_t i = 0; i < Size; i++) { 19 | uint8_t C = Data[i]; 20 | if (C >= 32 && C < 127) 21 | fprintf(stderr, "%c", C); 22 | } 23 | fprintf(stderr, "\n"); 24 | exit(1); 25 | } 26 | } 27 | } 28 | } 29 | } 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /Fuzzer/test/NthRunCrashTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Crash on the N-th execution. 5 | #include 6 | #include 7 | #include 8 | 9 | static int Counter; 10 | 11 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 12 | if (Counter++ == 1000) { 13 | std::cout << "BINGO; Found the target, exiting\n"; 14 | exit(1); 15 | } 16 | return 0; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /Fuzzer/test/NullDerefOnEmptyTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find the empty string. 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static volatile int *Null = 0; 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 13 | if (Size == 0) { 14 | std::cout << "Found the target, dereferencing NULL\n"; 15 | *Null = 1; 16 | } 17 | return 0; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /Fuzzer/test/NullDerefTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find the string "Hi!". 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static volatile int Sink; 11 | static volatile int *Null = 0; 12 | 13 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 14 | if (Size > 0 && Data[0] == 'H') { 15 | Sink = 1; 16 | if (Size > 1 && Data[1] == 'i') { 17 | Sink = 2; 18 | if (Size > 2 && Data[2] == '!') { 19 | std::cout << "Found the target, dereferencing NULL\n"; 20 | *Null = 1; 21 | } 22 | } 23 | } 24 | return 0; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /Fuzzer/test/OneHugeAllocTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Tests OOM handling when there is a single large allocation. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static volatile char *SinkPtr; 14 | 15 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 16 | if (Size > 0 && Data[0] == 'H') { 17 | if (Size > 1 && Data[1] == 'i') { 18 | if (Size > 2 && Data[2] == '!') { 19 | size_t kSize = (size_t)1 << 31; 20 | char *p = new char[kSize]; 21 | memset(p, 0, kSize); 22 | SinkPtr = p; 23 | delete [] p; 24 | } 25 | } 26 | } 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /Fuzzer/test/OutOfMemoryTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Tests OOM handling. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static volatile char *SinkPtr; 14 | 15 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 16 | if (Size > 0 && Data[0] == 'H') { 17 | if (Size > 1 && Data[1] == 'i') { 18 | if (Size > 2 && Data[2] == '!') { 19 | while (true) { 20 | size_t kSize = 1 << 28; 21 | char *p = new char[kSize]; 22 | memset(p, 0, kSize); 23 | SinkPtr = p; 24 | sleep(1); 25 | } 26 | } 27 | } 28 | } 29 | return 0; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /Fuzzer/test/RepeatedBytesTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find repeated bytes. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 12 | assert(Data); 13 | // Looking for AAAAAAAAAAAAAAAAAAAAAA or some such. 14 | size_t CurA = 0, MaxA = 0; 15 | for (size_t i = 0; i < Size; i++) { 16 | // Make sure there are no conditionals in the loop so that 17 | // coverage can't help the fuzzer. 18 | int EQ = Data[i] == 'A'; 19 | CurA = EQ * (CurA + 1); 20 | int GT = CurA > MaxA; 21 | MaxA = GT * CurA + (!GT) * MaxA; 22 | } 23 | if (MaxA >= 20) { 24 | std::cout << "BINGO; Found the target (Max: " << MaxA << "), exiting\n"; 25 | exit(0); 26 | } 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /Fuzzer/test/RepeatedMemcmp.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 11 | int Matches = 0; 12 | for (size_t i = 0; i + 2 < Size; i += 3) { 13 | const char *Pat = i % 2 ? "foo" : "bar"; 14 | if (!memcmp(Data + i, Pat, 3)) 15 | Matches++; 16 | } 17 | if (Matches > 20) { 18 | fprintf(stderr, "BINGO!\n"); 19 | exit(1); 20 | } 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /Fuzzer/test/ShrinkControlFlowTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Test that we can find the minimal item in the corpus (3 bytes: "FUZ"). 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static volatile int Sink; 12 | 13 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 14 | int8_t Ids[256]; 15 | memset(Ids, -1, sizeof(Ids)); 16 | for (size_t i = 0; i < Size; i++) 17 | if (Ids[Data[i]] == -1) 18 | Ids[Data[i]] = i; 19 | int F = Ids[(unsigned char)'F']; 20 | int U = Ids[(unsigned char)'U']; 21 | int Z = Ids[(unsigned char)'Z']; 22 | if (F >= 0 && U > F && Z > U) { 23 | Sink++; 24 | //fprintf(stderr, "IDS: %d %d %d\n", F, U, Z); 25 | } 26 | return 0; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /Fuzzer/test/ShrinkValueProfileTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Test that we can find the minimal item in the corpus (3 bytes: "FUZ"). 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static volatile uint32_t Sink; 12 | 13 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 14 | if (Size < sizeof(uint32_t)) return 0; 15 | uint32_t X, Y; 16 | size_t Offset = Size < 8 ? 0 : Size / 2; 17 | memcpy(&X, Data + Offset, sizeof(uint32_t)); 18 | memcpy(&Y, "FUZZ", sizeof(uint32_t)); 19 | Sink = X == Y; 20 | return 0; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Fuzzer/test/SignedIntOverflowTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Test for signed-integer-overflow. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static volatile int Sink; 13 | static int Large = INT_MAX; 14 | 15 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 16 | assert(Data); 17 | if (Size > 0 && Data[0] == 'H') { 18 | Sink = 1; 19 | if (Size > 1 && Data[1] == 'i') { 20 | Sink = 2; 21 | if (Size > 2 && Data[2] == '!') { 22 | Large++; // int overflow. 23 | } 24 | } 25 | } 26 | return 0; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /Fuzzer/test/SimpleCmpTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find several narrow ranges. 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 11 | if (Size < 14) return 0; 12 | uint64_t x = 0; 13 | int64_t y = 0; 14 | int z = 0; 15 | unsigned short a = 0; 16 | memcpy(&x, Data, 8); 17 | memcpy(&y, Data + Size - 8, 8); 18 | memcpy(&z, Data + Size / 2, sizeof(z)); 19 | memcpy(&a, Data + Size / 2 + 4, sizeof(a)); 20 | 21 | if (x > 1234567890 && 22 | x < 1234567895 && 23 | y >= 987654321 && 24 | y <= 987654325 && 25 | z < -10000 && 26 | z >= -10005 && 27 | z != -10003 && 28 | a == 4242 && 29 | true) { 30 | fprintf(stderr, "BINGO; Found the target: size %zd (%zd, %zd, %d, %d), exiting.\n", 31 | Size, x, y, z, a); 32 | exit(1); 33 | } 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /Fuzzer/test/SimpleDictionaryTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. 5 | // The fuzzer must find a string based on dictionary words: 6 | // "Elvis" 7 | // "Presley" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | static volatile int Zero = 0; 15 | 16 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 17 | const char *Expected = "ElvisPresley"; 18 | if (Size < strlen(Expected)) return 0; 19 | size_t Match = 0; 20 | for (size_t i = 0; Expected[i]; i++) 21 | if (Expected[i] + Zero == Data[i]) 22 | Match++; 23 | if (Match == strlen(Expected)) { 24 | std::cout << "BINGO; Found the target, exiting\n"; 25 | exit(1); 26 | } 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /Fuzzer/test/SimpleFnAdapterTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer Fn adapter. The fuzzer has to find two non-empty 5 | // vectors with the same content. 6 | 7 | #include 8 | #include 9 | 10 | #include "FuzzerFnAdapter.h" 11 | 12 | static void TestFn(std::vector V1, std::vector V2) { 13 | if (V1.size() > 0 && V1 == V2) { 14 | std::cout << "BINGO; Found the target, exiting\n"; 15 | exit(0); 16 | } 17 | } 18 | 19 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 20 | fuzzer::Adapt(TestFn, Data, Size); 21 | return 0; 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /Fuzzer/test/SimpleHashTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // This test computes a checksum of the data (all but the last 4 bytes), 5 | // and then compares the last 4 bytes with the computed value. 6 | // A fuzzer with cmp traces is expected to defeat this check. 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // A modified jenkins_one_at_a_time_hash initialized by non-zero, 13 | // so that simple_hash(0) != 0. See also 14 | // https://en.wikipedia.org/wiki/Jenkins_hash_function 15 | static uint32_t simple_hash(const uint8_t *Data, size_t Size) { 16 | uint32_t Hash = 0x12039854; 17 | for (uint32_t i = 0; i < Size; i++) { 18 | Hash += Data[i]; 19 | Hash += (Hash << 10); 20 | Hash ^= (Hash >> 6); 21 | } 22 | Hash += (Hash << 3); 23 | Hash ^= (Hash >> 11); 24 | Hash += (Hash << 15); 25 | return Hash; 26 | } 27 | 28 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 29 | if (Size < 14) 30 | return 0; 31 | 32 | uint32_t Hash = simple_hash(&Data[0], Size - 4); 33 | uint32_t Want = reinterpret_cast(&Data[Size - 4])[0]; 34 | if (Hash != Want) 35 | return 0; 36 | fprintf(stderr, "BINGO; simple_hash defeated: %x == %x\n", (unsigned int)Hash, 37 | (unsigned int)Want); 38 | exit(1); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /Fuzzer/test/SimpleTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find the string "Hi!". 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static volatile int Sink; 12 | 13 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 14 | assert(Data); 15 | if (Size > 0 && Data[0] == 'H') { 16 | Sink = 1; 17 | if (Size > 1 && Data[1] == 'i') { 18 | Sink = 2; 19 | if (Size > 2 && Data[2] == '!') { 20 | std::cout << "BINGO; Found the target, exiting\n"; 21 | exit(0); 22 | } 23 | } 24 | } 25 | return 0; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /Fuzzer/test/SimpleThreadedTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Threaded test for a fuzzer. The fuzzer should find "H" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 13 | auto C = [&] { 14 | if (Size >= 2 && Data[0] == 'H') { 15 | std::cout << "BINGO; Found the target, exiting\n"; 16 | abort(); 17 | } 18 | }; 19 | std::thread T[] = {std::thread(C), std::thread(C), std::thread(C), 20 | std::thread(C), std::thread(C), std::thread(C)}; 21 | for (auto &X : T) 22 | X.join(); 23 | return 0; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /Fuzzer/test/SingleMemcmpTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find a particular string. 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 11 | char *S = (char*)Data; 12 | if (Size >= 6 && !memcmp(S, "qwerty", 6)) { 13 | fprintf(stderr, "BINGO\n"); 14 | exit(1); 15 | } 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /Fuzzer/test/SingleStrcmpTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find a particular string. 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 11 | char *S = (char*)Data; 12 | if (Size >= 7 && !strcmp(S, "qwerty")) { 13 | fprintf(stderr, "BINGO\n"); 14 | exit(1); 15 | } 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /Fuzzer/test/SingleStrncmpTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find a particular string. 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 11 | char *S = (char*)Data; 12 | if (Size >= 6 && !strncmp(S, "qwerty", 6)) { 13 | fprintf(stderr, "BINGO\n"); 14 | exit(1); 15 | } 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /Fuzzer/test/SpamyTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // The test spams to stderr and stdout. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 12 | assert(Data); 13 | printf("PRINTF_STDOUT\n"); 14 | fflush(stdout); 15 | fprintf(stderr, "PRINTF_STDERR\n"); 16 | std::cout << "STREAM_COUT\n"; 17 | std::cout.flush(); 18 | std::cerr << "STREAM_CERR\n"; 19 | return 0; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /Fuzzer/test/StrcmpTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Break through a series of strcmp. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | bool Eq(const uint8_t *Data, size_t Size, const char *Str) { 12 | char Buff[1024]; 13 | size_t Len = strlen(Str); 14 | if (Size < Len) return false; 15 | if (Len >= sizeof(Buff)) return false; 16 | memcpy(Buff, (char*)Data, Len); 17 | Buff[Len] = 0; 18 | int res = strcmp(Buff, Str); 19 | return res == 0; 20 | } 21 | 22 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 23 | if (Eq(Data, Size, "ABC") && 24 | Size >= 3 && Eq(Data + 3, Size - 3, "QWER") && 25 | Size >= 7 && Eq(Data + 7, Size - 7, "ZXCVN") && 26 | Size >= 14 && Data[13] == 42 27 | ) { 28 | fprintf(stderr, "BINGO\n"); 29 | exit(1); 30 | } 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /Fuzzer/test/StrncmpOOBTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Test that libFuzzer itself does not read out of bounds. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static volatile int Sink; 13 | 14 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 15 | if (Size < 5) return 0; 16 | const char *Ch = reinterpret_cast(Data); 17 | if (Ch[Size - 3] == 'a') 18 | Sink = strncmp(Ch + Size - 3, "abcdefg", 6); 19 | return 0; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /Fuzzer/test/StrncmpTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find a particular string. 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static volatile int sink; 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 13 | // TODO: check other sizes. 14 | char *S = (char*)Data; 15 | if (Size >= 8 && strncmp(S, "123", 8)) 16 | sink = 1; 17 | if (Size >= 8 && strncmp(S, "01234567", 8) == 0) { 18 | if (Size >= 12 && strncmp(S + 8, "ABCD", 4) == 0) { 19 | if (Size >= 14 && strncmp(S + 12, "XY", 2) == 0) { 20 | if (Size >= 17 && strncmp(S + 14, "KLM", 3) == 0) { 21 | fprintf(stderr, "BINGO\n"); 22 | exit(1); 23 | } 24 | } 25 | } 26 | } 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /Fuzzer/test/StrstrTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Test strstr and strcasestr hooks. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 12 | if (Size < 4) return 0; 13 | std::string s(reinterpret_cast(Data), Size); 14 | if (strstr(s.c_str(), "FUZZ") && 15 | strcasestr(s.c_str(), "aBcD") && 16 | memmem(s.data(), s.size(), "kuku", 4) 17 | ) { 18 | fprintf(stderr, "BINGO\n"); 19 | exit(1); 20 | } 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /Fuzzer/test/SwapCmpTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // The fuzzer must find several constants with swapped bytes. 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 11 | if (Size < 14) return 0; 12 | uint64_t x = 0; 13 | uint32_t y = 0; 14 | uint16_t z = 0; 15 | memcpy(&x, Data, sizeof(x)); 16 | memcpy(&y, Data + Size / 2, sizeof(y)); 17 | memcpy(&z, Data + Size - sizeof(z), sizeof(z)); 18 | 19 | x = __builtin_bswap64(x); 20 | y = __builtin_bswap32(y); 21 | z = __builtin_bswap16(z); 22 | 23 | if (x == 0x46555A5A5A5A5546ULL && 24 | z == 0x4F4B && 25 | y == 0x66757A7A && 26 | true 27 | ) { 28 | if (Data[Size - 3] == 'z') { 29 | fprintf(stderr, "BINGO; Found the target\n"); 30 | exit(1); 31 | } 32 | } 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /Fuzzer/test/Switch2Test.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find the interesting switch value. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int Switch(int a) { 12 | switch(a) { 13 | case 100001: return 1; 14 | case 100002: return 2; 15 | case 100003: return 4; 16 | } 17 | return 0; 18 | } 19 | 20 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 21 | const int N = 3; 22 | if (Size < N * sizeof(int)) return 0; 23 | int Res = 0; 24 | for (int i = 0; i < N; i++) { 25 | int X; 26 | memcpy(&X, Data + i * sizeof(int), sizeof(int)); 27 | Res += Switch(X); 28 | } 29 | if (Res == 5 || Res == 3 || Res == 6 || Res == 7) { 30 | fprintf(stderr, "BINGO; Found the target, exiting; Res=%d\n", Res); 31 | exit(1); 32 | } 33 | return 0; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /Fuzzer/test/SwitchTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find the interesting switch value. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static volatile int Sink; 12 | 13 | template 14 | bool Switch(const uint8_t *Data, size_t Size) { 15 | T X; 16 | if (Size < sizeof(X)) return false; 17 | memcpy(&X, Data, sizeof(X)); 18 | switch (X) { 19 | case 1: Sink = __LINE__; break; 20 | case 101: Sink = __LINE__; break; 21 | case 1001: Sink = __LINE__; break; 22 | case 10001: Sink = __LINE__; break; 23 | case 100001: Sink = __LINE__; break; 24 | case 1000001: Sink = __LINE__; break; 25 | case 10000001: Sink = __LINE__; break; 26 | case 100000001: return true; 27 | } 28 | return false; 29 | } 30 | 31 | bool ShortSwitch(const uint8_t *Data, size_t Size) { 32 | short X; 33 | if (Size < sizeof(short)) return false; 34 | memcpy(&X, Data, sizeof(short)); 35 | switch(X) { 36 | case 42: Sink = __LINE__; break; 37 | case 402: Sink = __LINE__; break; 38 | case 4002: Sink = __LINE__; break; 39 | case 5002: Sink = __LINE__; break; 40 | case 7002: Sink = __LINE__; break; 41 | case 9002: Sink = __LINE__; break; 42 | case 14002: Sink = __LINE__; break; 43 | case 21402: return true; 44 | } 45 | return false; 46 | } 47 | 48 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 49 | if (Size >= 4 && Switch(Data, Size) && 50 | Size >= 12 && Switch(Data + 4, Size - 4) && 51 | Size >= 14 && ShortSwitch(Data + 12, 2) 52 | ) { 53 | fprintf(stderr, "BINGO; Found the target, exiting\n"); 54 | exit(1); 55 | } 56 | return 0; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /Fuzzer/test/ThreadedLeakTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // The fuzzer should find a leak in a non-main thread. 5 | #include 6 | #include 7 | #include 8 | 9 | static volatile int *Sink; 10 | 11 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 12 | if (Size == 0) return 0; 13 | if (Data[0] != 'F') return 0; 14 | std::thread T([&] { Sink = new int; }); 15 | T.join(); 16 | return 0; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /Fuzzer/test/ThreadedTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Threaded test for a fuzzer. The fuzzer should not crash. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 12 | if (Size < 8) return 0; 13 | assert(Data); 14 | auto C = [&] { 15 | size_t Res = 0; 16 | for (size_t i = 0; i < Size / 2; i++) 17 | Res += memcmp(Data, Data + Size / 2, 4); 18 | return Res; 19 | }; 20 | std::thread T[] = {std::thread(C), std::thread(C), std::thread(C), 21 | std::thread(C), std::thread(C), std::thread(C)}; 22 | for (auto &X : T) 23 | X.join(); 24 | return 0; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /Fuzzer/test/TimeoutTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Simple test for a fuzzer. The fuzzer must find the string "Hi!". 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static volatile int Sink; 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 13 | if (Size > 0 && Data[0] == 'H') { 14 | Sink = 1; 15 | if (Size > 1 && Data[1] == 'i') { 16 | Sink = 2; 17 | if (Size > 2 && Data[2] == '!') { 18 | Sink = 2; 19 | while (Sink) 20 | ; 21 | } 22 | } 23 | } 24 | return 0; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /Fuzzer/test/TraceMallocTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // Tests -trace_malloc 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int *Ptr; 12 | 13 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 14 | if (!Size) return 0; 15 | if (*Data == 1) { 16 | delete Ptr; 17 | Ptr = nullptr; 18 | } else if (*Data == 2) { 19 | delete Ptr; 20 | Ptr = new int; 21 | } else if (*Data == 3) { 22 | if (!Ptr) 23 | Ptr = new int; 24 | } 25 | return 0; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /Fuzzer/test/UninstrumentedTest.cpp: -------------------------------------------------------------------------------- 1 | // This file is distributed under the University of Illinois Open Source 2 | // License. See LICENSE.TXT for details. 3 | 4 | // This test should not be instrumented. 5 | #include 6 | #include 7 | 8 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 9 | return 0; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /Fuzzer/test/afl-driver-extra-stats.test: -------------------------------------------------------------------------------- 1 | ; Test that not specifying an extra stats file isn't broken. 2 | RUN: unset AFL_DRIVER_EXTRA_STATS_FILENAME 3 | RUN: AFLDriverTest 4 | 5 | ; Test that specifying an invalid extra stats file causes a crash. 6 | RUN: ASAN_OPTIONS= AFL_DRIVER_EXTRA_STATS_FILENAME=%T not --crash AFLDriverTest 7 | 8 | ; Test that specifying a corrupted stats file causes a crash. 9 | echo "peak_rss_mb :0" > %t 10 | ASAN_OPTIONS= AFL_DRIVER_EXTRA_STATS_FILENAME=%t not --crash AFLDriverTest 11 | 12 | ; Test that specifying a valid nonexistent stats file works. 13 | RUN: rm -f %t 14 | RUN: AFL_DRIVER_EXTRA_STATS_FILENAME=%t AFLDriverTest 15 | RUN: [[ $(grep "peak_rss_mb\|slowest_unit_time_sec" %t | wc -l) -eq 2 ]] 16 | 17 | ; Test that specifying a valid preexisting stats file works. 18 | RUN: printf "peak_rss_mb : 0\nslowest_unit_time_sec: 0\n" > %t 19 | RUN: AFL_DRIVER_EXTRA_STATS_FILENAME=%t AFLDriverTest 20 | ; Check that both lines were printed. 21 | RUN: [[ $(grep "peak_rss_mb\|slowest_unit_time_sec" %t | wc -l) -eq 2 ]] 22 | 23 | ; Test that peak_rss_mb and slowest_unit_time_in_secs are only updated when necessary. 24 | ; Check that both lines have 9999 since there's no way we have exceeded that 25 | ; amount of time or virtual memory. 26 | RUN: printf "peak_rss_mb : 9999\nslowest_unit_time_sec: 9999\n" > %t 27 | RUN: AFL_DRIVER_EXTRA_STATS_FILENAME=%t AFLDriverTest 28 | RUN: [[ $(grep "9999" %t | wc -l) -eq 2 ]] 29 | -------------------------------------------------------------------------------- /Fuzzer/test/afl-driver-stderr.test: -------------------------------------------------------------------------------- 1 | ; Test that not specifying a stderr file isn't broken. 2 | RUN: unset AFL_DRIVER_STDERR_DUPLICATE_FILENAME 3 | RUN: AFLDriverTest 4 | 5 | ; Test that specifying an invalid file causes a crash. 6 | RUN: ASAN_OPTIONS= AFL_DRIVER_STDERR_DUPLICATE_FILENAME="%T" not --crash AFLDriverTest 7 | 8 | ; Test that a file is created when specified as the duplicate stderr. 9 | RUN: AFL_DRIVER_STDERR_DUPLICATE_FILENAME=%t AFLDriverTest 10 | RUN: stat %t 11 | -------------------------------------------------------------------------------- /Fuzzer/test/coverage.test: -------------------------------------------------------------------------------- 1 | CHECK: COVERAGE: 2 | CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:13 3 | CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:14 4 | CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:16 5 | CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:19 6 | RUN: not LLVMFuzzer-NullDerefTest-TracePC -print_coverage=1 2>&1 | FileCheck %s 7 | 8 | RUN: LLVMFuzzer-DSOTest -print_coverage=1 -runs=0 2>&1 | FileCheck %s --check-prefix=DSO 9 | DSO: COVERAGE: 10 | DSO-DAG: COVERED:{{.*}}DSO1{{.*}}DSO1.cpp 11 | DSO-DAG: COVERED:{{.*}}DSO2{{.*}}DSO2.cpp 12 | DSO-DAG: COVERED:{{.*}}LLVMFuzzerTestOneInput{{.*}}DSOTestMain 13 | DSO-DAG: UNCOVERED_LINE:{{.*}}DSO1{{.*}}DSO1.cpp 14 | DSO-DAG: UNCOVERED_LINE:{{.*}}DSO2{{.*}}DSO2.cpp 15 | DSO-DAG: UNCOVERED_FUNC: in Uncovered1 16 | DSO-DAG: UNCOVERED_FUNC: in Uncovered2 17 | DSO-DAG: UNCOVERED_LINE: in LLVMFuzzerTestOneInput 18 | DSO-DAG: UNCOVERED_FILE:{{.*}}DSOTestExtra.cpp 19 | -------------------------------------------------------------------------------- /Fuzzer/test/dict1.txt: -------------------------------------------------------------------------------- 1 | # Dictionary for SimpleDictionaryTest 2 | 3 | a="Elvis" 4 | b="Presley" 5 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-customcrossover.test: -------------------------------------------------------------------------------- 1 | RUN: rm -rf %t/CustomCrossover 2 | RUN: mkdir -p %t/CustomCrossover 3 | RUN: echo "0123456789" > %t/CustomCrossover/digits 4 | RUN: echo "abcdefghij" > %t/CustomCrossover/chars 5 | RUN: not LLVMFuzzer-CustomCrossOverTest -seed=1 -use_memcmp=0 -runs=100000 %t/CustomCrossover 2>&1 | FileCheck %s --check-prefix=LLVMFuzzerCustomCrossover 6 | RUN: rm -rf %t/CustomCrossover 7 | 8 | LLVMFuzzerCustomCrossover: In LLVMFuzzerCustomCrossover 9 | LLVMFuzzerCustomCrossover: BINGO 10 | 11 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-custommutator.test: -------------------------------------------------------------------------------- 1 | RUN: not LLVMFuzzer-CustomMutatorTest 2>&1 | FileCheck %s --check-prefix=LLVMFuzzerCustomMutator 2 | LLVMFuzzerCustomMutator: In LLVMFuzzerCustomMutator 3 | LLVMFuzzerCustomMutator: BINGO 4 | 5 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-dict.test: -------------------------------------------------------------------------------- 1 | CHECK: BINGO 2 | Done1000000: Done 1000000 runs in 3 | 4 | RUN: not LLVMFuzzer-SimpleDictionaryTest -dict=%S/dict1.txt -seed=1 -runs=1000003 2>&1 | FileCheck %s 5 | RUN: LLVMFuzzer-SimpleDictionaryTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 6 | 7 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-dirs.test: -------------------------------------------------------------------------------- 1 | RUN: rm -rf %t/SUB1 2 | RUN: mkdir -p %t/SUB1/SUB2/SUB3 3 | RUN: echo a > %t/SUB1/a 4 | RUN: echo b > %t/SUB1/SUB2/b 5 | RUN: echo c > %t/SUB1/SUB2/SUB3/c 6 | RUN: LLVMFuzzer-SimpleTest %t/SUB1 -runs=0 2>&1 | FileCheck %s --check-prefix=SUBDIRS 7 | SUBDIRS: READ units: 3 8 | RUN: echo zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz > %t/SUB1/long 9 | RUN: LLVMFuzzer-SimpleTest %t/SUB1 -runs=0 2>&1 | FileCheck %s --check-prefix=LONG 10 | LONG: INFO: -max_len is not provided, using 94 11 | RUN: rm -rf %t/SUB1 12 | 13 | RUN: not LLVMFuzzer-SimpleTest NONEXISTENT_DIR 2>&1 | FileCheck %s --check-prefix=NONEXISTENT_DIR 14 | NONEXISTENT_DIR: No such directory: NONEXISTENT_DIR; exiting 15 | 16 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-fdmask.test: -------------------------------------------------------------------------------- 1 | RUN: LLVMFuzzer-SpamyTest -runs=1 2>&1 | FileCheck %s --check-prefix=FD_MASK_0 2 | RUN: LLVMFuzzer-SpamyTest -runs=1 -close_fd_mask=0 2>&1 | FileCheck %s --check-prefix=FD_MASK_0 3 | RUN: LLVMFuzzer-SpamyTest -runs=1 -close_fd_mask=1 2>&1 | FileCheck %s --check-prefix=FD_MASK_1 4 | RUN: LLVMFuzzer-SpamyTest -runs=1 -close_fd_mask=2 2>&1 | FileCheck %s --check-prefix=FD_MASK_2 5 | RUN: LLVMFuzzer-SpamyTest -runs=1 -close_fd_mask=3 2>&1 | FileCheck %s --check-prefix=FD_MASK_3 6 | 7 | FD_MASK_0: PRINTF_STDOUT 8 | FD_MASK_0: PRINTF_STDERR 9 | FD_MASK_0: STREAM_COUT 10 | FD_MASK_0: STREAM_CERR 11 | FD_MASK_0: INITED 12 | 13 | FD_MASK_1-NOT: PRINTF_STDOUT 14 | FD_MASK_1: PRINTF_STDERR 15 | FD_MASK_1-NOT: STREAM_COUT 16 | FD_MASK_1: STREAM_CERR 17 | FD_MASK_1: INITED 18 | 19 | FD_MASK_2: PRINTF_STDOUT 20 | FD_MASK_2-NOT: PRINTF_STDERR 21 | FD_MASK_2: STREAM_COUT 22 | FD_MASK_2-NOTE: STREAM_CERR 23 | FD_MASK_2: INITED 24 | 25 | FD_MASK_3-NOT: PRINTF_STDOUT 26 | FD_MASK_3-NOT: PRINTF_STDERR 27 | FD_MASK_3-NOT: STREAM_COUT 28 | FD_MASK_3-NOT: STREAM_CERR 29 | FD_MASK_3: INITED 30 | 31 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-finalstats.test: -------------------------------------------------------------------------------- 1 | RUN: LLVMFuzzer-SimpleTest -seed=1 -runs=77 -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=FINAL_STATS 2 | FINAL_STATS: stat::number_of_executed_units: 77 3 | FINAL_STATS: stat::average_exec_per_sec: 0 4 | FINAL_STATS: stat::new_units_added: 5 | FINAL_STATS: stat::slowest_unit_time_sec: 0 6 | FINAL_STATS: stat::peak_rss_mb: 7 | 8 | RUN: LLVMFuzzer-SimpleTest %S/dict1.txt -runs=33 -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=FINAL_STATS1 9 | FINAL_STATS1: stat::number_of_executed_units: 33 10 | FINAL_STATS1: stat::peak_rss_mb: 11 | 12 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-flags.test: -------------------------------------------------------------------------------- 1 | RUN: LLVMFuzzer-SimpleTest -foo_bar=1 2>&1 | FileCheck %s --check-prefix=FOO_BAR 2 | FOO_BAR: WARNING: unrecognized flag '-foo_bar=1'; use -help=1 to list all flags 3 | FOO_BAR: BINGO 4 | 5 | RUN: LLVMFuzzer-SimpleTest -runs=10 --max_len=100 2>&1 | FileCheck %s --check-prefix=DASH_DASH 6 | DASH_DASH: WARNING: did you mean '-max_len=100' (single dash)? 7 | DASH_DASH: INFO: A corpus is not provided, starting from an empty corpus 8 | 9 | RUN: LLVMFuzzer-SimpleTest -help=1 2>&1 | FileCheck %s --check-prefix=NO_INTERNAL 10 | NO_INTERNAL-NOT: internal flag 11 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-fn-adapter.test: -------------------------------------------------------------------------------- 1 | RUN: LLVMFuzzer-SimpleFnAdapterTest 2>&1 | FileCheck %s 2 | 3 | CHECK: BINGO 4 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-jobs.test: -------------------------------------------------------------------------------- 1 | RUN: rm -rf %tmp 2 | RUN: mkdir %tmp && cd %tmp 3 | # Create a shared corpus directory 4 | RUN: rm -rf FuzzerJobsTestCORPUS 5 | RUN: mkdir FuzzerJobsTestCORPUS 6 | RUN: rm -f fuzz-{0,1}.log 7 | # Start fuzzer and in parallel check that the output files 8 | # that should be created exist. 9 | RUN: LLVMFuzzer-EmptyTest -max_total_time=4 -jobs=2 -workers=2 FuzzerJobsTestCORPUS > %t-fuzzer-jobs-test.log 2>&1 & export FUZZER_PID=$! 10 | # Wait a short while to give time for the child processes 11 | # to start fuzzing 12 | RUN: sleep 2 13 | # If the instances are running in parallel they should have created their log 14 | # files by now. 15 | RUN: ls fuzz-0.log 16 | RUN: ls fuzz-1.log 17 | # Wait for libfuzzer to finish. 18 | # This probably isn't portable but we need a way to block until 19 | # the fuzzer is done otherwise we might remove the files while 20 | # they are being used. 21 | RUN: while kill -0 ${FUZZER_PID}; do : ; done 22 | RUN: rm -f fuzz-{0,1}.log 23 | RUN: rm -rf FuzzerJobsTestCORPUS 24 | RUN: FileCheck -input-file=%t-fuzzer-jobs-test.log %s 25 | RUN: rm %t-fuzzer-jobs-test.log 26 | RUN: cd ../ 27 | 28 | CHECK-DAG: Job 0 exited with exit code 0 29 | CHECK-DAG: Job 1 exited with exit code 0 30 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-leak.test: -------------------------------------------------------------------------------- 1 | REQUIRES: lsan 2 | RUN: not LLVMFuzzer-LeakTest -runs=100000 -detect_leaks=1 2>&1 | FileCheck %s --check-prefix=LEAK_DURING 3 | LEAK_DURING: ERROR: LeakSanitizer: detected memory leaks 4 | LEAK_DURING: Direct leak of 4 byte(s) in 1 object(s) allocated from: 5 | LEAK_DURING: INFO: to ignore leaks on libFuzzer side use -detect_leaks=0 6 | LEAK_DURING: Test unit written to ./leak- 7 | LEAK_DURING-NOT: DONE 8 | LEAK_DURING-NOT: Done 9 | 10 | RUN: not LLVMFuzzer-LeakTest -runs=0 -detect_leaks=1 %S 2>&1 | FileCheck %s --check-prefix=LEAK_IN_CORPUS 11 | LEAK_IN_CORPUS: ERROR: LeakSanitizer: detected memory leaks 12 | LEAK_IN_CORPUS: INFO: a leak has been found in the initial corpus. 13 | 14 | RUN: not LLVMFuzzer-LeakTest -runs=100000000 %S/hi.txt 2>&1 | FileCheck %s --check-prefix=MULTI_RUN_LEAK 15 | MULTI_RUN_LEAK-NOT: pulse 16 | MULTI_RUN_LEAK: LeakSanitizer: detected memory leaks 17 | 18 | RUN: not LLVMFuzzer-LeakTest -runs=100000 -detect_leaks=0 2>&1 | FileCheck %s --check-prefix=LEAK_AFTER 19 | RUN: not LLVMFuzzer-LeakTest -runs=100000 2>&1 | FileCheck %s --check-prefix=LEAK_DURING 20 | RUN: not LLVMFuzzer-ThreadedLeakTest -runs=100000 -detect_leaks=0 2>&1 | FileCheck %s --check-prefix=LEAK_AFTER 21 | RUN: not LLVMFuzzer-ThreadedLeakTest -runs=100000 2>&1 | FileCheck %s --check-prefix=LEAK_DURING 22 | LEAK_AFTER: Done 100000 runs in 23 | LEAK_AFTER: ERROR: LeakSanitizer: detected memory leaks 24 | 25 | RUN: not LLVMFuzzer-LeakTest -runs=100000 -max_len=1 2>&1 | FileCheck %s --check-prefix=MAX_LEN_1 26 | MAX_LEN_1: Test unit written to ./leak-7cf184f4c67ad58283ecb19349720b0cae756829 27 | 28 | RUN: not LLVMFuzzer-LeakTimeoutTest -timeout=1 2>&1 | FileCheck %s --check-prefix=LEAK_TIMEOUT 29 | LEAK_TIMEOUT: ERROR: libFuzzer: timeout after 30 | LEAK_TIMEOUT-NOT: LeakSanitizer 31 | 32 | RUN: LLVMFuzzer-AccumulateAllocationsTest -detect_leaks=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=ACCUMULATE_ALLOCS 33 | ACCUMULATE_ALLOCS: INFO: libFuzzer disabled leak detection after every mutation 34 | 35 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-oom-with-profile.test: -------------------------------------------------------------------------------- 1 | REQUIRES: linux 2 | RUN: not LLVMFuzzer-OutOfMemoryTest -rss_limit_mb=10 2>&1 | FileCheck %s 3 | CHECK: ERROR: libFuzzer: out-of-memory (used: {{.*}}; limit: 10Mb) 4 | CHECK: Live Heap Allocations 5 | CHECK: Test unit written to ./oom- 6 | SUMMARY: libFuzzer: out-of-memory 7 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-oom.test: -------------------------------------------------------------------------------- 1 | RUN: not LLVMFuzzer-OutOfMemoryTest -rss_limit_mb=10 2>&1 | FileCheck %s 2 | CHECK: ERROR: libFuzzer: out-of-memory (used: {{.*}}; limit: 10Mb) 3 | CHECK: Test unit written to ./oom- 4 | SUMMARY: libFuzzer: out-of-memory 5 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-printcovpcs.test: -------------------------------------------------------------------------------- 1 | RUN: LLVMFuzzer-SimpleTest-TracePC -print_pcs=1 -seed=1 2>&1 | FileCheck %s --check-prefix=PCS 2 | PCS-NOT: NEW_PC 3 | PCS:INITED 4 | PCS:NEW_PC: {{0x[a-f0-9]+}} 5 | PCS:NEW_PC: {{0x[a-f0-9]+}} 6 | PCS:NEW 7 | PCS:BINGO 8 | 9 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-runs.test: -------------------------------------------------------------------------------- 1 | RUN: mkdir -p %t 2 | RUN: echo abcd > %t/NthRunCrashTest.in 3 | RUN: LLVMFuzzer-NthRunCrashTest %t/NthRunCrashTest.in 4 | RUN: LLVMFuzzer-NthRunCrashTest %t/NthRunCrashTest.in -runs=10 5 | RUN: not LLVMFuzzer-NthRunCrashTest %t/NthRunCrashTest.in -runs=10000 2>&1 | FileCheck %s 6 | RUN: rm %t/NthRunCrashTest.in 7 | CHECK: BINGO 8 | 9 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-seed.test: -------------------------------------------------------------------------------- 1 | RUN: LLVMFuzzer-SimpleCmpTest -seed=-1 -runs=0 2>&1 | FileCheck %s --check-prefix=CHECK_SEED_MINUS_ONE 2 | CHECK_SEED_MINUS_ONE: Seed: 4294967295 3 | 4 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-segv.test: -------------------------------------------------------------------------------- 1 | RUN: ASAN_OPTIONS=handle_segv=0 not LLVMFuzzer-NullDerefTest 2>&1 | FileCheck %s --check-prefix=LIBFUZZER_OWN_SEGV_HANDLER 2 | LIBFUZZER_OWN_SEGV_HANDLER: == ERROR: libFuzzer: deadly signal 3 | LIBFUZZER_OWN_SEGV_HANDLER: SUMMARY: libFuzzer: deadly signal 4 | LIBFUZZER_OWN_SEGV_HANDLER: Test unit written to ./crash- 5 | 6 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-singleinputs.test: -------------------------------------------------------------------------------- 1 | RUN: not LLVMFuzzer-NullDerefTest %S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInput 2 | SingleInput-NOT: Test unit written to ./crash- 3 | 4 | RUN: rm -rf %tmp/SINGLE_INPUTS 5 | RUN: mkdir -p %tmp/SINGLE_INPUTS 6 | RUN: echo aaa > %tmp/SINGLE_INPUTS/aaa 7 | RUN: echo bbb > %tmp/SINGLE_INPUTS/bbb 8 | RUN: LLVMFuzzer-SimpleTest %tmp/SINGLE_INPUTS/aaa %tmp/SINGLE_INPUTS/bbb 2>&1 | FileCheck %s --check-prefix=SINGLE_INPUTS 9 | RUN: LLVMFuzzer-SimpleTest -max_len=2 %tmp/SINGLE_INPUTS/aaa %tmp/SINGLE_INPUTS/bbb 2>&1 | FileCheck %s --check-prefix=SINGLE_INPUTS 10 | RUN: rm -rf %tmp/SINGLE_INPUTS 11 | SINGLE_INPUTS: LLVMFuzzer-SimpleTest: Running 2 inputs 1 time(s) each. 12 | SINGLE_INPUTS: aaa in 13 | SINGLE_INPUTS: bbb in 14 | SINGLE_INPUTS: NOTE: fuzzing was not performed, you have only 15 | SINGLE_INPUTS: executed the target code on a fixed set of inputs. 16 | 17 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-threaded.test: -------------------------------------------------------------------------------- 1 | CHECK: Done 1000 runs in 2 | 3 | RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s 4 | RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s 5 | RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s 6 | RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s 7 | 8 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-timeout.test: -------------------------------------------------------------------------------- 1 | RUN: not LLVMFuzzer-TimeoutTest -timeout=1 2>&1 | FileCheck %s --check-prefix=TimeoutTest 2 | TimeoutTest: ALARM: working on the last Unit for 3 | TimeoutTest: Test unit written to ./timeout- 4 | TimeoutTest: == ERROR: libFuzzer: timeout after 5 | TimeoutTest: #0 6 | TimeoutTest: #1 7 | TimeoutTest: #2 8 | TimeoutTest: SUMMARY: libFuzzer: timeout 9 | 10 | RUN: not LLVMFuzzer-TimeoutTest -timeout=1 %S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInputTimeoutTest 11 | SingleInputTimeoutTest: ALARM: working on the last Unit for {{[1-3]}} seconds 12 | SingleInputTimeoutTest-NOT: Test unit written to ./timeout- 13 | 14 | RUN: LLVMFuzzer-TimeoutTest -timeout=1 -timeout_exitcode=0 15 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-traces-hooks.test: -------------------------------------------------------------------------------- 1 | // FIXME: Support sanitizer hooks for memcmp and strcmp need 2 | // to be implemented in the sanitizer runtime for platforms other 3 | // than linux 4 | REQUIRES: linux 5 | CHECK: BINGO 6 | Done1000000: Done 1000000 runs in 7 | 8 | RUN: not LLVMFuzzer-MemcmpTest -seed=4294967295 -runs=100000 2>&1 | FileCheck %s 9 | RUN: LLVMFuzzer-MemcmpTest -use_memcmp=0 -seed=4294967295 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 10 | 11 | RUN: not LLVMFuzzer-StrncmpTest -seed=2 -runs=100000 2>&1 | FileCheck %s 12 | RUN: LLVMFuzzer-StrncmpTest -use_memcmp=0 -seed=3 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 13 | 14 | RUN: not LLVMFuzzer-StrcmpTest -seed=4 -runs=200000 2>&1 | FileCheck %s 15 | RUN: LLVMFuzzer-StrcmpTest -use_memcmp=0 -seed=5 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 16 | 17 | RUN: not LLVMFuzzer-StrstrTest -seed=6 -runs=200000 2>&1 | FileCheck %s 18 | RUN: LLVMFuzzer-StrstrTest -use_memmem=0 -seed=7 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 19 | 20 | RUN: LLVMFuzzer-RepeatedMemcmp -seed=10 -runs=100000 2>&1 | FileCheck %s --check-prefix=RECOMMENDED_DICT 21 | RECOMMENDED_DICT:###### Recommended dictionary. ###### 22 | RECOMMENDED_DICT-DAG: "foo" 23 | RECOMMENDED_DICT-DAG: "bar" 24 | RECOMMENDED_DICT:###### End of recommended dictionary. ###### 25 | 26 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer-ubsan.test: -------------------------------------------------------------------------------- 1 | RUN: not LLVMFuzzer-SignedIntOverflowTest-Ubsan 2>&1 | FileCheck %s 2 | CHECK: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' 3 | CHECK: Test unit written to ./crash- 4 | 5 | -------------------------------------------------------------------------------- /Fuzzer/test/fuzzer.test: -------------------------------------------------------------------------------- 1 | CHECK: BINGO 2 | Done1000000: Done 1000000 runs in 3 | 4 | RUN: LLVMFuzzer-SimpleTest 2>&1 | FileCheck %s 5 | RUN: LLVMFuzzer-SimpleTest-TracePC 2>&1 | FileCheck %s 6 | 7 | # only_ascii mode. Will perform some minimal self-validation. 8 | RUN: LLVMFuzzer-SimpleTest -only_ascii=1 2>&1 9 | 10 | RUN: LLVMFuzzer-SimpleCmpTest -max_total_time=1 2>&1 | FileCheck %s --check-prefix=MaxTotalTime 11 | MaxTotalTime: Done {{.*}} runs in {{.}} second(s) 12 | 13 | RUN: not LLVMFuzzer-NullDerefTest 2>&1 | FileCheck %s --check-prefix=NullDerefTest 14 | RUN: not LLVMFuzzer-NullDerefTest -close_fd_mask=3 2>&1 | FileCheck %s --check-prefix=NullDerefTest 15 | NullDerefTest: ERROR: AddressSanitizer: SEGV on unknown address 16 | NullDerefTest: Test unit written to ./crash- 17 | RUN: not LLVMFuzzer-NullDerefTest -artifact_prefix=ZZZ 2>&1 | FileCheck %s --check-prefix=NullDerefTestPrefix 18 | NullDerefTestPrefix: Test unit written to ZZZcrash- 19 | RUN: not LLVMFuzzer-NullDerefTest -artifact_prefix=ZZZ -exact_artifact_path=FOOBAR 2>&1 | FileCheck %s --check-prefix=NullDerefTestExactPath 20 | NullDerefTestExactPath: Test unit written to FOOBAR 21 | 22 | RUN: not LLVMFuzzer-NullDerefOnEmptyTest -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=NULL_DEREF_ON_EMPTY 23 | NULL_DEREF_ON_EMPTY: stat::number_of_executed_units: 24 | 25 | #not LLVMFuzzer-FullCoverageSetTest -timeout=15 -seed=1 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s 26 | 27 | RUN: not LLVMFuzzer-CounterTest -use_counters=1 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s --check-prefix=COUNTERS 28 | RUN: not LLVMFuzzer-CounterTest-TracePC -use_counters=1 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s --check-prefix=COUNTERS 29 | 30 | COUNTERS: INITED {{.*}} {{bits:|ft:}} 31 | COUNTERS: NEW {{.*}} {{bits:|ft:}} {{[1-9]*}} 32 | COUNTERS: NEW {{.*}} {{bits:|ft:}} {{[1-9]*}} 33 | COUNTERS: BINGO 34 | 35 | RUN: not LLVMFuzzer-CallerCalleeTest -use_value_profile=1 -cross_over=0 -max_len=6 -seed=1 -max_total_time=15 2>&1 | FileCheck %s 36 | RUN: not LLVMFuzzer-CallerCalleeTest-TracePC -use_value_profile=1 -cross_over=0 -max_len=6 -seed=1 -max_total_time=15 2>&1 | FileCheck %s 37 | # This one is flaky, may actually find the goal even w/o use_indir_calls. 38 | # LLVMFuzzer-CallerCalleeTest -use_indir_calls=0 -cross_over=0 -max_len=6 -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 39 | 40 | RUN: not LLVMFuzzer-UninstrumentedTest-Uninstrumented 2>&1 | FileCheck %s --check-prefix=UNINSTRUMENTED 41 | UNINSTRUMENTED: ERROR: __sanitizer_set_death_callback is not defined. Exiting. 42 | 43 | RUN: not LLVMFuzzer-UninstrumentedTest-NoCoverage 2>&1 | FileCheck %s --check-prefix=NO_COVERAGE 44 | NO_COVERAGE: ERROR: no interesting inputs were found. Is the code instrumented for coverage? Exiting 45 | 46 | RUN: not LLVMFuzzer-BufferOverflowOnInput 2>&1 | FileCheck %s --check-prefix=OOB 47 | OOB: AddressSanitizer: heap-buffer-overflow 48 | OOB: is located 0 bytes to the right of 3-byte region 49 | 50 | RUN: not LLVMFuzzer-InitializeTest -use_value_profile=1 2>&1 | FileCheck %s 51 | 52 | RUN: not LLVMFuzzer-DSOTest 2>&1 | FileCheck %s --check-prefix=DSO 53 | DSO: INFO: Loaded 3 modules 54 | DSO: BINGO 55 | 56 | RUN: LLVMFuzzer-SimpleTest-TracePC -exit_on_src_pos=SimpleTest.cpp:17 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS 57 | RUN: LLVMFuzzer-ShrinkControlFlowTest-TracePC -exit_on_src_pos=ShrinkControlFlowTest.cpp:23 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS 58 | EXIT_ON_SRC_POS: INFO: found line matching '{{.*}}', exiting. 59 | 60 | RUN: ASAN_OPTIONS=strict_string_checks=1 not LLVMFuzzer-StrncmpOOBTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=STRNCMP 61 | STRNCMP: AddressSanitizer: heap-buffer-overflow 62 | STRNCMP-NOT: __sanitizer_weak_hook_strncmp 63 | STRNCMP: in LLVMFuzzerTestOneInput 64 | -------------------------------------------------------------------------------- /Fuzzer/test/hi.txt: -------------------------------------------------------------------------------- 1 | Hi! -------------------------------------------------------------------------------- /Fuzzer/test/lit.cfg: -------------------------------------------------------------------------------- 1 | import lit.formats 2 | import sys 3 | 4 | config.name = "LLVMFuzzer" 5 | config.test_format = lit.formats.ShTest(True) 6 | config.suffixes = ['.test'] 7 | config.test_source_root = os.path.dirname(__file__) 8 | 9 | # Tweak PATH to include llvm tools dir and current exec dir. 10 | llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) 11 | if (not llvm_tools_dir) or (not os.path.exists(llvm_tools_dir)): 12 | lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % llvm_tools_dir) 13 | path = os.path.pathsep.join((llvm_tools_dir, config.test_exec_root, 14 | config.environment['PATH'])) 15 | config.environment['PATH'] = path 16 | 17 | if config.has_lsan: 18 | lit_config.note('lsan feature available') 19 | config.available_features.add('lsan') 20 | else: 21 | lit_config.note('lsan feature unavailable') 22 | 23 | if sys.platform.startswith('linux'): 24 | # Note the value of ``sys.platform`` is not consistent 25 | # between python 2 and 3, hence the use of ``.startswith()``. 26 | lit_config.note('linux feature available') 27 | config.available_features.add('linux') 28 | else: 29 | lit_config.note('linux feature unavailable') 30 | -------------------------------------------------------------------------------- /Fuzzer/test/lit.site.cfg.in: -------------------------------------------------------------------------------- 1 | config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" 2 | config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" 3 | config.has_lsan = True if @HAS_LSAN@ == 1 else False 4 | lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg") 5 | -------------------------------------------------------------------------------- /Fuzzer/test/merge.test: -------------------------------------------------------------------------------- 1 | CHECK: BINGO 2 | 3 | RUN: rm -rf %tmp/T1 %tmp/T2 4 | RUN: mkdir -p %tmp/T1 %tmp/T2 5 | RUN: echo F..... > %tmp/T1/1 6 | RUN: echo .U.... > %tmp/T1/2 7 | RUN: echo ..Z... > %tmp/T1/3 8 | 9 | # T1 has 3 elements, T2 is empty. 10 | RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK1 11 | RUN: LLVMFuzzer-FullCoverageSetTest-TracePC -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK1 12 | CHECK1: === Minimizing the initial corpus of 3 units 13 | CHECK1: === Merge: written 0 units 14 | 15 | RUN: echo ...Z.. > %tmp/T2/1 16 | RUN: echo ....E. > %tmp/T2/2 17 | RUN: echo .....R > %tmp/T2/3 18 | RUN: echo F..... > %tmp/T2/a 19 | RUN: echo .U.... > %tmp/T2/b 20 | RUN: echo ..Z... > %tmp/T2/c 21 | 22 | # T1 has 3 elements, T2 has 6 elements, only 3 are new. 23 | RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK2 24 | CHECK2: === Minimizing the initial corpus of 3 units 25 | CHECK2: === Merging extra 6 units 26 | CHECK2: === Merge: written 3 units 27 | 28 | # Now, T1 has 6 units and T2 has no new interesting units. 29 | RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK3 30 | RUN: LLVMFuzzer-FullCoverageSetTest-TracePC -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK3 31 | CHECK3: === Minimizing the initial corpus of 6 units 32 | CHECK3: === Merge: written 0 units 33 | 34 | 35 | # Check that when merge fails we print an error message. 36 | RUN: echo 'Hi!' > %tmp/T1/HiI 37 | RUN: not LLVMFuzzer-NullDerefTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=MERGE_FAIL 38 | MERGE_FAIL: NOTE: merge did not succeed due to a failure on one of the inputs. 39 | -------------------------------------------------------------------------------- /Fuzzer/test/minimize_crash.test: -------------------------------------------------------------------------------- 1 | CHECK: CRASH_MIN: failed to minimize beyond minimized-from-{{.*}} (3 bytes), exiting 2 | RUN: echo 'Hi!rv349f34t3gg' > not_minimal_crash 3 | RUN: LLVMFuzzer-NullDerefTest -minimize_crash=1 not_minimal_crash -max_total_time=2 2>&1 | FileCheck %s 4 | RUN: rm not_minimal_crash minimized-from-* 5 | 6 | 7 | -------------------------------------------------------------------------------- /Fuzzer/test/no-coverage/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # These tests are not instrumented with coverage, 2 | # but have coverage rt in the binary. 3 | 4 | set(CMAKE_CXX_FLAGS 5 | "${LIBFUZZER_FLAGS_BASE} -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters") 6 | 7 | set(NoCoverageTests 8 | UninstrumentedTest 9 | ) 10 | 11 | foreach(Test ${NoCoverageTests}) 12 | add_libfuzzer_test(${Test}-NoCoverage SOURCES ../${Test}.cpp) 13 | endforeach() 14 | 15 | 16 | ############################################################################### 17 | # AFL Driver test 18 | ############################################################################### 19 | 20 | add_executable(AFLDriverTest 21 | ../AFLDriverTest.cpp ../../afl/afl_driver.cpp) 22 | 23 | set_target_properties(AFLDriverTest 24 | PROPERTIES RUNTIME_OUTPUT_DIRECTORY 25 | "${CMAKE_BINARY_DIR}/lib/Fuzzer/test" 26 | ) 27 | 28 | # Propagate value into parent directory 29 | set(TestBinaries ${TestBinaries} AFLDriverTest PARENT_SCOPE) 30 | -------------------------------------------------------------------------------- /Fuzzer/test/repeated-bytes.test: -------------------------------------------------------------------------------- 1 | CHECK: BINGO 2 | RUN: LLVMFuzzer-RepeatedBytesTest -seed=1 -runs=1000000 2>&1 | FileCheck %s 3 | -------------------------------------------------------------------------------- /Fuzzer/test/shrink.test: -------------------------------------------------------------------------------- 1 | RUN: LLVMFuzzer-ShrinkControlFlowTest-TracePC -seed=1 -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000 -shrink=1 2>&1 | FileCheck %s --check-prefix=SHRINK1 2 | RUN: LLVMFuzzer-ShrinkControlFlowTest-TracePC -seed=1 -exit_on_item=0eb8e4ed029b774d80f2b66408203801cb982a60 -runs=1000000 -shrink=0 2>&1 | FileCheck %s --check-prefix=SHRINK0 3 | RUN: LLVMFuzzer-ShrinkValueProfileTest-TracePC -seed=1 -exit_on_item=aea2e3923af219a8956f626558ef32f30a914ebc -runs=100000 -shrink=1 -use_value_profile=1 2>&1 | FileCheck %s --check-prefix=SHRINK1_VP 4 | 5 | SHRINK0: Done 1000000 runs in 6 | SHRINK1: INFO: found item with checksum '0eb8e4ed029b774d80f2b66408203801cb982a60', exiting. 7 | SHRINK1_VP: INFO: found item with checksum 'aea2e3923af219a8956f626558ef32f30a914ebc', exiting 8 | -------------------------------------------------------------------------------- /Fuzzer/test/simple-cmp.test: -------------------------------------------------------------------------------- 1 | CHECK: BINGO 2 | RUN: not LLVMFuzzer-SimpleCmpTest -seed=1 -use_cmp=1 -runs=100000000 2>&1 | FileCheck %s 3 | -------------------------------------------------------------------------------- /Fuzzer/test/standalone.test: -------------------------------------------------------------------------------- 1 | RUN: LLVMFuzzer-StandaloneInitializeTest %S/hi.txt %S/dict1.txt 2>&1 | FileCheck %s 2 | CHECK: StandaloneFuzzTargetMain: running 2 inputs 3 | CHECK: Done: {{.*}}hi.txt: (3 bytes) 4 | CHECK: Done: {{.*}}dict1.txt: (61 bytes) 5 | -------------------------------------------------------------------------------- /Fuzzer/test/swap-cmp.test: -------------------------------------------------------------------------------- 1 | CHECK: BINGO 2 | RUN: not LLVMFuzzer-SwapCmpTest -seed=1 -use_cmp=1 -runs=10000000 2>&1 | FileCheck %s 3 | -------------------------------------------------------------------------------- /Fuzzer/test/trace-bb/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # These tests are not instrumented with coverage. 2 | 3 | set(CMAKE_CXX_FLAGS 4 | "${LIBFUZZER_FLAGS_BASE} -fsanitize-coverage=edge,trace-bb") 5 | 6 | set(TraceBBTests 7 | SimpleTest 8 | ) 9 | 10 | foreach(Test ${TraceBBTests}) 11 | add_libfuzzer_test(${Test}-TraceBB SOURCES ../${Test}.cpp) 12 | endforeach() 13 | 14 | # Propagate value into parent directory 15 | set(TestBinaries ${TestBinaries} PARENT_SCOPE) 16 | -------------------------------------------------------------------------------- /Fuzzer/test/trace-malloc.test: -------------------------------------------------------------------------------- 1 | RUN: LLVMFuzzer-TraceMallocTest -seed=1 -trace_malloc=1 -runs=10000 2>&1 | FileCheck %s 2 | CHECK-DAG: MallocFreeTracer: STOP 0 0 (same) 3 | CHECK-DAG: MallocFreeTracer: STOP 0 1 (DIFFERENT) 4 | CHECK-DAG: MallocFreeTracer: STOP 1 0 (DIFFERENT) 5 | CHECK-DAG: MallocFreeTracer: STOP 1 1 (same) 6 | 7 | RUN: LLVMFuzzer-TraceMallocTest -seed=1 -trace_malloc=2 -runs=1000 2>&1 | FileCheck %s --check-prefix=TRACE2 8 | TRACE2-DAG: FREE[0] 9 | TRACE2-DAG: MALLOC[0] 10 | TRACE2-DAG: in LLVMFuzzerTestOneInput 11 | -------------------------------------------------------------------------------- /Fuzzer/test/trace-pc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # These tests are not instrumented with coverage. 2 | 3 | set(CMAKE_CXX_FLAGS 4 | "${LIBFUZZER_FLAGS_BASE} -fno-sanitize-coverage=8bit-counters -fsanitize-coverage=trace-pc-guard") 5 | 6 | set(TracePCTests 7 | SimpleTest 8 | CounterTest 9 | CallerCalleeTest 10 | NullDerefTest 11 | ShrinkControlFlowTest 12 | ShrinkValueProfileTest 13 | SwitchTest 14 | Switch2Test 15 | FullCoverageSetTest 16 | ) 17 | 18 | foreach(Test ${TracePCTests}) 19 | add_libfuzzer_test(${Test}-TracePC SOURCES ../${Test}.cpp) 20 | endforeach() 21 | 22 | # Propagate value into parent directory 23 | set(TestBinaries ${TestBinaries} PARENT_SCOPE) 24 | 25 | add_library(LLVMFuzzer-DSO1 SHARED ../DSO1.cpp) 26 | add_library(LLVMFuzzer-DSO2 SHARED ../DSO2.cpp) 27 | 28 | add_executable(LLVMFuzzer-DSOTest 29 | ../DSOTestMain.cpp 30 | ../DSOTestExtra.cpp) 31 | 32 | target_link_libraries(LLVMFuzzer-DSOTest 33 | LLVMFuzzer-DSO1 34 | LLVMFuzzer-DSO2 35 | LLVMFuzzer 36 | ) 37 | 38 | set_target_properties(LLVMFuzzer-DSOTest PROPERTIES RUNTIME_OUTPUT_DIRECTORY 39 | "${CMAKE_BINARY_DIR}/lib/Fuzzer/test") 40 | set_target_properties(LLVMFuzzer-DSO1 PROPERTIES LIBRARY_OUTPUT_DIRECTORY 41 | "${CMAKE_BINARY_DIR}/lib/Fuzzer/lib") 42 | set_target_properties(LLVMFuzzer-DSO2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY 43 | "${CMAKE_BINARY_DIR}/lib/Fuzzer/lib") 44 | 45 | set(TestBinaries ${TestBinaries} LLVMFuzzer-DSOTest PARENT_SCOPE) 46 | -------------------------------------------------------------------------------- /Fuzzer/test/ubsan/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # These tests are instrumented with ubsan in non-recovery mode. 2 | 3 | set(CMAKE_CXX_FLAGS 4 | "${LIBFUZZER_FLAGS_BASE} -fsanitize=undefined -fno-sanitize-recover=all") 5 | 6 | set(UbsanTests 7 | SignedIntOverflowTest 8 | ) 9 | 10 | foreach(Test ${UbsanTests}) 11 | add_libfuzzer_test(${Test}-Ubsan SOURCES ../${Test}.cpp) 12 | endforeach() 13 | 14 | # Propagate value into parent directory 15 | set(TestBinaries ${TestBinaries} PARENT_SCOPE) 16 | -------------------------------------------------------------------------------- /Fuzzer/test/uninstrumented/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # These tests are not instrumented with coverage and don't 2 | # have coverage rt in the binary. 3 | 4 | set(CMAKE_CXX_FLAGS 5 | "${LIBFUZZER_FLAGS_BASE} -fno-sanitize=all -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters") 6 | 7 | set(UninstrumentedTests 8 | UninstrumentedTest 9 | ) 10 | 11 | foreach(Test ${UninstrumentedTests}) 12 | add_libfuzzer_test(${Test}-Uninstrumented SOURCES ../${Test}.cpp) 13 | endforeach() 14 | 15 | # Propagate value into parent directory 16 | set(TestBinaries ${TestBinaries} PARENT_SCOPE) 17 | -------------------------------------------------------------------------------- /Fuzzer/test/unit/lit.cfg: -------------------------------------------------------------------------------- 1 | import lit.formats 2 | 3 | config.name = "LLVMFuzzer-Unittest" 4 | print config.test_exec_root 5 | config.test_format = lit.formats.GoogleTest(".", "Unittest") 6 | config.suffixes = [] 7 | config.test_source_root = config.test_exec_root 8 | -------------------------------------------------------------------------------- /Fuzzer/test/unit/lit.site.cfg.in: -------------------------------------------------------------------------------- 1 | config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" 2 | lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/unit/lit.cfg") 3 | -------------------------------------------------------------------------------- /Fuzzer/test/value-profile-cmp.test: -------------------------------------------------------------------------------- 1 | CHECK: BINGO 2 | RUN: not LLVMFuzzer-SimpleCmpTest -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s 3 | RUN: not LLVMFuzzer-SimpleHashTest -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s 4 | RUN: not LLVMFuzzer-AbsNegAndConstantTest -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s 5 | RUN: not LLVMFuzzer-AbsNegAndConstant64Test -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s 6 | 7 | 8 | -------------------------------------------------------------------------------- /Fuzzer/test/value-profile-div.test: -------------------------------------------------------------------------------- 1 | CHECK: AddressSanitizer: FPE 2 | RUN: not LLVMFuzzer-DivTest -seed=1 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s 3 | 4 | -------------------------------------------------------------------------------- /Fuzzer/test/value-profile-load.test: -------------------------------------------------------------------------------- 1 | CHECK: AddressSanitizer: global-buffer-overflow 2 | RUN: not LLVMFuzzer-LoadTest -seed=1 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s 3 | 4 | -------------------------------------------------------------------------------- /Fuzzer/test/value-profile-mem.test: -------------------------------------------------------------------------------- 1 | CHECK: BINGO 2 | RUN: not LLVMFuzzer-SingleMemcmpTest -seed=1 -use_memcmp=0 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s 3 | RUN: not LLVMFuzzer-SingleStrcmpTest -seed=1 -use_memcmp=0 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s 4 | RUN: not LLVMFuzzer-SingleStrncmpTest -seed=1 -use_memcmp=0 -use_value_profile=1 -runs=10000000 2>&1 | FileCheck %s 5 | -------------------------------------------------------------------------------- /Fuzzer/test/value-profile-set.test: -------------------------------------------------------------------------------- 1 | CHECK: BINGO 2 | RUN: not LLVMFuzzer-FourIndependentBranchesTest -seed=1 -use_value_profile=1 -runs=100000000 2>&1 | FileCheck %s 3 | 4 | -------------------------------------------------------------------------------- /Fuzzer/test/value-profile-switch.test: -------------------------------------------------------------------------------- 1 | CHECK: BINGO 2 | RUN: not LLVMFuzzer-SwitchTest-TracePC -use_value_profile=1 -runs=100000000 -seed=1 2>&1 | FileCheck %s 3 | RUN: not LLVMFuzzer-Switch2Test-TracePC -use_value_profile=1 -runs=100000000 -seed=1 2>&1 | FileCheck %s 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CLANGVERS=-4.0 2 | LSAN_OPTIONS=detect_leaks=0 3 | 4 | SAN = -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp 5 | #SAN = -fsanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp 6 | 7 | OBJS = \ 8 | Fuzzer/FuzzerCrossOver.o \ 9 | Fuzzer/FuzzerDriver.o \ 10 | Fuzzer/FuzzerIO.o \ 11 | Fuzzer/FuzzerLoop.o \ 12 | Fuzzer/FuzzerMutate.o \ 13 | Fuzzer/FuzzerSHA1.o \ 14 | Fuzzer/FuzzerTraceState.o \ 15 | Fuzzer/FuzzerUtil.o \ 16 | Fuzzer/FuzzerUtilDarwin.cpp \ 17 | Fuzzer/FuzzerUtilLinux.cpp \ 18 | Fuzzer/FuzzerExtFunctionsDlsym.cpp \ 19 | Fuzzer/FuzzerExtFunctionsWeak.cpp \ 20 | Fuzzer/FuzzerTracePC.cpp \ 21 | test_harness.o test_pg.o # fail_pg.o 22 | 23 | all: test.so 24 | 25 | %.o: %.cpp 26 | clang++$(CLANGVERS) -g -O2 -fPIC -o $@ -c -std=c++11 $< 27 | 28 | test_harness.o: test_harness.cpp 29 | clang++$(CLANGVERS) -g -O0 -Wno-writable-strings -fPIC -c -std=c++11 $(SAN) test_harness.cpp 30 | 31 | %.o: %.c 32 | clang$(CLANGVERS) -g -O0 -I`/usr/local/pgsql/bin/pg_config --includedir-server` -fPIC -o $@ -c $(SAN) -Wno-ignored-attributes $< 33 | 34 | test.so: $(OBJS) 35 | clang++$(CLANGVERS) -fPIC -std=c++11 -shared -g -O0 -o test.so $(SAN) $(OBJS) 36 | 37 | test: test.so 38 | /usr/local/pgsql/bin/psql -c "select fuzz(10000, 'select \$$1')" 39 | 40 | clean: 41 | rm -f *.o *.so Fuzzer/*.o 42 | -------------------------------------------------------------------------------- /fail_pg.c: -------------------------------------------------------------------------------- 1 | #include "postgres.h" 2 | #include "funcapi.h" 3 | #include "utils/builtins.h" 4 | #include 5 | 6 | /* Postgres SQL Function to elog an internal error */ 7 | 8 | PG_FUNCTION_INFO_V1(fuzz_fail); 9 | Datum 10 | fuzz_fail(PG_FUNCTION_ARGS) 11 | { 12 | text *msgtext = PG_GETARG_TEXT_P(0); 13 | char *msgstr = text_to_cstring(msgtext); 14 | fprintf(stderr, "elogging internal error as requested (%s)\n", msgstr); 15 | elog(ERROR, "Internal Error requested (%s)", msgstr); 16 | } 17 | -------------------------------------------------------------------------------- /fuzz-functions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import os 4 | import psycopg2 5 | import sys 6 | import pprint 7 | import itertools 8 | 9 | # xml requires xml support 10 | testable_types = ['text','cstring','bytea','name','json','jsonb'] 11 | testable_types_sql = '[' + ','.join(["'%s'" % t for t in testable_types]) + ']' 12 | 13 | functions_query = ( 14 | "SELECT proname, proargtypes::regtype[]::text[]" 15 | " FROM pg_proc" 16 | " WHERE (provolatile = 'i' OR provolatile = 's')" 17 | " AND proargtypes::regtype[] && array["+testable_types_sql+"]::regtype[]" 18 | " AND NOT proargtypes::regtype[] && array['internal']::regtype[]" 19 | " AND provariadic = 0" 20 | " AND NOT proisagg" 21 | " AND NOT proiswindow" 22 | ) 23 | 24 | conn_string = "host='/tmp'" 25 | 26 | # These are just too slow to fuzz 27 | problem_functions = [ 28 | 'ts_debug', 29 | 'database_to_xmlschema', 30 | 'database_to_xml', 31 | 'database_to_xml_and_xmlschema', 32 | 'nameregexeq', 33 | 'nameregexne', 34 | 'textregexeq', 35 | 'textregexne', 36 | 'texticregexeq', 37 | 'texticregexne', 38 | 'nameicregexeq', 39 | 'nameicregexne', 40 | 'bpcharicregexeq', 41 | 'bpcharicregexne', 42 | 'bpcharregexeq', 43 | 'bpcharregexne', 44 | 'regexp_replace', 45 | 'regexp_replace', 46 | 'regexp_match', 47 | 'regexp_match', 48 | 'regexp_matches', 49 | 'regexp_matches', 50 | 'regexp_split_to_table', 51 | 'regexp_split_to_table', 52 | 'regexp_split_to_array', 53 | 'regexp_split_to_array', 54 | 'regexeqsel', 55 | 'icregexeqsel', 56 | 'regexnesel', 57 | 'icregexnesel', 58 | 'regexeqjoinsel', 59 | 'icregexeqjoinsel', 60 | 'regexnejoinsel', 61 | 'icregexnejoinsel', 62 | # substring(text,text) and substring(text,text,text) are regex functions 63 | 'substring', 64 | ] 65 | 66 | dummy_args = { 67 | # '"any"' : '', 68 | # 'anyarray' : '', 69 | # 'anyelement' : '', 70 | # 'anynonarray' : '', 71 | # 'refcursor' : '', 72 | # 'xml' : '', 73 | 74 | 'abstime' : ['0'], 75 | 'bigint' : ['0'], 76 | 'boolean' : ['f'], 77 | 'bytea' : [''], 78 | 'character' : [''], 79 | 'date' : ['2000-01-01'], 80 | 'double precision' : ['0.0'], 81 | 'integer' : ['0'], 82 | 'interval' : ['1 second'], 83 | 'json' : ['{}'], 84 | 'jsonb' : ['{}'], 85 | 'name' : [''], 86 | 'numeric' : ['0'], 87 | 'oid' : ['23'], 88 | 'real' : ['0.0'], 89 | 'regclass' : ['pg_proc'], 90 | 'regconfig' : ['3748'], 91 | 'regdictionary' : ['37650'], 92 | 'reltime' : ['0'], 93 | 'smallint' : ['0'], 94 | 'text' : [''], 95 | 'text[]' : ['{}'], 96 | 'time with time zone' : ['12:00:00'], 97 | 'time without time zone' : ['12:00:00'], 98 | 'timestamp with time zone' : ['2000-01-01 12:00:00'], 99 | 'timestamp without time zone' : ['2000-01-01 12:00:00'], 100 | 'tsquery' : [''], 101 | 'tsvector' : [''], 102 | } 103 | 104 | def fuzz(proname, proargs, arg_to_test): 105 | arglists = [] 106 | for i in range(0,len(proargs)): 107 | arg = proargs[i] 108 | if i == arg_to_test: 109 | arglists.append(["$1::%s" % proargs[i]]) 110 | elif arg not in dummy_args: 111 | return 112 | else: 113 | arglists.append(["'%s'::%s" % (d,proargs[i]) for d in dummy_args[proargs[i]]]) 114 | for args in itertools.product(*arglists): 115 | query = 'select "%s"(%s)' % (proname, ', '.join(args)) 116 | print(query) 117 | 118 | # Need a fresh connection due to fuzzer being only capable of running once 119 | with psycopg2.connect(conn_string) as connection: 120 | with connection.cursor() as cur: 121 | cur.execute("set max_stack_depth='7680kB'") 122 | try: 123 | cur.execute("select fuzz(100000, '%s')" % query.replace("'", "''")) 124 | except psycopg2.Error as e: 125 | print e.pgcode 126 | print e.pgerror 127 | pass 128 | 129 | def main(): 130 | with psycopg2.connect(conn_string) as connection: 131 | with connection.cursor() as cur: 132 | cur.execute(functions_query) 133 | functions = cur.fetchall() 134 | for f in functions: 135 | (proname,proargs) = f 136 | if proname in problem_functions: 137 | continue 138 | if proname.find("regex") > -1: 139 | print "skipping regex function %s" % proname 140 | continue 141 | for i in range(0,len(proargs)): 142 | if proargs[i] in testable_types: 143 | fuzz(proname, proargs, i) 144 | 145 | if __name__ == "__main__": 146 | main() 147 | -------------------------------------------------------------------------------- /make.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -v -x 3 | 4 | # Clean 5 | rm *.o 6 | 7 | # Build standard .cpp files from LLVM 8 | for i in Fuzzer*.cpp ; do clang++ -fPIC -c -std=c++11 $i ; done 9 | 10 | # We don't want FuzzerMain 11 | rm FuzzerMain.o 12 | 13 | # We want our harness instead that provides an InvokeFuzzer() call 14 | clang++ -Wno-writable-strings -fPIC -c -std=c++11 test_harness.cpp 15 | 16 | # And our function to fuzz 17 | #clang -fPIC -c -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters test_function.c 18 | 19 | # And our dummy main() Which calls InvokeFuzzer() 20 | #clang -c test_main.c 21 | # And our PG function entry point which calls InvokeFuzzer() 22 | clang -I`/usr/local/pgsql/bin/pg_config --includedir-server` -fPIC -c test_pg.c 23 | 24 | # Now link them all together 25 | clang++ -shared -o test.so -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters *.o 26 | -------------------------------------------------------------------------------- /test_function.c: -------------------------------------------------------------------------------- 1 | #include "postgres.h" 2 | #include "fmgr.h" 3 | 4 | #include "tsearch/ts_type.h" 5 | 6 | extern void InvokeFuzzer(); 7 | 8 | 9 | void LLVMFuzzerTestOneInput(const unsigned char *Data, size_t Size) { 10 | static StringInfoData data; 11 | data.data = Data; 12 | data.len = Size; 13 | data.maxlen = Size; 14 | data.cursor = 0; 15 | 16 | Datum retval; 17 | 18 | retval = DirectFunctionCall1(tsvectorrecv, 19 | &data, /* fake stringinfo */ 20 | InvalidOid, /* typeelem */ 21 | -1 /* typmod */ 22 | ); 23 | (void) retval; 24 | } 25 | -------------------------------------------------------------------------------- /test_harness.cpp: -------------------------------------------------------------------------------- 1 | #include "Fuzzer/FuzzerInterface.h" 2 | #include "Fuzzer/FuzzerInternal.h" 3 | #include 4 | #include 5 | 6 | extern "C" int FuzzOne(const uint8_t *Data, size_t Size); 7 | extern "C" int GoFuzz(unsigned runs); 8 | extern "C" void aborthandler(int signum, siginfo_t *info, void *cxt); 9 | extern "C" void staticdeathcallback(); 10 | //extern "C" void errorcallback(const char *errorname); 11 | 12 | int GoFuzz(unsigned runs) { 13 | char runarg[] = "-runs=400000000999"; 14 | sprintf(runarg, "-runs=%u", runs); 15 | char *argvdata[] = { 16 | "PostgresFuzzer", 17 | runarg, 18 | "-verbosity=1", 19 | "-only_ascii=1", 20 | "-timeout=60", 21 | "-report_slow_units=1", 22 | "-handle_int=0", 23 | "-use_counters=1", 24 | "-use_indir_calls=1", 25 | "-use_memcmp=1", 26 | "-use_memmem=1", 27 | "-use_value_profile=1", 28 | "/var/tmp/corpus", 29 | "-max_len=32", 30 | NULL 31 | }; 32 | char **argv = argvdata; 33 | int argc = sizeof(argvdata)/sizeof(*argvdata) - 1; 34 | 35 | /* Catch abort and print out the test case */ 36 | struct sigaction sigact; 37 | memset(&sigact, 0, sizeof(sigact)); 38 | sigact.sa_sigaction = aborthandler; 39 | sigaction(SIGABRT, &sigact, 0); 40 | 41 | return fuzzer::FuzzerDriver(&argc, &argv, FuzzOne); 42 | } 43 | 44 | void aborthandler(int signum, siginfo_t *info, void *cxt) { 45 | #if 0 46 | fuzzer::Fuzzer::StaticDeathCallback(); 47 | exit(0); 48 | #endif 49 | raise(SIGSEGV); 50 | } 51 | 52 | //void staticdeathcallback() { 53 | // fuzzer::Fuzzer::StaticDeathCallback(); 54 | //} 55 | 56 | //void errorcallback(const char *errorname) { 57 | // fuzzer::Fuzzer::StaticErrorCallback(errorname); 58 | //} 59 | -------------------------------------------------------------------------------- /test_main.c: -------------------------------------------------------------------------------- 1 | extern void InvokeFuzzer(); 2 | 3 | 4 | int main (int argc, char *argv[], char *envp[]) { 5 | InvokeFuzzer(); 6 | } 7 | -------------------------------------------------------------------------------- /test_pg.c: -------------------------------------------------------------------------------- 1 | #include "postgres.h" 2 | #include "funcapi.h" 3 | #include "executor/spi.h" 4 | #include "miscadmin.h" 5 | #include "storage/ipc.h" 6 | #include "catalog/pg_type.h" 7 | #include "utils/array.h" 8 | #include "utils/timeout.h" 9 | #include "utils/builtins.h" 10 | #include "utils/memutils.h" 11 | #include "utils/guc.h" 12 | #include "access/xact.h" 13 | #include "regex/regex.h" 14 | #include "lib/stringinfo.h" 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | extern void GoFuzz(); 21 | //extern void staticdeathcallback(); 22 | //extern void errorcallback(const char *errorname); 23 | 24 | static int in_fuzzer; 25 | 26 | PG_MODULE_MAGIC; 27 | 28 | SPIPlanPtr plan; 29 | 30 | void fuzz_exit_handler(int code, Datum arg) { 31 | // if (in_fuzzer) 32 | // abort(); 33 | } 34 | 35 | 36 | static void limit_resources() { 37 | int i; 38 | struct rlimit old, new; 39 | struct { 40 | char *resource_name; 41 | int resource; 42 | rlim_t new_soft_limit; 43 | rlim_t new_hard_limit; 44 | } limits[] = { 45 | // { "max memory size", RLIMIT_AS, 200000000 }, 46 | { "core file size", RLIMIT_CORE, 0 , 0}, 47 | // { "cpu time", RLIMIT_CPU, 1, 300}, 48 | { "data seg size", RLIMIT_DATA, 200000000, RLIM_INFINITY}, 49 | }; 50 | 51 | for (i=0; i old.rlim_max) 61 | new.rlim_max = old.rlim_max; 62 | fprintf(stderr, "Setting %s to %zd / %zd (was %zd / %zd)\n", 63 | limits[i].resource_name, 64 | new.rlim_cur, new.rlim_max, 65 | old.rlim_cur, old.rlim_max); 66 | retval = setrlimit(limits[i].resource, &new); 67 | if (retval < 0) { 68 | perror("setrlimit"); 69 | abort(); 70 | } 71 | } 72 | } 73 | 74 | PG_FUNCTION_INFO_V1(test_fuzz_environment); 75 | Datum 76 | test_fuzz_environment(PG_FUNCTION_ARGS){ 77 | elog(WARNING, "setting rlimit"); 78 | limit_resources(); 79 | 80 | elog(WARNING, "setting statement_timeout"); 81 | SetConfigOption("statement_timeout", "200", PGC_SUSET, PGC_S_OVERRIDE); 82 | elog(WARNING, "setting max_stack_depth"); 83 | SetConfigOption("set max_stack_depth", "7680kB", PGC_SUSET, PGC_S_OVERRIDE); 84 | 85 | PG_RETURN_NULL(); 86 | } 87 | 88 | /* Postgres SQL Function to invoke fuzzer */ 89 | 90 | /* 91 | Current project... surface progress reports via SQL return values and INFO/WARNING logs. 92 | 93 | Progress report from fuzzer looks like: 94 | 95 | #27718 INITED cov: 870 bits: 994 indir: 198 corp: 7/31b exec/s: 13859 rss: 388Mb 96 | #32768 pulse cov: 1477 bits: 1731 indir: 203 corp: 40/292b exec/s: 6553 rss: 457Mb 97 | #34008 NEW cov: 1477 bits: 1732 indir: 203 corp: 41/295b exec/s: 6801 rss: 458Mb L: 3 MS: 2 ChangeByte-ChangeBit- 98 | #27718 DONE cov: 870 bits: 994 indir: 198 corp: 7/31b exec/s: 13859 rss: 388Mb 99 | 100 | Progress reports from here look like: 101 | 102 | FuzzOne n=65536 success=0 fail=65536 null=0 103 | Error codes seen 42601:60539 42704:3460 22023:166 3F000:242 22P02:194 0A000:24 22003:80 22021:476 22025:355 104 | 105 | */ 106 | 107 | PG_FUNCTION_INFO_V1(fuzz); 108 | Datum 109 | fuzz(PG_FUNCTION_ARGS) 110 | { 111 | unsigned runs = PG_GETARG_INT32(0); 112 | text *expr_text = PG_GETARG_TEXT_P(1); 113 | char *expr = text_to_cstring(expr_text); 114 | Oid argtypes[1] = { TEXTOID }; 115 | int retval; 116 | static unsigned ever_called_before = 0; 117 | 118 | if (ever_called_before++) { 119 | elog(ERROR, "Fuzzer can only be used once, reconnect to a new process to run again"); 120 | } 121 | 122 | if (atoi(GetConfigOptionByName("max_stack_depth", NULL, false)) < 7680) { 123 | elog(WARNING, "setting max_stack_depth"); 124 | SetConfigOption("max_stack_depth", "7680", PGC_SUSET, PGC_S_OVERRIDE); 125 | } 126 | 127 | if (runs > 400000000) 128 | elog(ERROR, "Unreasonable number of runs"); 129 | 130 | limit_resources(); 131 | 132 | /* If Postgres handles a FATAL error it'll exit cleanly but we 133 | * want to treat the last test as a failure */ 134 | on_proc_exit(fuzz_exit_handler, 0); 135 | in_fuzzer = 1; 136 | 137 | retval = SPI_connect(); 138 | if (retval != SPI_OK_CONNECT) 139 | abort(); 140 | 141 | /* Prepare once before we start the driver */ 142 | plan = SPI_prepare(expr, 1, argtypes); 143 | if (!plan) 144 | elog(ERROR, "Failed to plan query"); 145 | 146 | retval = SPI_getargcount(plan); 147 | if (retval != 1) 148 | elog(ERROR, "Query to fuzz must take precisely one parameter"); 149 | 150 | /* Invoke the driver via the test_harness.cpp C++ code */ 151 | 152 | GoFuzz(runs); 153 | 154 | SPI_finish(); 155 | 156 | /* disable the proc_exit call which calls the deathcallback */ 157 | in_fuzzer = 0; 158 | 159 | PG_RETURN_NULL(); 160 | } 161 | 162 | static struct { 163 | int errcode; 164 | int count; 165 | } errcode_counts[100]; 166 | int num_counts; 167 | 168 | static int inc_errcode_count(int errcode) { 169 | int i; 170 | for (i=0;i= 100) 176 | abort(); 177 | errcode_counts[num_counts].errcode = errcode; 178 | errcode_counts[num_counts].count = 1; 179 | num_counts++; 180 | return 1; 181 | } 182 | static void list_errcode_counts() { 183 | int i; 184 | fprintf(stderr, "Error codes seen"); 185 | for (i=0; idata); 206 | } 207 | 208 | 209 | 210 | /* 211 | * Callback from fuzzer to execute one fuzz test case as set up in 212 | * global "plan" variable by fuzz() 213 | */ 214 | 215 | int FuzzOne(const char *Data, size_t Size) { 216 | text *arg = cstring_to_text_with_len(Data, Size); 217 | 218 | static unsigned long n_execs, n_success, n_fail, n_null; 219 | static int last_error, last_error_count; 220 | MemoryContext oldcontext = CurrentMemoryContext; 221 | ResourceOwner oldowner = CurrentResourceOwner; 222 | 223 | n_execs++; 224 | 225 | /* Not sure why we're being passed NULL */ 226 | if (!Data) { 227 | n_null++; 228 | return 0; 229 | } 230 | 231 | BeginInternalSubTransaction(NULL); 232 | PG_TRY(); 233 | { 234 | Datum values[1] = { PointerGetDatum(arg) }; 235 | int retval; 236 | 237 | /* Slow queries are bad but if they CHECK_FOR_INTERRUPTS often 238 | enough then that's not too bad. We must directly call 239 | enable_timeout because STATEMENT_TIMEOUT is only armed in 240 | postgres.c which SPI bypasses */ 241 | CHECK_FOR_INTERRUPTS(); 242 | enable_timeout_after(STATEMENT_TIMEOUT, 100); 243 | 244 | retval = SPI_execute_plan(plan, values, 245 | NULL /* nulls */, 246 | true, /* read-only */ 247 | 0 /* max rows */); 248 | disable_timeout(STATEMENT_TIMEOUT, true); 249 | 250 | SPI_freetuptable(SPI_tuptable); 251 | 252 | if (retval == SPI_OK_SELECT) 253 | n_success++; 254 | else if (retval >= 0) 255 | fprintf(stderr, "SPI reports non-select run retval=%d\n", retval); 256 | else 257 | abort(); 258 | 259 | last_error_count = 0; 260 | last_error = 0; 261 | 262 | ReleaseCurrentSubTransaction(); 263 | MemoryContextSwitchTo(oldcontext); 264 | CurrentResourceOwner = oldowner; 265 | SPI_restore_connection(); 266 | } 267 | PG_CATCH(); 268 | { 269 | /* Save error info */ 270 | MemoryContextSwitchTo(oldcontext); 271 | disable_timeout(STATEMENT_TIMEOUT, true); 272 | 273 | ErrorData *edata = CopyErrorData(); 274 | inc_errcode_count(edata->sqlerrcode); 275 | 276 | 277 | /* Allow C-c to cancel the whole fuzzer */ 278 | if (edata->sqlerrcode == ERRCODE_QUERY_CANCELED && 279 | strstr(edata->message, "due to user request")) { 280 | in_fuzzer = 0; 281 | PG_RE_THROW(); 282 | } else if (last_error != edata->sqlerrcode) { 283 | /* New error seen -- that's a good thing */ 284 | last_error = edata->sqlerrcode; 285 | last_error_count = 0; 286 | } else if (last_error_count++ > 10) { 287 | /* If we're repeatedly hitting the same errcode over 288 | * and over abort because that's usually a sign the 289 | * harness isn't working properly */ 290 | in_fuzzer = 0; 291 | PG_RE_THROW(); 292 | } 293 | 294 | /* Otherwise attempt to recover using the subtransaction */ 295 | FlushErrorState(); 296 | 297 | /* Abort the inner transaction */ 298 | RollbackAndReleaseCurrentSubTransaction(); 299 | MemoryContextSwitchTo(oldcontext); 300 | CurrentResourceOwner = oldowner; 301 | 302 | SPI_restore_connection(); 303 | 304 | n_fail++; 305 | 306 | /* INTERNAL_ERROR is definitely a bug. The others debatable 307 | * but in particular we're interested in infinite recursion 308 | * caught by check_for_stack_depth() which shows up as 309 | * STATEMENT_TOO_COMPLEX which is in the 310 | * PROGRAM_LIMIT_EXCEEDED category 311 | */ 312 | 313 | int errcategory = ERRCODE_TO_CATEGORY(edata->sqlerrcode); 314 | int regerrcode = -1; 315 | char regerrstr[256]; 316 | 317 | if (edata->sqlerrcode == ERRCODE_INVALID_REGULAR_EXPRESSION) { 318 | char *p = strrchr(edata->message, ':'); 319 | if (p && p[1] == ' ') 320 | p += 2; 321 | if (p && p[0]) { 322 | strncpy(regerrstr, p, 256); 323 | pg_regerror(REG_ATOI, NULL, regerrstr, 256); 324 | regerrcode = atoi(regerrstr); 325 | } 326 | } 327 | 328 | if (errcategory == ERRCODE_PROGRAM_LIMIT_EXCEEDED || 329 | errcategory == ERRCODE_INSUFFICIENT_RESOURCES || 330 | // errcategory == ERRCODE_OPERATOR_INTERVENTION || /* statement_timeout */ 331 | errcategory == ERRCODE_INTERNAL_ERROR || 332 | (edata->sqlerrcode == ERRCODE_INVALID_REGULAR_EXPRESSION && 333 | (regerrcode == REG_ESPACE || 334 | regerrcode == REG_ASSERT || 335 | //regerrcode == REG_ETOOBIG || 336 | //regerrcode == REG_CANCEL || 337 | regerrcode == REG_INVARG || 338 | regerrcode == REG_MIXED || 339 | regerrcode == REG_ECOLORS))) 340 | { 341 | if (in_fuzzer) { 342 | char errorname[80]; 343 | sprintf(errorname, "error-%s", unpack_sql_state(edata->sqlerrcode)); 344 | fprintf(stderr, "Calling errocallback for %s (%s)\n", errorname, edata->message); 345 | // errorcallback(errorname); 346 | } 347 | 348 | /* we were in a subtransaction so yay we can continue */ 349 | FreeErrorData(edata); 350 | } 351 | else 352 | { 353 | last_error = 0; 354 | last_error_count = 0; 355 | 356 | FreeErrorData(edata); 357 | } 358 | } 359 | PG_END_TRY(); 360 | 361 | pfree(arg); 362 | 363 | /* Every power of two executions print progress */ 364 | if ((n_execs & (n_execs-1)) == 0) { 365 | static int old_n_execs; 366 | fprintf(stderr, "FuzzOne n=%lu success=%lu fail=%lu null=%lu\n", n_execs, n_success, n_fail, n_null); 367 | jsonb_errcode_counts(); 368 | old_n_execs = n_execs; 369 | } 370 | 371 | return 0; 372 | } 373 | 374 | 375 | 376 | -------------------------------------------------------------------------------- /test_pg_simple.c: -------------------------------------------------------------------------------- 1 | #include "postgres.h" 2 | #include "funcapi.h" 3 | #include "executor/spi.h" 4 | #include "miscadmin.h" 5 | #include "storage/ipc.h" 6 | #include "catalog/pg_type.h" 7 | #include "utils/array.h" 8 | #include "utils/timeout.h" 9 | #include "utils/builtins.h" 10 | #include "utils/memutils.h" 11 | #include "utils/guc.h" 12 | #include "access/xact.h" 13 | #include "regex/regex.h" 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | extern void GoFuzz(); 20 | extern void staticdeathcallback(); 21 | extern void errorcallback(const char *errorname); 22 | 23 | static int in_fuzzer; 24 | 25 | PG_MODULE_MAGIC; 26 | 27 | SPIPlanPtr plan; 28 | 29 | void fuzz_exit_handler(int code, Datum arg) { 30 | if (in_fuzzer) 31 | abort(); 32 | } 33 | 34 | 35 | static void limit_resources() { 36 | int i; 37 | struct rlimit old, new; 38 | struct { 39 | char *resource_name; 40 | int resource; 41 | rlim_t new_soft_limit; 42 | rlim_t new_hard_limit; 43 | } limits[] = { 44 | // { "max memory size", RLIMIT_AS, 200000000 }, 45 | { "core file size", RLIMIT_CORE, 0 , 0}, 46 | // { "cpu time", RLIMIT_CPU, 1, 300}, 47 | { "data seg size", RLIMIT_DATA, 200000000, RLIM_INFINITY}, 48 | }; 49 | 50 | for (i=0; i old.rlim_max) 60 | new.rlim_max = old.rlim_max; 61 | fprintf(stderr, "Setting %s to %zd / %zd (was %zd / %zd)\n", 62 | limits[i].resource_name, 63 | new.rlim_cur, new.rlim_max, 64 | old.rlim_cur, old.rlim_max); 65 | retval = setrlimit(limits[i].resource, &new); 66 | if (retval < 0) { 67 | perror("setrlimit"); 68 | abort(); 69 | } 70 | } 71 | } 72 | 73 | PG_FUNCTION_INFO_V1(test_fuzz_environment); 74 | Datum 75 | test_fuzz_environment(PG_FUNCTION_ARGS){ 76 | elog(WARNING, "setting rlimit"); 77 | limit_resources(); 78 | 79 | elog(WARNING, "setting statement_timeout"); 80 | SetConfigOption("statement_timeout", "200", PGC_SUSET, PGC_S_OVERRIDE); 81 | 82 | PG_RETURN_NULL(); 83 | } 84 | 85 | /* Postgres SQL Function to invoke fuzzer */ 86 | 87 | SPIPlanPtr plan; 88 | 89 | PG_FUNCTION_INFO_V1(fuzz); 90 | Datum 91 | fuzz(PG_FUNCTION_ARGS) 92 | { 93 | unsigned runs = PG_GETARG_INT32(0); 94 | text *expr_text = PG_GETARG_TEXT_P(1); 95 | char *expr = text_to_cstring(expr_text); 96 | Oid argtypes[1] = { TEXTOID }; 97 | 98 | struct rlimit new; 99 | new.rlim_cur = new.rlim_max = 0; 100 | setrlimit(RLIMIT_CORE, &new); 101 | new.rlim_cur = 1; new.rlim_max = 300; 102 | setrlimit(RLIMIT_CPU, &new); 103 | new.rlim_cur = 200000000; new.rlim_max = RLIM_INFINITY; 104 | setrlimit(RLIMIT_DATA); 105 | 106 | SPI_connect(); 107 | /* Prepare once before we start the driver */ 108 | plan = SPI_prepare(expr, 1, argtypes); 109 | /* Invoke the driver via the C++ code */ 110 | GoFuzz(runs); 111 | SPI_finish(); 112 | 113 | PG_RETURN_NULL(); 114 | } 115 | 116 | static struct { 117 | int errcode; 118 | int count; 119 | } errcode_counts[100]; 120 | int num_counts; 121 | 122 | static int inc_errcode_count(int errcode) { 123 | int i; 124 | for (i=0;i= 100) 130 | abort(); 131 | errcode_counts[num_counts].errcode = errcode; 132 | errcode_counts[num_counts].count = 1; 133 | num_counts++; 134 | return 1; 135 | } 136 | static void list_errcode_counts() { 137 | int i; 138 | fprintf(stderr, "Error codes seen"); 139 | for (i=0; isqlerrcode); 190 | 191 | 192 | /* Attempt to recover using the subtransaction */ 193 | FlushErrorState(); 194 | /* Abort the inner transaction */ 195 | RollbackAndReleaseCurrentSubTransaction(); 196 | MemoryContextSwitchTo(oldcontext); 197 | CurrentResourceOwner = oldowner; 198 | SPI_restore_connection(); 199 | 200 | 201 | /* INTERNAL_ERROR is definitely a bug. The others debatable but in 202 | * particular we're interested in infinite recursion caught by 203 | * check_for_stack_depth() which shows up as STATEMENT_TOO_COMPLEX 204 | * which is in the PROGRAM_LIMIT_EXCEEDED category 205 | */ 206 | int errcategory = ERRCODE_TO_CATEGORY(edata->sqlerrcode); 207 | int regerrcode = ... // elided for space 208 | 209 | if (errcategory == ERRCODE_PROGRAM_LIMIT_EXCEEDED || 210 | errcategory == ERRCODE_INSUFFICIENT_RESOURCES || 211 | errcategory == ERRCODE_INTERNAL_ERROR || 212 | (edata->sqlerrcode == ERRCODE_INVALID_REGULAR_EXPRESSION && 213 | (regerrcode == REG_ESPACE || regerrcode == REG_ASSERT || 214 | regerrcode == REG_INVARG || regerrcode == REG_MIXED || 215 | regerrcode == REG_ECOLORS))) 216 | { 217 | char errorname[80]; 218 | sprintf(errorname, "error-%s", unpack_sql_state(edata->sqlerrcode)); 219 | fprintf(stderr, "Calling errocallback for %s (%s)\n", 220 | errorname, edata->message); 221 | errorcallback(errorname); 222 | FreeErrorData(edata); 223 | } 224 | else 225 | FreeErrorData(edata); 226 | } 227 | PG_END_TRY(); 228 | 229 | pfree(arg); 230 | 231 | /* Every power of two executions print progress */ 232 | if ((n_execs & (n_execs-1)) == 0) { 233 | static int old_n_execs; 234 | fprintf(stderr, "FuzzOne n=%lu success=%lu fail=%lu null=%lu\n", n_execs, n_success, n_fail, n_null); 235 | list_errcode_counts(); 236 | old_n_execs = n_execs; 237 | } 238 | } 239 | 240 | 241 | 242 | --------------------------------------------------------------------------------