aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Fuzzer
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Fuzzer')
-rw-r--r--lib/Fuzzer/CMakeLists.txt21
-rw-r--r--lib/Fuzzer/FuzzerCrossOver.cpp47
-rw-r--r--lib/Fuzzer/FuzzerDriver.cpp199
-rw-r--r--lib/Fuzzer/FuzzerFlags.def45
-rw-r--r--lib/Fuzzer/FuzzerIO.cpp57
-rw-r--r--lib/Fuzzer/FuzzerInterface.h25
-rw-r--r--lib/Fuzzer/FuzzerInternal.h104
-rw-r--r--lib/Fuzzer/FuzzerLoop.cpp233
-rw-r--r--lib/Fuzzer/FuzzerMain.cpp20
-rw-r--r--lib/Fuzzer/FuzzerMutate.cpp70
-rw-r--r--lib/Fuzzer/FuzzerSanitizerOptions.cpp18
-rw-r--r--lib/Fuzzer/FuzzerUtil.cpp61
-rw-r--r--lib/Fuzzer/README.txt112
-rw-r--r--lib/Fuzzer/test/CMakeLists.txt61
-rw-r--r--lib/Fuzzer/test/FourIndependentBranchesTest.cpp18
-rw-r--r--lib/Fuzzer/test/FullCoverageSetTest.cpp20
-rw-r--r--lib/Fuzzer/test/FuzzerUnittest.cpp62
-rw-r--r--lib/Fuzzer/test/InfiniteTest.cpp20
-rw-r--r--lib/Fuzzer/test/NullDerefTest.cpp22
-rw-r--r--lib/Fuzzer/test/SimpleTest.cpp21
-rw-r--r--lib/Fuzzer/test/TimeoutTest.cpp22
-rw-r--r--lib/Fuzzer/test/fuzzer.test19
-rw-r--r--lib/Fuzzer/test/lit.cfg14
-rw-r--r--lib/Fuzzer/test/lit.site.cfg.in3
-rw-r--r--lib/Fuzzer/test/unit/lit.cfg7
-rw-r--r--lib/Fuzzer/test/unit/lit.site.cfg.in2
26 files changed, 1303 insertions, 0 deletions
diff --git a/lib/Fuzzer/CMakeLists.txt b/lib/Fuzzer/CMakeLists.txt
new file mode 100644
index 0000000..81e51d1
--- /dev/null
+++ b/lib/Fuzzer/CMakeLists.txt
@@ -0,0 +1,21 @@
+# Disable the coverage instrumentation for the fuzzer itself.
+set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -fsanitize-coverage=0")
+if( LLVM_USE_SANITIZE_COVERAGE )
+ add_library(LLVMFuzzerNoMain OBJECT
+ FuzzerCrossOver.cpp
+ FuzzerDriver.cpp
+ FuzzerIO.cpp
+ FuzzerLoop.cpp
+ FuzzerMutate.cpp
+ FuzzerSanitizerOptions.cpp
+ FuzzerUtil.cpp
+ )
+ add_library(LLVMFuzzer STATIC
+ FuzzerMain.cpp
+ $<TARGET_OBJECTS:LLVMFuzzerNoMain>
+ )
+
+ if( LLVM_INCLUDE_TESTS )
+ add_subdirectory(test)
+ endif()
+endif()
diff --git a/lib/Fuzzer/FuzzerCrossOver.cpp b/lib/Fuzzer/FuzzerCrossOver.cpp
new file mode 100644
index 0000000..94af6d5
--- /dev/null
+++ b/lib/Fuzzer/FuzzerCrossOver.cpp
@@ -0,0 +1,47 @@
+//===- FuzzerCrossOver.cpp - Cross over two test inputs -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Cross over test inputs.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerInternal.h"
+#include <algorithm>
+
+namespace fuzzer {
+
+// Cross A and B, store the result (ap to MaxLen bytes) in U.
+void CrossOver(const Unit &A, const Unit &B, Unit *U, size_t MaxLen) {
+ size_t Size = rand() % MaxLen + 1;
+ U->clear();
+ const Unit *V = &A;
+ size_t PosA = 0;
+ size_t PosB = 0;
+ size_t *Pos = &PosA;
+ while (U->size() < Size && (PosA < A.size() || PosB < B.size())) {
+ // Merge a part of V into U.
+ size_t SizeLeftU = Size - U->size();
+ if (*Pos < V->size()) {
+ size_t SizeLeftV = V->size() - *Pos;
+ size_t MaxExtraSize = std::min(SizeLeftU, SizeLeftV);
+ size_t ExtraSize = rand() % MaxExtraSize + 1;
+ U->insert(U->end(), V->begin() + *Pos, V->begin() + *Pos + ExtraSize);
+ (*Pos) += ExtraSize;
+ }
+
+ // Use the other Unit on the next iteration.
+ if (Pos == &PosA) {
+ Pos = &PosB;
+ V = &B;
+ } else {
+ Pos = &PosA;
+ V = &A;
+ }
+ }
+}
+
+} // namespace fuzzer
diff --git a/lib/Fuzzer/FuzzerDriver.cpp b/lib/Fuzzer/FuzzerDriver.cpp
new file mode 100644
index 0000000..1746afd
--- /dev/null
+++ b/lib/Fuzzer/FuzzerDriver.cpp
@@ -0,0 +1,199 @@
+//===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// FuzzerDriver and flag parsing.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerInterface.h"
+#include "FuzzerInternal.h"
+
+#include <cstring>
+#include <unistd.h>
+#include <iostream>
+#include <thread>
+#include <atomic>
+#include <mutex>
+
+namespace fuzzer {
+
+// Program arguments.
+struct FlagDescription {
+ const char *Name;
+ const char *Description;
+ int Default;
+ int *Flag;
+};
+
+struct {
+#define FUZZER_FLAG(Type, Name, Default, Description) Type Name;
+#include "FuzzerFlags.def"
+#undef FUZZER_FLAG
+} Flags;
+
+static FlagDescription FlagDescriptions [] {
+#define FUZZER_FLAG(Type, Name, Default, Description) {#Name, Description, Default, &Flags.Name},
+#include "FuzzerFlags.def"
+#undef FUZZER_FLAG
+};
+
+static const size_t kNumFlags =
+ sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]);
+
+static std::vector<std::string> inputs;
+static const char *ProgName;
+
+static void PrintHelp() {
+ std::cerr << "Usage: " << ProgName
+ << " [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n";
+ std::cerr << "\nFlags: (strictly in form -flag=value)\n";
+ size_t MaxFlagLen = 0;
+ for (size_t F = 0; F < kNumFlags; F++)
+ MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen);
+
+ for (size_t F = 0; F < kNumFlags; F++) {
+ const auto &D = FlagDescriptions[F];
+ std::cerr << " " << D.Name;
+ for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++)
+ std::cerr << " ";
+ std::cerr << "\t";
+ std::cerr << D.Default << "\t" << D.Description << "\n";
+ }
+}
+
+static const char *FlagValue(const char *Param, const char *Name) {
+ size_t Len = strlen(Name);
+ if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 &&
+ Param[Len + 1] == '=')
+ return &Param[Len + 2];
+ return nullptr;
+}
+
+static bool ParseOneFlag(const char *Param) {
+ if (Param[0] != '-') return false;
+ for (size_t F = 0; F < kNumFlags; F++) {
+ const char *Name = FlagDescriptions[F].Name;
+ const char *Str = FlagValue(Param, Name);
+ if (Str) {
+ int Val = std::stol(Str);
+ *FlagDescriptions[F].Flag = Val;
+ if (Flags.verbosity >= 2)
+ std::cerr << "Flag: " << Name << " " << Val << "\n";
+ return true;
+ }
+ }
+ PrintHelp();
+ exit(1);
+}
+
+// We don't use any library to minimize dependencies.
+static void ParseFlags(int argc, char **argv) {
+ for (size_t F = 0; F < kNumFlags; F++)
+ *FlagDescriptions[F].Flag = FlagDescriptions[F].Default;
+ for (int A = 1; A < argc; A++) {
+ if (ParseOneFlag(argv[A])) continue;
+ inputs.push_back(argv[A]);
+ }
+}
+
+static void WorkerThread(const std::string &Cmd, std::atomic<int> *Counter,
+ int NumJobs, std::atomic<bool> *HasErrors) {
+ static std::mutex CerrMutex;
+ while (true) {
+ int C = (*Counter)++;
+ if (C >= NumJobs) break;
+ std::string Log = "fuzz-" + std::to_string(C) + ".log";
+ std::string ToRun = Cmd + " > " + Log + " 2>&1\n";
+ if (Flags.verbosity)
+ std::cerr << ToRun;
+ int ExitCode = system(ToRun.c_str());
+ if (ExitCode != 0)
+ *HasErrors = true;
+ std::lock_guard<std::mutex> Lock(CerrMutex);
+ std::cerr << "================== Job " << C
+ << " exited with exit code " << ExitCode
+ << " =================\n";
+ fuzzer::CopyFileToErr(Log);
+ }
+}
+
+static int RunInMultipleProcesses(int argc, char **argv, int NumWorkers,
+ int NumJobs) {
+ std::atomic<int> Counter(0);
+ std::atomic<bool> HasErrors(false);
+ std::string Cmd;
+ for (int i = 0; i < argc; i++) {
+ if (FlagValue(argv[i], "jobs") || FlagValue(argv[i], "workers")) continue;
+ Cmd += argv[i];
+ Cmd += " ";
+ }
+ std::vector<std::thread> V;
+ for (int i = 0; i < NumWorkers; i++)
+ V.push_back(std::thread(WorkerThread, Cmd, &Counter, NumJobs, &HasErrors));
+ for (auto &T : V)
+ T.join();
+ return HasErrors ? 1 : 0;
+}
+
+int FuzzerDriver(int argc, char **argv, UserCallback Callback) {
+ using namespace fuzzer;
+
+ ProgName = argv[0];
+ ParseFlags(argc, argv);
+ if (Flags.help) {
+ PrintHelp();
+ return 0;
+ }
+
+ if (Flags.workers > 0 && Flags.jobs > 0)
+ return RunInMultipleProcesses(argc, argv, Flags.workers, Flags.jobs);
+
+ Fuzzer::FuzzingOptions Options;
+ Options.Verbosity = Flags.verbosity;
+ Options.MaxLen = Flags.max_len;
+ Options.DoCrossOver = Flags.cross_over;
+ Options.MutateDepth = Flags.mutate_depth;
+ Options.ExitOnFirst = Flags.exit_on_first;
+ Options.UseFullCoverageSet = Flags.use_full_coverage_set;
+ Options.UseCoveragePairs = Flags.use_coverage_pairs;
+ Options.PreferSmallDuringInitialShuffle =
+ Flags.prefer_small_during_initial_shuffle;
+ if (Flags.runs >= 0)
+ Options.MaxNumberOfRuns = Flags.runs;
+ if (!inputs.empty())
+ Options.OutputCorpus = inputs[0];
+ Fuzzer F(Callback, Options);
+
+ unsigned seed = Flags.seed;
+ // Initialize seed.
+ if (seed == 0)
+ seed = time(0) * 10000 + getpid();
+ if (Flags.verbosity)
+ std::cerr << "Seed: " << seed << "\n";
+ srand(seed);
+
+ // Timer
+ if (Flags.timeout > 0)
+ SetTimer(Flags.timeout);
+
+ for (auto &inp : inputs)
+ F.ReadDir(inp);
+
+ if (F.CorpusSize() == 0)
+ F.AddToCorpus(Unit()); // Can't fuzz empty corpus, so add an empty input.
+ F.ShuffleAndMinimize();
+ if (Flags.save_minimized_corpus)
+ F.SaveCorpus();
+ F.Loop(Flags.iterations < 0 ? INT_MAX : Flags.iterations);
+ if (Flags.verbosity)
+ std::cerr << "Done " << F.getTotalNumberOfRuns()
+ << " runs in " << F.secondsSinceProcessStartUp()
+ << " seconds\n";
+ return 0;
+}
+
+} // namespace fuzzer
diff --git a/lib/Fuzzer/FuzzerFlags.def b/lib/Fuzzer/FuzzerFlags.def
new file mode 100644
index 0000000..068f245
--- /dev/null
+++ b/lib/Fuzzer/FuzzerFlags.def
@@ -0,0 +1,45 @@
+//===- FuzzerFlags.def - Run-time flags -------------------------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Flags. FUZZER_FLAG macro should be defined at the point of inclusion.
+// We are not using any flag parsing library for better portability and
+// independence.
+//===----------------------------------------------------------------------===//
+FUZZER_FLAG(int, verbosity, 1, "Verbosity level.")
+FUZZER_FLAG(int, seed, 0, "Random seed. If 0, seed is generated.")
+FUZZER_FLAG(int, iterations, -1,
+ "Number of iterations of the fuzzer internal loop"
+ " (-1 for infinite iterations).")
+FUZZER_FLAG(int, runs, -1,
+ "Number of individual test runs (-1 for infinite runs).")
+FUZZER_FLAG(int, max_len, 64, "Maximal length of the test input.")
+FUZZER_FLAG(int, cross_over, 1, "If 1, cross over inputs.")
+FUZZER_FLAG(int, mutate_depth, 5,
+ "Apply this number of consecutive mutations to each input.")
+FUZZER_FLAG(
+ int, prefer_small_during_initial_shuffle, -1,
+ "If 1, always prefer smaller inputs during the initial corpus shuffle."
+ " If 0, never do that. If -1, do it sometimes.")
+FUZZER_FLAG(int, exit_on_first, 0,
+ "If 1, exit after the first new interesting input is found.")
+FUZZER_FLAG(int, timeout, -1, "Timeout in seconds (if positive).")
+FUZZER_FLAG(int, help, 0, "Print help.")
+FUZZER_FLAG(
+ int, save_minimized_corpus, 0,
+ "If 1, the minimized corpus is saved into the first input directory")
+FUZZER_FLAG(int, use_full_coverage_set, 0,
+ "Experimental: Maximize the number of different full"
+ " coverage sets as opposed to maximizing the total coverage."
+ " This is potentially MUCH slower, but may discover more paths.")
+FUZZER_FLAG(int, use_coverage_pairs, 0,
+ "Experimental: Maximize the number of different coverage pairs.")
+FUZZER_FLAG(int, jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn"
+ " this number of jobs in separate worker processes"
+ " with stdout/stderr redirected to fuzz-JOB.log.")
+FUZZER_FLAG(int, workers, 0,
+ "Number of simultaneous worker processes to run the jobs.")
diff --git a/lib/Fuzzer/FuzzerIO.cpp b/lib/Fuzzer/FuzzerIO.cpp
new file mode 100644
index 0000000..224808c
--- /dev/null
+++ b/lib/Fuzzer/FuzzerIO.cpp
@@ -0,0 +1,57 @@
+//===- FuzzerIO.cpp - IO utils. -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// IO functions.
+//===----------------------------------------------------------------------===//
+#include "FuzzerInternal.h"
+#include <iostream>
+#include <iterator>
+#include <fstream>
+#include <dirent.h>
+namespace fuzzer {
+
+static std::vector<std::string> ListFilesInDir(const std::string &Dir) {
+ std::vector<std::string> V;
+ DIR *D = opendir(Dir.c_str());
+ if (!D) return V;
+ while (auto E = readdir(D)) {
+ if (E->d_type == DT_REG || E->d_type == DT_LNK)
+ V.push_back(E->d_name);
+ }
+ closedir(D);
+ return V;
+}
+
+Unit FileToVector(const std::string &Path) {
+ std::ifstream T(Path);
+ return Unit((std::istreambuf_iterator<char>(T)),
+ std::istreambuf_iterator<char>());
+}
+
+void CopyFileToErr(const std::string &Path) {
+ std::ifstream T(Path);
+ std::copy(std::istreambuf_iterator<char>(T), std::istreambuf_iterator<char>(),
+ std::ostream_iterator<char>(std::cerr, ""));
+}
+
+void WriteToFile(const Unit &U, const std::string &Path) {
+ std::ofstream OF(Path);
+ OF.write((const char*)U.data(), U.size());
+}
+
+void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V) {
+ for (auto &X : ListFilesInDir(Path))
+ V->push_back(FileToVector(DirPlusFile(Path, X)));
+}
+
+std::string DirPlusFile(const std::string &DirPath,
+ const std::string &FileName) {
+ return DirPath + "/" + FileName;
+}
+
+} // namespace fuzzer
diff --git a/lib/Fuzzer/FuzzerInterface.h b/lib/Fuzzer/FuzzerInterface.h
new file mode 100644
index 0000000..49d8c0f
--- /dev/null
+++ b/lib/Fuzzer/FuzzerInterface.h
@@ -0,0 +1,25 @@
+//===- FuzzerInterface.h - Interface header for the Fuzzer ------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Define the interface between the Fuzzer and the library being tested.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_INTERFACE_H
+#define LLVM_FUZZER_INTERFACE_H
+
+#include <cstddef>
+#include <cstdint>
+
+namespace fuzzer {
+
+typedef void (*UserCallback)(const uint8_t *data, size_t size);
+int FuzzerDriver(int argc, char **argv, UserCallback Callback);
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_INTERFACE_H
diff --git a/lib/Fuzzer/FuzzerInternal.h b/lib/Fuzzer/FuzzerInternal.h
new file mode 100644
index 0000000..980b00e
--- /dev/null
+++ b/lib/Fuzzer/FuzzerInternal.h
@@ -0,0 +1,104 @@
+//===- FuzzerInternal.h - Internal header for the Fuzzer --------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Define the main class fuzzer::Fuzzer and most functions.
+//===----------------------------------------------------------------------===//
+#include <cassert>
+#include <climits>
+#include <chrono>
+#include <cstddef>
+#include <cstdlib>
+#include <string>
+#include <vector>
+#include <unordered_set>
+
+#include "FuzzerInterface.h"
+
+namespace fuzzer {
+typedef std::vector<uint8_t> Unit;
+using namespace std::chrono;
+
+Unit ReadFile(const char *Path);
+void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V);
+void WriteToFile(const Unit &U, const std::string &Path);
+void CopyFileToErr(const std::string &Path);
+// Returns "Dir/FileName" or equivalent for the current OS.
+std::string DirPlusFile(const std::string &DirPath,
+ const std::string &FileName);
+
+void Mutate(Unit *U, size_t MaxLen);
+
+void CrossOver(const Unit &A, const Unit &B, Unit *U, size_t MaxLen);
+
+void Print(const Unit &U, const char *PrintAfter = "");
+void PrintASCII(const Unit &U, const char *PrintAfter = "");
+std::string Hash(const Unit &U);
+void SetTimer(int Seconds);
+
+class Fuzzer {
+ public:
+ struct FuzzingOptions {
+ int Verbosity = 1;
+ int MaxLen = 0;
+ bool DoCrossOver = true;
+ int MutateDepth = 5;
+ bool ExitOnFirst = false;
+ bool UseFullCoverageSet = false;
+ bool UseCoveragePairs = false;
+ int PreferSmallDuringInitialShuffle = -1;
+ size_t MaxNumberOfRuns = ULONG_MAX;
+ std::string OutputCorpus;
+ };
+ Fuzzer(UserCallback Callback, FuzzingOptions Options)
+ : Callback(Callback), Options(Options) {
+ SetDeathCallback();
+ }
+ void AddToCorpus(const Unit &U) { Corpus.push_back(U); }
+ size_t Loop(size_t NumIterations);
+ void ShuffleAndMinimize();
+ size_t CorpusSize() const { return Corpus.size(); }
+ void ReadDir(const std::string &Path) {
+ ReadDirToVectorOfUnits(Path.c_str(), &Corpus);
+ }
+ // Save the current corpus to OutputCorpus.
+ void SaveCorpus();
+
+ size_t secondsSinceProcessStartUp() {
+ return duration_cast<seconds>(system_clock::now() - ProcessStartTime)
+ .count();
+ }
+
+ size_t getTotalNumberOfRuns() { return TotalNumberOfRuns; }
+
+ static void AlarmCallback();
+
+ private:
+ size_t MutateAndTestOne(Unit *U);
+ size_t RunOne(const Unit &U);
+ size_t RunOneMaximizeTotalCoverage(const Unit &U);
+ size_t RunOneMaximizeFullCoverageSet(const Unit &U);
+ size_t RunOneMaximizeCoveragePairs(const Unit &U);
+ void WriteToOutputCorpus(const Unit &U);
+ static void WriteToCrash(const Unit &U, const char *Prefix);
+
+ void SetDeathCallback();
+ static void DeathCallback();
+ static Unit CurrentUnit;
+
+ size_t TotalNumberOfRuns = 0;
+
+ std::vector<Unit> Corpus;
+ std::unordered_set<uintptr_t> FullCoverageSets;
+ std::unordered_set<uint64_t> CoveragePairs;
+ UserCallback Callback;
+ FuzzingOptions Options;
+ system_clock::time_point ProcessStartTime = system_clock::now();
+ static system_clock::time_point UnitStartTime;
+};
+
+}; // namespace fuzzer
diff --git a/lib/Fuzzer/FuzzerLoop.cpp b/lib/Fuzzer/FuzzerLoop.cpp
new file mode 100644
index 0000000..70b63eb
--- /dev/null
+++ b/lib/Fuzzer/FuzzerLoop.cpp
@@ -0,0 +1,233 @@
+//===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Fuzzer's main loop.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerInternal.h"
+#include <sanitizer/coverage_interface.h>
+#include <algorithm>
+#include <iostream>
+
+namespace fuzzer {
+
+// static
+Unit Fuzzer::CurrentUnit;
+system_clock::time_point Fuzzer::UnitStartTime;
+
+void Fuzzer::SetDeathCallback() {
+ __sanitizer_set_death_callback(DeathCallback);
+}
+
+void Fuzzer::DeathCallback() {
+ std::cerr << "DEATH: " << std::endl;
+ Print(CurrentUnit, "\n");
+ PrintASCII(CurrentUnit, "\n");
+ WriteToCrash(CurrentUnit, "crash-");
+}
+
+void Fuzzer::AlarmCallback() {
+ size_t Seconds =
+ duration_cast<seconds>(system_clock::now() - UnitStartTime).count();
+ std::cerr << "ALARM: working on the last Unit for " << Seconds << " seconds"
+ << std::endl;
+ if (Seconds >= 3) {
+ Print(CurrentUnit, "\n");
+ PrintASCII(CurrentUnit, "\n");
+ WriteToCrash(CurrentUnit, "timeout-");
+ }
+ exit(1);
+}
+
+void Fuzzer::ShuffleAndMinimize() {
+ bool PreferSmall =
+ (Options.PreferSmallDuringInitialShuffle == 1 ||
+ (Options.PreferSmallDuringInitialShuffle == -1 && rand() % 2));
+ if (Options.Verbosity)
+ std::cerr << "Shuffle: Size: " << Corpus.size()
+ << " prefer small: " << PreferSmall
+ << "\n";
+ std::vector<Unit> NewCorpus;
+ std::random_shuffle(Corpus.begin(), Corpus.end());
+ if (PreferSmall)
+ std::stable_sort(
+ Corpus.begin(), Corpus.end(),
+ [](const Unit &A, const Unit &B) { return A.size() < B.size(); });
+ size_t MaxCov = 0;
+ Unit &U = CurrentUnit;
+ for (const auto &C : Corpus) {
+ for (size_t First = 0; First < 1; First++) {
+ U.clear();
+ size_t Last = std::min(First + Options.MaxLen, C.size());
+ U.insert(U.begin(), C.begin() + First, C.begin() + Last);
+ size_t NewCoverage = RunOne(U);
+ if (NewCoverage) {
+ MaxCov = NewCoverage;
+ NewCorpus.push_back(U);
+ if (Options.Verbosity >= 2)
+ std::cerr << "NEW0: " << NewCoverage
+ << " L " << U.size()
+ << "\n";
+ }
+ }
+ }
+ Corpus = NewCorpus;
+ if (Options.Verbosity)
+ std::cerr << "Shuffle done: " << Corpus.size() << " IC: " << MaxCov << "\n";
+}
+
+size_t Fuzzer::RunOne(const Unit &U) {
+ UnitStartTime = system_clock::now();
+ TotalNumberOfRuns++;
+ if (Options.UseFullCoverageSet)
+ return RunOneMaximizeFullCoverageSet(U);
+ if (Options.UseCoveragePairs)
+ return RunOneMaximizeCoveragePairs(U);
+ return RunOneMaximizeTotalCoverage(U);
+}
+
+static uintptr_t HashOfArrayOfPCs(uintptr_t *PCs, uintptr_t NumPCs) {
+ uintptr_t Res = 0;
+ for (uintptr_t i = 0; i < NumPCs; i++) {
+ Res = (Res + PCs[i]) * 7;
+ }
+ return Res;
+}
+
+// Experimental. Does not yet scale.
+// Fuly reset the current coverage state, run a single unit,
+// collect all coverage pairs and return non-zero if a new pair is observed.
+size_t Fuzzer::RunOneMaximizeCoveragePairs(const Unit &U) {
+ __sanitizer_reset_coverage();
+ Callback(U.data(), U.size());
+ uintptr_t *PCs;
+ uintptr_t NumPCs = __sanitizer_get_coverage_guards(&PCs);
+ bool HasNewPairs = false;
+ for (uintptr_t i = 0; i < NumPCs; i++) {
+ if (!PCs[i]) continue;
+ for (uintptr_t j = 0; j < NumPCs; j++) {
+ if (!PCs[j]) continue;
+ uint64_t Pair = (i << 32) | j;
+ HasNewPairs |= CoveragePairs.insert(Pair).second;
+ }
+ }
+ if (HasNewPairs)
+ return CoveragePairs.size();
+ return 0;
+}
+
+// Experimental.
+// Fuly reset the current coverage state, run a single unit,
+// compute a hash function from the full coverage set,
+// return non-zero if the hash value is new.
+// This produces tons of new units and as is it's only suitable for small tests,
+// e.g. test/FullCoverageSetTest.cpp. FIXME: make it scale.
+size_t Fuzzer::RunOneMaximizeFullCoverageSet(const Unit &U) {
+ __sanitizer_reset_coverage();
+ Callback(U.data(), U.size());
+ uintptr_t *PCs;
+ uintptr_t NumPCs =__sanitizer_get_coverage_guards(&PCs);
+ if (FullCoverageSets.insert(HashOfArrayOfPCs(PCs, NumPCs)).second)
+ return FullCoverageSets.size();
+ return 0;
+}
+
+size_t Fuzzer::RunOneMaximizeTotalCoverage(const Unit &U) {
+ size_t OldCoverage = __sanitizer_get_total_unique_coverage();
+ Callback(U.data(), U.size());
+ size_t NewCoverage = __sanitizer_get_total_unique_coverage();
+ if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) && Options.Verbosity) {
+ size_t Seconds = secondsSinceProcessStartUp();
+ std::cerr
+ << "#" << TotalNumberOfRuns
+ << "\tcov: " << NewCoverage
+ << "\texec/s: " << (Seconds ? TotalNumberOfRuns / Seconds : 0) << "\n";
+ }
+ if (NewCoverage > OldCoverage)
+ return NewCoverage;
+ return 0;
+}
+
+void Fuzzer::WriteToOutputCorpus(const Unit &U) {
+ if (Options.OutputCorpus.empty()) return;
+ std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
+ WriteToFile(U, Path);
+ if (Options.Verbosity >= 2)
+ std::cerr << "Written to " << Path << std::endl;
+}
+
+void Fuzzer::WriteToCrash(const Unit &U, const char *Prefix) {
+ std::string Path = Prefix + Hash(U);
+ WriteToFile(U, Path);
+ std::cerr << "CRASHED; file written to " << Path << std::endl;
+}
+
+void Fuzzer::SaveCorpus() {
+ if (Options.OutputCorpus.empty()) return;
+ for (const auto &U : Corpus)
+ WriteToFile(U, DirPlusFile(Options.OutputCorpus, Hash(U)));
+ if (Options.Verbosity)
+ std::cerr << "Written corpus of " << Corpus.size() << " files to "
+ << Options.OutputCorpus << "\n";
+}
+
+size_t Fuzzer::MutateAndTestOne(Unit *U) {
+ size_t NewUnits = 0;
+ for (int i = 0; i < Options.MutateDepth; i++) {
+ if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
+ return NewUnits;
+ Mutate(U, Options.MaxLen);
+ size_t NewCoverage = RunOne(*U);
+ if (NewCoverage) {
+ Corpus.push_back(*U);
+ NewUnits++;
+ if (Options.Verbosity) {
+ std::cerr << "#" << TotalNumberOfRuns
+ << "\tNEW: " << NewCoverage
+ << " L: " << U->size()
+ << " S: " << Corpus.size()
+ << " I: " << i
+ << "\t";
+ if (U->size() < 30) {
+ PrintASCII(*U);
+ std::cerr << "\t";
+ Print(*U);
+ }
+ std::cerr << "\n";
+ }
+ WriteToOutputCorpus(*U);
+ if (Options.ExitOnFirst)
+ exit(0);
+ }
+ }
+ return NewUnits;
+}
+
+size_t Fuzzer::Loop(size_t NumIterations) {
+ size_t NewUnits = 0;
+ for (size_t i = 1; i <= NumIterations; i++) {
+ for (size_t J1 = 0; J1 < Corpus.size(); J1++) {
+ if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
+ return NewUnits;
+ // First, simply mutate the unit w/o doing crosses.
+ CurrentUnit = Corpus[J1];
+ NewUnits += MutateAndTestOne(&CurrentUnit);
+ // Now, cross with others.
+ if (Options.DoCrossOver) {
+ for (size_t J2 = 0; J2 < Corpus.size(); J2++) {
+ CurrentUnit.clear();
+ CrossOver(Corpus[J1], Corpus[J2], &CurrentUnit, Options.MaxLen);
+ NewUnits += MutateAndTestOne(&CurrentUnit);
+ }
+ }
+ }
+ }
+ return NewUnits;
+}
+
+} // namespace fuzzer
diff --git a/lib/Fuzzer/FuzzerMain.cpp b/lib/Fuzzer/FuzzerMain.cpp
new file mode 100644
index 0000000..d0c3df3
--- /dev/null
+++ b/lib/Fuzzer/FuzzerMain.cpp
@@ -0,0 +1,20 @@
+//===- FuzzerMain.cpp - main() function and flags -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// main() and flags.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerInterface.h"
+#include "FuzzerInternal.h"
+
+// This function should be defined by the user.
+extern "C" void TestOneInput(const uint8_t *Data, size_t Size);
+
+int main(int argc, char **argv) {
+ return fuzzer::FuzzerDriver(argc, argv, TestOneInput);
+}
diff --git a/lib/Fuzzer/FuzzerMutate.cpp b/lib/Fuzzer/FuzzerMutate.cpp
new file mode 100644
index 0000000..b28264a
--- /dev/null
+++ b/lib/Fuzzer/FuzzerMutate.cpp
@@ -0,0 +1,70 @@
+//===- FuzzerMutate.cpp - Mutate a test input -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Mutate a test input.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerInternal.h"
+
+namespace fuzzer {
+
+static char FlipRandomBit(char X) {
+ int Bit = rand() % 8;
+ char Mask = 1 << Bit;
+ char R;
+ if (X & (1 << Bit))
+ R = X & ~Mask;
+ else
+ R = X | Mask;
+ assert(R != X);
+ return R;
+}
+
+static char RandCh() {
+ if (rand() % 2) return rand();
+ const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~.";
+ return Special[rand() % (sizeof(Special) - 1)];
+}
+
+// Mutate U in place.
+void Mutate(Unit *U, size_t MaxLen) {
+ assert(MaxLen > 0);
+ assert(U->size() <= MaxLen);
+ if (U->empty()) {
+ for (size_t i = 0; i < MaxLen; i++)
+ U->push_back(RandCh());
+ return;
+ }
+ assert(!U->empty());
+ switch (rand() % 3) {
+ case 0:
+ if (U->size() > 1) {
+ U->erase(U->begin() + rand() % U->size());
+ break;
+ }
+ [[clang::fallthrough]];
+ case 1:
+ if (U->size() < MaxLen) {
+ U->insert(U->begin() + rand() % U->size(), RandCh());
+ } else { // At MaxLen.
+ uint8_t Ch = RandCh();
+ size_t Idx = rand() % U->size();
+ (*U)[Idx] = Ch;
+ }
+ break;
+ default:
+ {
+ size_t Idx = rand() % U->size();
+ (*U)[Idx] = FlipRandomBit((*U)[Idx]);
+ }
+ break;
+ }
+ assert(!U->empty());
+}
+
+} // namespace fuzzer
diff --git a/lib/Fuzzer/FuzzerSanitizerOptions.cpp b/lib/Fuzzer/FuzzerSanitizerOptions.cpp
new file mode 100644
index 0000000..1c58f3a
--- /dev/null
+++ b/lib/Fuzzer/FuzzerSanitizerOptions.cpp
@@ -0,0 +1,18 @@
+//===- FuzzerSanitizerOptions.cpp - default flags for sanitizers ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Set default options for sanitizers while running the fuzzer.
+// Options reside in a separate file, so if we don't want to set the default
+// options we simply do not link this file in.
+// ASAN options:
+// * don't dump the coverage to disk.
+// * enable coverage by default.
+//===----------------------------------------------------------------------===//
+extern "C" const char *__asan_default_options() {
+ return "coverage_pcs=0:coverage=1";
+}
diff --git a/lib/Fuzzer/FuzzerUtil.cpp b/lib/Fuzzer/FuzzerUtil.cpp
new file mode 100644
index 0000000..679f289
--- /dev/null
+++ b/lib/Fuzzer/FuzzerUtil.cpp
@@ -0,0 +1,61 @@
+//===- FuzzerUtil.cpp - Misc utils ----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Misc utils.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerInternal.h"
+#include <iostream>
+#include <sys/time.h>
+#include <cassert>
+#include <cstring>
+#include <signal.h>
+
+namespace fuzzer {
+
+void Print(const Unit &v, const char *PrintAfter) {
+ std::cerr << v.size() << ": ";
+ for (auto x : v)
+ std::cerr << (unsigned) x << " ";
+ std::cerr << PrintAfter;
+}
+
+void PrintASCII(const Unit &U, const char *PrintAfter) {
+ for (auto X : U)
+ std::cerr << (char)((isascii(X) && X >= ' ') ? X : '?');
+ std::cerr << PrintAfter;
+}
+
+std::string Hash(const Unit &in) {
+ size_t h1 = 0, h2 = 0;
+ for (auto x : in) {
+ h1 += x;
+ h1 *= 5;
+ h2 += x;
+ h2 *= 7;
+ }
+ return std::to_string(h1) + std::to_string(h2);
+}
+
+static void AlarmHandler(int, siginfo_t *, void *) {
+ Fuzzer::AlarmCallback();
+}
+
+void SetTimer(int Seconds) {
+ struct itimerval T {{Seconds, 0}, {Seconds, 0}};
+ std::cerr << "SetTimer " << Seconds << "\n";
+ int Res = setitimer(ITIMER_REAL, &T, nullptr);
+ assert(Res == 0);
+ struct sigaction sigact;
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_sigaction = AlarmHandler;
+ Res = sigaction(SIGALRM, &sigact, 0);
+ assert(Res == 0);
+}
+
+} // namespace fuzzer
diff --git a/lib/Fuzzer/README.txt b/lib/Fuzzer/README.txt
new file mode 100644
index 0000000..e4d6b4f
--- /dev/null
+++ b/lib/Fuzzer/README.txt
@@ -0,0 +1,112 @@
+===============================
+Fuzzer -- a library for coverage-guided fuzz testing.
+===============================
+
+This library is intended primarily for in-process coverage-guided fuzz testing
+(fuzzing) of other libraries. The typical workflow looks like this:
+
+ * Build the Fuzzer library as a static archive (or just a set of .o files).
+ Note that the Fuzzer contains the main() function.
+ Preferably do *not* use sanitizers while building the Fuzzer.
+ * Build the library you are going to test with -fsanitize-coverage=[234]
+ and one of the sanitizers. We recommend to build the library in several
+ different modes (e.g. asan, msan, lsan, ubsan, etc) and even using different
+ optimizations options (e.g. -O0, -O1, -O2) to diversify testing.
+ * Build a test driver using the same options as the library.
+ The test driver is a C/C++ file containing interesting calls to the library
+ inside a single function:
+ extern "C" void TestOneInput(const uint8_t *Data, size_t Size);
+ * Link the Fuzzer, the library and the driver together into an executable
+ using the same sanitizer options as for the library.
+ * Collect the initial corpus of inputs for the
+ fuzzer (a directory with test inputs, one file per input).
+ The better your inputs are the faster you will find something interesting.
+ Also try to keep your inputs small, otherwise the Fuzzer will run too slow.
+ * Run the fuzzer with the test corpus. As new interesting test cases are
+ discovered they will be added to the corpus. If a bug is discovered by
+ the sanitizer (asan, etc) it will be reported as usual and the reproducer
+ will be written to disk.
+ Each Fuzzer process is single-threaded (unless the library starts its own
+ threads). You can run the Fuzzer on the same corpus in multiple processes.
+ in parallel. For run-time options run the Fuzzer binary with '-help=1'.
+
+
+The Fuzzer is similar in concept to AFL (http://lcamtuf.coredump.cx/afl/),
+but uses in-process Fuzzing, which is more fragile, more restrictive, but
+potentially much faster as it has no overhead for process start-up.
+It uses LLVM's "Sanitizer Coverage" instrumentation to get in-process
+coverage-feedback https://code.google.com/p/address-sanitizer/wiki/AsanCoverage
+
+The code resides in the LLVM repository and is (or will be) used by various
+parts of LLVM, but the Fuzzer itself does not (and should not) depend on any
+part of LLVM and can be used for other projects. Ideally, the Fuzzer's code
+should not have any external dependencies. Right now it uses STL, which may need
+to be fixed later. See also F.A.Q. below.
+
+Examples of usage in LLVM:
+ * clang-format-fuzzer. The inputs are random pieces of C++-like text.
+ * Build (make sure to use fresh clang as the host compiler):
+ cmake -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
+ -DLLVM_USE_SANITIZER=Address -DLLVM_USE_SANITIZE_COVERAGE=YES \
+ /path/to/llvm -DCMAKE_BUILD_TYPE=Release
+ ninja clang-format-fuzzer
+ * Optionally build other kinds of binaries (asan+Debug, msan, ubsan, etc)
+ * TODO: commit the pre-fuzzed corpus to svn (?).
+ * Run:
+ clang-format-fuzzer CORPUS_DIR
+
+Toy example (see SimpleTest.cpp):
+a simple function that does something interesting if it receives bytes "Hi!".
+ # Build the Fuzzer with asan:
+ % clang++ -std=c++11 -fsanitize=address -fsanitize-coverage=3 -O1 -g \
+ Fuzzer*.cpp test/SimpleTest.cpp
+ # Run the fuzzer with no corpus (assuming on empty input)
+ % ./a.out
+
+===============================================================================
+F.A.Q.
+
+Q. Why Fuzzer does not use any of the LLVM support?
+A. There are two reasons.
+First, we want this library to be used outside of the LLVM w/o users having to
+build the rest of LLVM. This may sound unconvincing for many LLVM folks,
+but in practice the need for building the whole LLVM frightens many potential
+users -- and we want more users to use this code.
+Second, there is a subtle technical reason not to rely on the rest of LLVM, or
+any other large body of code (maybe not even STL). When coverage instrumentation
+is enabled, it will also instrument the LLVM support code which will blow up the
+coverage set of the process (since the fuzzer is in-process). In other words, by
+using more external dependencies we will slow down the fuzzer while the main
+reason for it to exist is extreme speed.
+
+Q. What about Windows then? The Fuzzer contains code that does not build on
+Windows.
+A. The sanitizer coverage support does not work on Windows either as of 01/2015.
+Once it's there, we'll need to re-implement OS-specific parts (I/O, signals).
+
+Q. When this Fuzzer is not a good solution for a problem?
+A.
+ * If the test inputs are validated by the target library and the validator
+ asserts/crashes on invalid inputs, the in-process fuzzer is not applicable
+ (we could use fork() w/o exec, but it comes with extra overhead).
+ * Bugs in the target library may accumulate w/o being detected. E.g. a memory
+ corruption that goes undetected at first and then leads to a crash while
+ testing another input. This is why it is highly recommended to run this
+ in-process fuzzer with all sanitizers to detect most bugs on the spot.
+ * It is harder to protect the in-process fuzzer from excessive memory
+ consumption and infinite loops in the target library (still possible).
+ * The target library should not have significant global state that is not
+ reset between the runs.
+ * Many interesting target libs are not designed in a way that supports
+ the in-process fuzzer interface (e.g. require a file path instead of a
+ byte array).
+ * If a single test run takes a considerable fraction of a second (or
+ more) the speed benefit from the in-process fuzzer is negligible.
+ * If the target library runs persistent threads (that outlive
+ execution of one test) the fuzzing results will be unreliable.
+
+Q. So, what exactly this Fuzzer is good for?
+A. This Fuzzer might be a good choice for testing libraries that have relatively
+small inputs, each input takes < 1ms to run, and the library code is not expected
+to crash on invalid inputs.
+Examples: regular expression matchers, text or binary format parsers.
diff --git a/lib/Fuzzer/test/CMakeLists.txt b/lib/Fuzzer/test/CMakeLists.txt
new file mode 100644
index 0000000..bed9cd8
--- /dev/null
+++ b/lib/Fuzzer/test/CMakeLists.txt
@@ -0,0 +1,61 @@
+# Build all these tests with -O0, otherwise optimizations may merge some
+# basic blocks and we'll fail to discover the targets.
+# Also enable the coverage instrumentation back (it is disabled
+# for the Fuzzer lib)
+set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O0 -fsanitize-coverage=4")
+
+set(Tests
+ FourIndependentBranchesTest
+ FullCoverageSetTest
+ InfiniteTest
+ NullDerefTest
+ SimpleTest
+ TimeoutTest
+ )
+
+set(TestBinaries)
+
+foreach(Test ${Tests})
+ add_executable(LLVMFuzzer-${Test}
+ EXCLUDE_FROM_ALL
+ ${Test}.cpp
+ )
+ target_link_libraries(LLVMFuzzer-${Test}
+ LLVMFuzzer
+ )
+ set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test})
+endforeach()
+
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ )
+
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/unit/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/unit/lit.site.cfg
+ )
+
+include_directories(..)
+include_directories(${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include)
+
+add_executable(LLVMFuzzer-Unittest
+ FuzzerUnittest.cpp
+ $<TARGET_OBJECTS:LLVMFuzzerNoMain>
+ )
+
+target_link_libraries(LLVMFuzzer-Unittest
+ gtest
+ gtest_main
+ )
+
+set(TestBinaries ${TestBinaries} LLVMFuzzer-Unittest)
+
+set_target_properties(${TestBinaries}
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ )
+
+add_lit_testsuite(check-fuzzer "Running Fuzzer tests"
+ ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS ${TestBinaries} FileCheck not
+ )
diff --git a/lib/Fuzzer/test/FourIndependentBranchesTest.cpp b/lib/Fuzzer/test/FourIndependentBranchesTest.cpp
new file mode 100644
index 0000000..171668b
--- /dev/null
+++ b/lib/Fuzzer/test/FourIndependentBranchesTest.cpp
@@ -0,0 +1,18 @@
+// Simple test for a fuzzer. The fuzzer must find the string "FUZZ".
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <iostream>
+
+extern "C" void TestOneInput(const uint8_t *Data, size_t Size) {
+ int bits = 0;
+ if (Size > 0 && Data[0] == 'F') bits |= 1;
+ if (Size > 1 && Data[1] == 'U') bits |= 2;
+ if (Size > 2 && Data[2] == 'Z') bits |= 4;
+ if (Size > 3 && Data[3] == 'Z') bits |= 8;
+ if (bits == 15) {
+ std::cerr << "BINGO!\n";
+ exit(1);
+ }
+}
+
diff --git a/lib/Fuzzer/test/FullCoverageSetTest.cpp b/lib/Fuzzer/test/FullCoverageSetTest.cpp
new file mode 100644
index 0000000..d4f8c11
--- /dev/null
+++ b/lib/Fuzzer/test/FullCoverageSetTest.cpp
@@ -0,0 +1,20 @@
+// Simple test for a fuzzer. The fuzzer must find the string "FUZZER".
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <iostream>
+
+extern "C" void TestOneInput(const uint8_t *Data, size_t Size) {
+ int bits = 0;
+ if (Size > 0 && Data[0] == 'F') bits |= 1;
+ if (Size > 1 && Data[1] == 'U') bits |= 2;
+ if (Size > 2 && Data[2] == 'Z') bits |= 4;
+ if (Size > 3 && Data[3] == 'Z') bits |= 8;
+ if (Size > 4 && Data[4] == 'E') bits |= 16;
+ if (Size > 5 && Data[5] == 'R') bits |= 32;
+ if (bits == 63) {
+ std::cerr << "BINGO!\n";
+ exit(1);
+ }
+}
+
diff --git a/lib/Fuzzer/test/FuzzerUnittest.cpp b/lib/Fuzzer/test/FuzzerUnittest.cpp
new file mode 100644
index 0000000..368a0f2
--- /dev/null
+++ b/lib/Fuzzer/test/FuzzerUnittest.cpp
@@ -0,0 +1,62 @@
+#include "FuzzerInternal.h"
+#include "gtest/gtest.h"
+#include <set>
+
+// For now, have TestOneInput just to make it link.
+// Later we may want to make unittests that actually call TestOneInput.
+extern "C" void TestOneInput(const uint8_t *Data, size_t Size) {
+ abort();
+}
+
+TEST(Fuzzer, CrossOver) {
+ using namespace fuzzer;
+ Unit A({0, 1, 2}), B({5, 6, 7});
+ Unit C;
+ Unit Expected[] = {
+ { 0 },
+ { 0, 1 },
+ { 0, 5 },
+ { 0, 1, 2 },
+ { 0, 1, 5 },
+ { 0, 5, 1 },
+ { 0, 5, 6 },
+ { 0, 1, 2, 5 },
+ { 0, 1, 5, 2 },
+ { 0, 1, 5, 6 },
+ { 0, 5, 1, 2 },
+ { 0, 5, 1, 6 },
+ { 0, 5, 6, 1 },
+ { 0, 5, 6, 7 },
+ { 0, 1, 2, 5, 6 },
+ { 0, 1, 5, 2, 6 },
+ { 0, 1, 5, 6, 2 },
+ { 0, 1, 5, 6, 7 },
+ { 0, 5, 1, 2, 6 },
+ { 0, 5, 1, 6, 2 },
+ { 0, 5, 1, 6, 7 },
+ { 0, 5, 6, 1, 2 },
+ { 0, 5, 6, 1, 7 },
+ { 0, 5, 6, 7, 1 },
+ { 0, 1, 2, 5, 6, 7 },
+ { 0, 1, 5, 2, 6, 7 },
+ { 0, 1, 5, 6, 2, 7 },
+ { 0, 1, 5, 6, 7, 2 },
+ { 0, 5, 1, 2, 6, 7 },
+ { 0, 5, 1, 6, 2, 7 },
+ { 0, 5, 1, 6, 7, 2 },
+ { 0, 5, 6, 1, 2, 7 },
+ { 0, 5, 6, 1, 7, 2 },
+ { 0, 5, 6, 7, 1, 2 }
+ };
+ for (size_t Len = 1; Len < 8; Len++) {
+ std::set<Unit> FoundUnits, ExpectedUnitsWitThisLength;
+ for (int Iter = 0; Iter < 3000; Iter++) {
+ CrossOver(A, B, &C, Len);
+ FoundUnits.insert(C);
+ }
+ for (const Unit &U : Expected)
+ if (U.size() <= Len)
+ ExpectedUnitsWitThisLength.insert(U);
+ EXPECT_EQ(ExpectedUnitsWitThisLength, FoundUnits);
+ }
+}
diff --git a/lib/Fuzzer/test/InfiniteTest.cpp b/lib/Fuzzer/test/InfiniteTest.cpp
new file mode 100644
index 0000000..dcb3030
--- /dev/null
+++ b/lib/Fuzzer/test/InfiniteTest.cpp
@@ -0,0 +1,20 @@
+// Simple test for a fuzzer. The fuzzer must find the string "Hi!".
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <iostream>
+
+static volatile int Sink;
+
+extern "C" void TestOneInput(const uint8_t *Data, size_t Size) {
+ if (Size > 0 && Data[0] == 'H') {
+ Sink = 1;
+ if (Size > 1 && Data[1] == 'i') {
+ Sink = 2;
+ if (Size > 2 && Data[2] == '!') {
+ Sink = 2;
+ }
+ }
+ }
+}
+
diff --git a/lib/Fuzzer/test/NullDerefTest.cpp b/lib/Fuzzer/test/NullDerefTest.cpp
new file mode 100644
index 0000000..8811e38
--- /dev/null
+++ b/lib/Fuzzer/test/NullDerefTest.cpp
@@ -0,0 +1,22 @@
+// Simple test for a fuzzer. The fuzzer must find the string "Hi!".
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <iostream>
+
+static volatile int Sink;
+static volatile int *Null = 0;
+
+extern "C" void TestOneInput(const uint8_t *Data, size_t Size) {
+ if (Size > 0 && Data[0] == 'H') {
+ Sink = 1;
+ if (Size > 1 && Data[1] == 'i') {
+ Sink = 2;
+ if (Size > 2 && Data[2] == '!') {
+ std::cout << "Found the target, dereferencing NULL\n";
+ *Null = 1;
+ }
+ }
+ }
+}
+
diff --git a/lib/Fuzzer/test/SimpleTest.cpp b/lib/Fuzzer/test/SimpleTest.cpp
new file mode 100644
index 0000000..adb90ce
--- /dev/null
+++ b/lib/Fuzzer/test/SimpleTest.cpp
@@ -0,0 +1,21 @@
+// Simple test for a fuzzer. The fuzzer must find the string "Hi!".
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <iostream>
+
+static volatile int Sink;
+
+extern "C" void TestOneInput(const uint8_t *Data, size_t Size) {
+ if (Size > 0 && Data[0] == 'H') {
+ Sink = 1;
+ if (Size > 1 && Data[1] == 'i') {
+ Sink = 2;
+ if (Size > 2 && Data[2] == '!') {
+ std::cout << "Found the target, exiting\n";
+ exit(0);
+ }
+ }
+ }
+}
+
diff --git a/lib/Fuzzer/test/TimeoutTest.cpp b/lib/Fuzzer/test/TimeoutTest.cpp
new file mode 100644
index 0000000..23683ce
--- /dev/null
+++ b/lib/Fuzzer/test/TimeoutTest.cpp
@@ -0,0 +1,22 @@
+// Simple test for a fuzzer. The fuzzer must find the string "Hi!".
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <iostream>
+
+static volatile int Sink;
+
+extern "C" void TestOneInput(const uint8_t *Data, size_t Size) {
+ if (Size > 0 && Data[0] == 'H') {
+ Sink = 1;
+ if (Size > 1 && Data[1] == 'i') {
+ Sink = 2;
+ if (Size > 2 && Data[2] == '!') {
+ Sink = 2;
+ while (Sink)
+ ;
+ }
+ }
+ }
+}
+
diff --git a/lib/Fuzzer/test/fuzzer.test b/lib/Fuzzer/test/fuzzer.test
new file mode 100644
index 0000000..1e42e72
--- /dev/null
+++ b/lib/Fuzzer/test/fuzzer.test
@@ -0,0 +1,19 @@
+RUN: ./LLVMFuzzer-SimpleTest 2>&1 | FileCheck %s --check-prefix=SimpleTest
+SimpleTest: Found the target, exiting
+
+RUN: not ./LLVMFuzzer-InfiniteTest -timeout=2 2>&1 | FileCheck %s --check-prefix=InfiniteTest
+InfiniteTest: ALARM: working on the last Unit for
+InfiniteTest-NOT: CRASHED; file written to timeout
+
+RUN: not ./LLVMFuzzer-TimeoutTest -timeout=5 2>&1 | FileCheck %s --check-prefix=TimeoutTest
+TimeoutTest: ALARM: working on the last Unit for
+TimeoutTest: CRASHED; file written to timeout
+
+RUN: not ./LLVMFuzzer-NullDerefTest 2>&1 | FileCheck %s --check-prefix=NullDerefTest
+NullDerefTest: CRASHED; file written to crash-
+
+RUN: not ./LLVMFuzzer-FullCoverageSetTest -timeout=15 -seed=1 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s --check-prefix=FullCoverageSetTest
+FullCoverageSetTest: BINGO
+
+RUN: not ./LLVMFuzzer-FourIndependentBranchesTest -timeout=15 -seed=1 -use_coverage_pairs=1 2>&1 | FileCheck %s --check-prefix=FourIndependentBranchesTest
+FourIndependentBranchesTest: BINGO
diff --git a/lib/Fuzzer/test/lit.cfg b/lib/Fuzzer/test/lit.cfg
new file mode 100644
index 0000000..834a16ae
--- /dev/null
+++ b/lib/Fuzzer/test/lit.cfg
@@ -0,0 +1,14 @@
+import lit.formats
+
+config.name = "LLVMFuzzer"
+config.test_format = lit.formats.ShTest(True)
+config.suffixes = ['.test']
+config.test_source_root = os.path.dirname(__file__)
+
+# Tweak PATH to include llvm tools dir.
+llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
+if (not llvm_tools_dir) or (not os.path.exists(llvm_tools_dir)):
+ lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % llvm_tools_dir)
+path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH']))
+config.environment['PATH'] = path
+
diff --git a/lib/Fuzzer/test/lit.site.cfg.in b/lib/Fuzzer/test/lit.site.cfg.in
new file mode 100644
index 0000000..e520db8
--- /dev/null
+++ b/lib/Fuzzer/test/lit.site.cfg.in
@@ -0,0 +1,3 @@
+config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@"
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")
diff --git a/lib/Fuzzer/test/unit/lit.cfg b/lib/Fuzzer/test/unit/lit.cfg
new file mode 100644
index 0000000..0cc3193
--- /dev/null
+++ b/lib/Fuzzer/test/unit/lit.cfg
@@ -0,0 +1,7 @@
+import lit.formats
+
+config.name = "LLVMFuzzer-Unittest"
+print config.test_exec_root
+config.test_format = lit.formats.GoogleTest(".", "Unittest")
+config.suffixes = []
+config.test_source_root = config.test_exec_root
diff --git a/lib/Fuzzer/test/unit/lit.site.cfg.in b/lib/Fuzzer/test/unit/lit.site.cfg.in
new file mode 100644
index 0000000..114daf4
--- /dev/null
+++ b/lib/Fuzzer/test/unit/lit.site.cfg.in
@@ -0,0 +1,2 @@
+config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@"
+lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/unit/lit.cfg")