summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/lib/Fuzzer
diff options
context:
space:
mode:
authorpascal <pascal@openbsd.org>2016-09-03 22:46:54 +0000
committerpascal <pascal@openbsd.org>2016-09-03 22:46:54 +0000
commitb5500b9ca0102f1ccaf32f0e77e96d0739aded9b (patch)
treee1b7ebb5a0231f9e6d8d3f6f719582cebd64dc98 /gnu/llvm/lib/Fuzzer
parentclarify purpose of src/gnu/ directory. (diff)
downloadwireguard-openbsd-b5500b9ca0102f1ccaf32f0e77e96d0739aded9b.tar.xz
wireguard-openbsd-b5500b9ca0102f1ccaf32f0e77e96d0739aded9b.zip
Use the space freed up by sparc and zaurus to import LLVM.
ok hackroom@
Diffstat (limited to 'gnu/llvm/lib/Fuzzer')
-rw-r--r--gnu/llvm/lib/Fuzzer/CMakeLists.txt34
-rw-r--r--gnu/llvm/lib/Fuzzer/FuzzerCrossOver.cpp51
-rw-r--r--gnu/llvm/lib/Fuzzer/FuzzerDFSan.h61
-rw-r--r--gnu/llvm/lib/Fuzzer/FuzzerDriver.cpp336
-rw-r--r--gnu/llvm/lib/Fuzzer/FuzzerFlags.def72
-rw-r--r--gnu/llvm/lib/Fuzzer/FuzzerIO.cpp101
-rw-r--r--gnu/llvm/lib/Fuzzer/FuzzerInterface.cpp30
-rw-r--r--gnu/llvm/lib/Fuzzer/FuzzerInterface.h198
-rw-r--r--gnu/llvm/lib/Fuzzer/FuzzerInternal.h207
-rw-r--r--gnu/llvm/lib/Fuzzer/FuzzerLoop.cpp512
-rw-r--r--gnu/llvm/lib/Fuzzer/FuzzerMain.cpp20
-rw-r--r--gnu/llvm/lib/Fuzzer/FuzzerMutate.cpp278
-rw-r--r--gnu/llvm/lib/Fuzzer/FuzzerSHA1.cpp202
-rw-r--r--gnu/llvm/lib/Fuzzer/FuzzerSanitizerOptions.cpp19
-rw-r--r--gnu/llvm/lib/Fuzzer/FuzzerTraceState.cpp604
-rw-r--r--gnu/llvm/lib/Fuzzer/FuzzerUtil.cpp212
-rw-r--r--gnu/llvm/lib/Fuzzer/README.txt2
-rw-r--r--gnu/llvm/lib/Fuzzer/cxx.dict122
-rwxr-xr-xgnu/llvm/lib/Fuzzer/pull_and_push_fuzz_corpus.sh17
-rw-r--r--gnu/llvm/lib/Fuzzer/test/CMakeLists.txt118
-rw-r--r--gnu/llvm/lib/Fuzzer/test/CallerCalleeTest.cpp56
-rw-r--r--gnu/llvm/lib/Fuzzer/test/CounterTest.cpp15
-rw-r--r--gnu/llvm/lib/Fuzzer/test/FourIndependentBranchesTest.cpp19
-rw-r--r--gnu/llvm/lib/Fuzzer/test/FullCoverageSetTest.cpp21
-rw-r--r--gnu/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp402
-rw-r--r--gnu/llvm/lib/Fuzzer/test/MemcmpTest.cpp28
-rw-r--r--gnu/llvm/lib/Fuzzer/test/NullDerefTest.cpp23
-rw-r--r--gnu/llvm/lib/Fuzzer/test/SimpleCmpTest.cpp31
-rw-r--r--gnu/llvm/lib/Fuzzer/test/SimpleDictionaryTest.cpp26
-rw-r--r--gnu/llvm/lib/Fuzzer/test/SimpleHashTest.cpp37
-rw-r--r--gnu/llvm/lib/Fuzzer/test/SimpleTest.cpp24
-rw-r--r--gnu/llvm/lib/Fuzzer/test/StrcmpTest.cpp29
-rw-r--r--gnu/llvm/lib/Fuzzer/test/StrncmpTest.cpp25
-rw-r--r--gnu/llvm/lib/Fuzzer/test/SwitchTest.cpp55
-rw-r--r--gnu/llvm/lib/Fuzzer/test/ThreadedTest.cpp23
-rw-r--r--gnu/llvm/lib/Fuzzer/test/TimeoutTest.cpp23
-rw-r--r--gnu/llvm/lib/Fuzzer/test/UninstrumentedTest.cpp8
-rw-r--r--gnu/llvm/lib/Fuzzer/test/UserSuppliedFuzzerTest.cpp51
-rw-r--r--gnu/llvm/lib/Fuzzer/test/dfsan/CMakeLists.txt14
-rw-r--r--gnu/llvm/lib/Fuzzer/test/dict1.txt4
-rw-r--r--gnu/llvm/lib/Fuzzer/test/fuzzer-dfsan.test23
-rw-r--r--gnu/llvm/lib/Fuzzer/test/fuzzer-dict.test6
-rw-r--r--gnu/llvm/lib/Fuzzer/test/fuzzer-drill.test8
-rw-r--r--gnu/llvm/lib/Fuzzer/test/fuzzer-threaded.test7
-rw-r--r--gnu/llvm/lib/Fuzzer/test/fuzzer-timeout.test13
-rw-r--r--gnu/llvm/lib/Fuzzer/test/fuzzer-traces.test20
-rw-r--r--gnu/llvm/lib/Fuzzer/test/fuzzer.test36
-rw-r--r--gnu/llvm/lib/Fuzzer/test/hi.txt1
-rw-r--r--gnu/llvm/lib/Fuzzer/test/lit.cfg15
-rw-r--r--gnu/llvm/lib/Fuzzer/test/lit.site.cfg.in3
-rw-r--r--gnu/llvm/lib/Fuzzer/test/merge.test29
-rw-r--r--gnu/llvm/lib/Fuzzer/test/trace-bb/CMakeLists.txt14
-rw-r--r--gnu/llvm/lib/Fuzzer/test/uninstrumented/CMakeLists.txt14
-rw-r--r--gnu/llvm/lib/Fuzzer/test/unit/lit.cfg7
-rw-r--r--gnu/llvm/lib/Fuzzer/test/unit/lit.site.cfg.in2
55 files changed, 4308 insertions, 0 deletions
diff --git a/gnu/llvm/lib/Fuzzer/CMakeLists.txt b/gnu/llvm/lib/Fuzzer/CMakeLists.txt
new file mode 100644
index 00000000000..d4d85041d21
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/CMakeLists.txt
@@ -0,0 +1,34 @@
+set(LIBFUZZER_FLAGS_BASE "${CMAKE_CXX_FLAGS_RELEASE}")
+# Disable the coverage and sanitizer instrumentation for the fuzzer itself.
+set(CMAKE_CXX_FLAGS_RELEASE "${LIBFUZZER_FLAGS_BASE} -O2 -fno-sanitize=all")
+if( LLVM_USE_SANITIZE_COVERAGE )
+ add_library(LLVMFuzzerNoMainObjects OBJECT
+ FuzzerCrossOver.cpp
+ FuzzerInterface.cpp
+ FuzzerTraceState.cpp
+ FuzzerDriver.cpp
+ FuzzerIO.cpp
+ FuzzerLoop.cpp
+ FuzzerMutate.cpp
+ FuzzerSanitizerOptions.cpp
+ FuzzerSHA1.cpp
+ FuzzerUtil.cpp
+ )
+ add_library(LLVMFuzzerNoMain STATIC
+ $<TARGET_OBJECTS:LLVMFuzzerNoMainObjects>
+ )
+ if( HAVE_LIBPTHREAD )
+ target_link_libraries(LLVMFuzzerNoMain pthread)
+ endif()
+ add_library(LLVMFuzzer STATIC
+ FuzzerMain.cpp
+ $<TARGET_OBJECTS:LLVMFuzzerNoMainObjects>
+ )
+ if( HAVE_LIBPTHREAD )
+ target_link_libraries(LLVMFuzzer pthread)
+ endif()
+
+ if( LLVM_INCLUDE_TESTS )
+ add_subdirectory(test)
+ endif()
+endif()
diff --git a/gnu/llvm/lib/Fuzzer/FuzzerCrossOver.cpp b/gnu/llvm/lib/Fuzzer/FuzzerCrossOver.cpp
new file mode 100644
index 00000000000..5203deaf912
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/FuzzerCrossOver.cpp
@@ -0,0 +1,51 @@
+//===- 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 <cstring>
+
+#include "FuzzerInternal.h"
+
+namespace fuzzer {
+
+// Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out.
+size_t MutationDispatcher::CrossOver(const uint8_t *Data1, size_t Size1,
+ const uint8_t *Data2, size_t Size2,
+ uint8_t *Out, size_t MaxOutSize) {
+ assert(Size1 || Size2);
+ MaxOutSize = Rand(MaxOutSize) + 1;
+ size_t OutPos = 0;
+ size_t Pos1 = 0;
+ size_t Pos2 = 0;
+ size_t *InPos = &Pos1;
+ size_t InSize = Size1;
+ const uint8_t *Data = Data1;
+ bool CurrentlyUsingFirstData = true;
+ while (OutPos < MaxOutSize && (Pos1 < Size1 || Pos2 < Size2)) {
+ // Merge a part of Data into Out.
+ size_t OutSizeLeft = MaxOutSize - OutPos;
+ if (*InPos < InSize) {
+ size_t InSizeLeft = InSize - *InPos;
+ size_t MaxExtraSize = std::min(OutSizeLeft, InSizeLeft);
+ size_t ExtraSize = Rand(MaxExtraSize) + 1;
+ memcpy(Out + OutPos, Data + *InPos, ExtraSize);
+ OutPos += ExtraSize;
+ (*InPos) += ExtraSize;
+ }
+ // Use the other input data on the next iteration.
+ InPos = CurrentlyUsingFirstData ? &Pos2 : &Pos1;
+ InSize = CurrentlyUsingFirstData ? Size2 : Size1;
+ Data = CurrentlyUsingFirstData ? Data2 : Data1;
+ CurrentlyUsingFirstData = !CurrentlyUsingFirstData;
+ }
+ return OutPos;
+}
+
+} // namespace fuzzer
diff --git a/gnu/llvm/lib/Fuzzer/FuzzerDFSan.h b/gnu/llvm/lib/Fuzzer/FuzzerDFSan.h
new file mode 100644
index 00000000000..eb206ec61ce
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/FuzzerDFSan.h
@@ -0,0 +1,61 @@
+//===- FuzzerDFSan.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.
+//
+//===----------------------------------------------------------------------===//
+// DFSan interface.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_DFSAN_H
+#define LLVM_FUZZER_DFSAN_H
+
+#define LLVM_FUZZER_SUPPORTS_DFSAN 0
+#if defined(__has_include)
+# if __has_include(<sanitizer/dfsan_interface.h>)
+# if defined (__linux__)
+# undef LLVM_FUZZER_SUPPORTS_DFSAN
+# define LLVM_FUZZER_SUPPORTS_DFSAN 1
+# include <sanitizer/dfsan_interface.h>
+# endif // __linux__
+# endif
+#endif // defined(__has_include)
+
+#if LLVM_FUZZER_SUPPORTS_DFSAN
+
+extern "C" {
+__attribute__((weak))
+dfsan_label dfsan_create_label(const char *desc, void *userdata);
+__attribute__((weak))
+void dfsan_set_label(dfsan_label label, void *addr, size_t size);
+__attribute__((weak))
+void dfsan_add_label(dfsan_label label, void *addr, size_t size);
+__attribute__((weak))
+const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label);
+__attribute__((weak))
+dfsan_label dfsan_read_label(const void *addr, size_t size);
+} // extern "C"
+
+namespace fuzzer {
+static bool ReallyHaveDFSan() {
+ return &dfsan_create_label != nullptr;
+}
+} // namespace fuzzer
+#else
+// When compiling with a compiler which does not support dfsan,
+// this code is still expected to build (but not necessary work).
+typedef unsigned short dfsan_label;
+struct dfsan_label_info {
+ dfsan_label l1, l2;
+ const char *desc;
+ void *userdata;
+};
+namespace fuzzer {
+static bool ReallyHaveDFSan() { return false; }
+} // namespace fuzzer
+
+#endif
+
+#endif // LLVM_FUZZER_DFSAN_H
diff --git a/gnu/llvm/lib/Fuzzer/FuzzerDriver.cpp b/gnu/llvm/lib/Fuzzer/FuzzerDriver.cpp
new file mode 100644
index 00000000000..66e46dbf3aa
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/FuzzerDriver.cpp
@@ -0,0 +1,336 @@
+//===- 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 <chrono>
+#include <unistd.h>
+#include <thread>
+#include <atomic>
+#include <mutex>
+#include <string>
+#include <sstream>
+#include <algorithm>
+#include <iterator>
+
+namespace fuzzer {
+
+// Program arguments.
+struct FlagDescription {
+ const char *Name;
+ const char *Description;
+ int Default;
+ int *IntFlag;
+ const char **StrFlag;
+ unsigned int *UIntFlag;
+};
+
+struct {
+#define FUZZER_FLAG_INT(Name, Default, Description) int Name;
+#define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name;
+#define FUZZER_FLAG_STRING(Name, Description) const char *Name;
+#include "FuzzerFlags.def"
+#undef FUZZER_FLAG_INT
+#undef FUZZER_FLAG_UNSIGNED
+#undef FUZZER_FLAG_STRING
+} Flags;
+
+static const FlagDescription FlagDescriptions [] {
+#define FUZZER_FLAG_INT(Name, Default, Description) \
+ {#Name, Description, Default, &Flags.Name, nullptr, nullptr},
+#define FUZZER_FLAG_UNSIGNED(Name, Default, Description) \
+ {#Name, Description, static_cast<int>(Default), \
+ nullptr, nullptr, &Flags.Name},
+#define FUZZER_FLAG_STRING(Name, Description) \
+ {#Name, Description, 0, nullptr, &Flags.Name, nullptr},
+#include "FuzzerFlags.def"
+#undef FUZZER_FLAG_INT
+#undef FUZZER_FLAG_UNSIGNED
+#undef FUZZER_FLAG_STRING
+};
+
+static const size_t kNumFlags =
+ sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]);
+
+static std::vector<std::string> *Inputs;
+static std::string *ProgName;
+
+static void PrintHelp() {
+ Printf("Usage: %s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n",
+ ProgName->c_str());
+ Printf("\nFlags: (strictly in form -flag=value)\n");
+ size_t MaxFlagLen = 0;
+ for (size_t F = 0; F < kNumFlags; F++)
+ MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen);
+
+ for (size_t F = 0; F < kNumFlags; F++) {
+ const auto &D = FlagDescriptions[F];
+ Printf(" %s", D.Name);
+ for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++)
+ Printf(" ");
+ Printf("\t");
+ Printf("%d\t%s\n", D.Default, D.Description);
+ }
+ Printf("\nFlags starting with '--' will be ignored and "
+ "will be passed verbatim to subprocesses.\n");
+}
+
+static const char *FlagValue(const char *Param, const char *Name) {
+ size_t Len = strlen(Name);
+ if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 &&
+ Param[Len + 1] == '=')
+ return &Param[Len + 2];
+ return nullptr;
+}
+
+static bool ParseOneFlag(const char *Param) {
+ if (Param[0] != '-') return false;
+ if (Param[1] == '-') {
+ static bool PrintedWarning = false;
+ if (!PrintedWarning) {
+ PrintedWarning = true;
+ Printf("WARNING: libFuzzer ignores flags that start with '--'\n");
+ }
+ return true;
+ }
+ for (size_t F = 0; F < kNumFlags; F++) {
+ const char *Name = FlagDescriptions[F].Name;
+ const char *Str = FlagValue(Param, Name);
+ if (Str) {
+ if (FlagDescriptions[F].IntFlag) {
+ int Val = std::stol(Str);
+ *FlagDescriptions[F].IntFlag = Val;
+ if (Flags.verbosity >= 2)
+ Printf("Flag: %s %d\n", Name, Val);;
+ return true;
+ } else if (FlagDescriptions[F].UIntFlag) {
+ unsigned int Val = std::stoul(Str);
+ *FlagDescriptions[F].UIntFlag = Val;
+ if (Flags.verbosity >= 2)
+ Printf("Flag: %s %u\n", Name, Val);
+ return true;
+ } else if (FlagDescriptions[F].StrFlag) {
+ *FlagDescriptions[F].StrFlag = Str;
+ if (Flags.verbosity >= 2)
+ Printf("Flag: %s %s\n", Name, Str);
+ return true;
+ }
+ }
+ }
+ PrintHelp();
+ exit(1);
+}
+
+// We don't use any library to minimize dependencies.
+static void ParseFlags(const std::vector<std::string> &Args) {
+ for (size_t F = 0; F < kNumFlags; F++) {
+ if (FlagDescriptions[F].IntFlag)
+ *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default;
+ if (FlagDescriptions[F].UIntFlag)
+ *FlagDescriptions[F].UIntFlag =
+ static_cast<unsigned int>(FlagDescriptions[F].Default);
+ if (FlagDescriptions[F].StrFlag)
+ *FlagDescriptions[F].StrFlag = nullptr;
+ }
+ Inputs = new std::vector<std::string>;
+ for (size_t A = 1; A < Args.size(); A++) {
+ if (ParseOneFlag(Args[A].c_str())) continue;
+ Inputs->push_back(Args[A]);
+ }
+}
+
+static std::mutex Mu;
+
+static void PulseThread() {
+ while (true) {
+ std::this_thread::sleep_for(std::chrono::seconds(600));
+ std::lock_guard<std::mutex> Lock(Mu);
+ Printf("pulse...\n");
+ }
+}
+
+static void WorkerThread(const std::string &Cmd, std::atomic<int> *Counter,
+ int NumJobs, std::atomic<bool> *HasErrors) {
+ 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)
+ Printf("%s", ToRun.c_str());
+ int ExitCode = ExecuteCommand(ToRun.c_str());
+ if (ExitCode != 0)
+ *HasErrors = true;
+ std::lock_guard<std::mutex> Lock(Mu);
+ Printf("================== Job %d exited with exit code %d ============\n",
+ C, ExitCode);
+ fuzzer::CopyFileToErr(Log);
+ }
+}
+
+static int RunInMultipleProcesses(const std::vector<std::string> &Args,
+ int NumWorkers, int NumJobs) {
+ std::atomic<int> Counter(0);
+ std::atomic<bool> HasErrors(false);
+ std::string Cmd;
+ for (auto &S : Args) {
+ if (FlagValue(S.c_str(), "jobs") || FlagValue(S.c_str(), "workers"))
+ continue;
+ Cmd += S + " ";
+ }
+ std::vector<std::thread> V;
+ std::thread Pulse(PulseThread);
+ Pulse.detach();
+ 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 RunOneTest(Fuzzer *F, const char *InputFilePath) {
+ Unit U = FileToVector(InputFilePath);
+ Unit PreciseSizedU(U);
+ assert(PreciseSizedU.size() == PreciseSizedU.capacity());
+ F->ExecuteCallback(PreciseSizedU);
+ return 0;
+}
+
+int FuzzerDriver(int argc, char **argv, UserCallback Callback) {
+ FuzzerRandomLibc Rand(0);
+ SimpleUserSuppliedFuzzer SUSF(&Rand, Callback);
+ return FuzzerDriver(argc, argv, SUSF);
+}
+
+int FuzzerDriver(int argc, char **argv, UserSuppliedFuzzer &USF) {
+ std::vector<std::string> Args(argv, argv + argc);
+ return FuzzerDriver(Args, USF);
+}
+
+int FuzzerDriver(const std::vector<std::string> &Args, UserCallback Callback) {
+ FuzzerRandomLibc Rand(0);
+ SimpleUserSuppliedFuzzer SUSF(&Rand, Callback);
+ return FuzzerDriver(Args, SUSF);
+}
+
+int FuzzerDriver(const std::vector<std::string> &Args,
+ UserSuppliedFuzzer &USF) {
+ using namespace fuzzer;
+ assert(!Args.empty());
+ ProgName = new std::string(Args[0]);
+ ParseFlags(Args);
+ if (Flags.help) {
+ PrintHelp();
+ return 0;
+ }
+
+ if (Flags.jobs > 0 && Flags.workers == 0) {
+ Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs);
+ if (Flags.workers > 1)
+ Printf("Running %d workers\n", Flags.workers);
+ }
+
+ if (Flags.workers > 0 && Flags.jobs > 0)
+ return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs);
+
+ Fuzzer::FuzzingOptions Options;
+ Options.Verbosity = Flags.verbosity;
+ Options.MaxLen = Flags.max_len;
+ Options.UnitTimeoutSec = Flags.timeout;
+ Options.MaxTotalTimeSec = Flags.max_total_time;
+ Options.DoCrossOver = Flags.cross_over;
+ Options.MutateDepth = Flags.mutate_depth;
+ Options.ExitOnFirst = Flags.exit_on_first;
+ Options.UseCounters = Flags.use_counters;
+ Options.UseIndirCalls = Flags.use_indir_calls;
+ Options.UseTraces = Flags.use_traces;
+ Options.ShuffleAtStartUp = Flags.shuffle;
+ Options.PreferSmallDuringInitialShuffle =
+ Flags.prefer_small_during_initial_shuffle;
+ Options.Reload = Flags.reload;
+ Options.OnlyASCII = Flags.only_ascii;
+ Options.OutputCSV = Flags.output_csv;
+ if (Flags.runs >= 0)
+ Options.MaxNumberOfRuns = Flags.runs;
+ if (!Inputs->empty())
+ Options.OutputCorpus = (*Inputs)[0];
+ if (Flags.sync_command)
+ Options.SyncCommand = Flags.sync_command;
+ Options.SyncTimeout = Flags.sync_timeout;
+ Options.ReportSlowUnits = Flags.report_slow_units;
+ if (Flags.artifact_prefix)
+ Options.ArtifactPrefix = Flags.artifact_prefix;
+ if (Flags.exact_artifact_path)
+ Options.ExactArtifactPath = Flags.exact_artifact_path;
+ std::vector<Unit> Dictionary;
+ if (Flags.dict)
+ if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary))
+ return 1;
+ if (Flags.verbosity > 0 && !Dictionary.empty())
+ Printf("Dictionary: %zd entries\n", Dictionary.size());
+ Options.SaveArtifacts = !Flags.test_single_input;
+ Options.PrintNewCovPcs = Flags.print_new_cov_pcs;
+
+ Fuzzer F(USF, Options);
+
+ for (auto &U: Dictionary)
+ USF.GetMD().AddWordToManualDictionary(U);
+
+ // Timer
+ if (Flags.timeout > 0)
+ SetTimer(Flags.timeout / 2 + 1);
+
+ if (Flags.test_single_input) {
+ RunOneTest(&F, Flags.test_single_input);
+ exit(0);
+ }
+
+ if (Flags.save_minimized_corpus) {
+ Printf("The flag -save_minimized_corpus is deprecated; use -merge=1\n");
+ exit(1);
+ }
+
+ if (Flags.merge) {
+ F.Merge(*Inputs);
+ exit(0);
+ }
+
+ unsigned Seed = Flags.seed;
+ // Initialize Seed.
+ if (Seed == 0)
+ Seed = time(0) * 10000 + getpid();
+ if (Flags.verbosity)
+ Printf("Seed: %u\n", Seed);
+ USF.GetRand().ResetSeed(Seed);
+
+ F.RereadOutputCorpus();
+ for (auto &inp : *Inputs)
+ if (inp != Options.OutputCorpus)
+ F.ReadDir(inp, nullptr);
+
+ if (F.CorpusSize() == 0)
+ F.AddToCorpus(Unit()); // Can't fuzz empty corpus, so add an empty input.
+ F.ShuffleAndMinimize();
+ if (Flags.drill)
+ F.Drill();
+ else
+ F.Loop();
+
+ if (Flags.verbosity)
+ Printf("Done %d runs in %zd second(s)\n", F.getTotalNumberOfRuns(),
+ F.secondsSinceProcessStartUp());
+
+ exit(0); // Don't let F destroy itself.
+}
+
+} // namespace fuzzer
diff --git a/gnu/llvm/lib/Fuzzer/FuzzerFlags.def b/gnu/llvm/lib/Fuzzer/FuzzerFlags.def
new file mode 100644
index 00000000000..977efb76922
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/FuzzerFlags.def
@@ -0,0 +1,72 @@
+//===- FuzzerFlags.def - Run-time flags -------------------------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Flags. FUZZER_FLAG_INT/FUZZER_FLAG_STRING macros should be defined at the
+// point of inclusion. We are not using any flag parsing library for better
+// portability and independence.
+//===----------------------------------------------------------------------===//
+FUZZER_FLAG_INT(verbosity, 1, "Verbosity level.")
+FUZZER_FLAG_UNSIGNED(seed, 0, "Random seed. If 0, seed is generated.")
+FUZZER_FLAG_INT(runs, -1,
+ "Number of individual test runs (-1 for infinite runs).")
+FUZZER_FLAG_INT(max_len, 64, "Maximum 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(shuffle, 1, "Shuffle inputs at startup")
+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, 1200,
+ "Timeout in seconds (if positive). "
+ "If one unit runs more than this number of seconds the process will abort.")
+FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total "
+ "time in seconds to run the fuzzer.")
+FUZZER_FLAG_INT(help, 0, "Print help.")
+FUZZER_FLAG_INT(save_minimized_corpus, 0, "Deprecated. Use -merge=1")
+FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be "
+ "merged into the 1-st corpus. Only interesting units will be taken.")
+FUZZER_FLAG_INT(use_counters, 1, "Use coverage counters")
+FUZZER_FLAG_INT(use_indir_calls, 1, "Use indirect caller-callee counters")
+FUZZER_FLAG_INT(use_traces, 0, "Experimental: use instruction traces")
+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."
+ " If zero, \"min(jobs,NumberOfCpuCores()/2)\" is used.")
+FUZZER_FLAG_INT(reload, 1,
+ "Reload the main corpus periodically to get new units"
+ " discovered by other processes.")
+FUZZER_FLAG_STRING(sync_command, "Execute an external command "
+ "\"<sync_command> <test_corpus>\" "
+ "to synchronize the test corpus.")
+FUZZER_FLAG_INT(sync_timeout, 600, "Minimum timeout between syncs.")
+FUZZER_FLAG_INT(report_slow_units, 10,
+ "Report slowest units if they run for more than this number of seconds.")
+FUZZER_FLAG_INT(only_ascii, 0,
+ "If 1, generate only ASCII (isprint+isspace) inputs.")
+FUZZER_FLAG_STRING(dict, "Experimental. Use the dictionary file.")
+FUZZER_FLAG_STRING(test_single_input, "Use specified file as test input.")
+FUZZER_FLAG_STRING(artifact_prefix, "Write fuzzing artifacts (crash, "
+ "timeout, or slow inputs) as "
+ "$(artifact_prefix)file")
+FUZZER_FLAG_STRING(exact_artifact_path,
+ "Write the single artifact on failure (crash, timeout) "
+ "as $(exact_artifact_path). This overrides -artifact_prefix "
+ "and will not use checksum in the file name. Do not "
+ "use the same path for several parallel processes.")
+FUZZER_FLAG_INT(drill, 0, "Experimental: fuzz using a single unit as the seed "
+ "corpus, then merge with the initial corpus")
+FUZZER_FLAG_INT(output_csv, 0, "Enable pulse output in CSV format.")
+FUZZER_FLAG_INT(print_new_cov_pcs, 0, "If 1, print out new covered pcs.")
+
diff --git a/gnu/llvm/lib/Fuzzer/FuzzerIO.cpp b/gnu/llvm/lib/Fuzzer/FuzzerIO.cpp
new file mode 100644
index 00000000000..043fad396d5
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/FuzzerIO.cpp
@@ -0,0 +1,101 @@
+//===- 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 <iterator>
+#include <fstream>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <cstdarg>
+#include <cstdio>
+
+namespace fuzzer {
+
+static long GetEpoch(const std::string &Path) {
+ struct stat St;
+ if (stat(Path.c_str(), &St))
+ return 0; // Can't stat, be conservative.
+ return St.st_mtime;
+}
+
+static std::vector<std::string> ListFilesInDir(const std::string &Dir,
+ long *Epoch) {
+ std::vector<std::string> V;
+ if (Epoch) {
+ auto E = GetEpoch(Dir);
+ if (*Epoch >= E) return V;
+ *Epoch = E;
+ }
+ DIR *D = opendir(Dir.c_str());
+ if (!D) {
+ Printf("No such directory: %s; exiting\n", Dir.c_str());
+ exit(1);
+ }
+ while (auto E = readdir(D)) {
+ 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);
+ if (!T) {
+ Printf("No such directory: %s; exiting\n", Path.c_str());
+ exit(1);
+ }
+ return Unit((std::istreambuf_iterator<char>(T)),
+ std::istreambuf_iterator<char>());
+}
+
+std::string FileToString(const std::string &Path) {
+ std::ifstream T(Path);
+ return std::string((std::istreambuf_iterator<char>(T)),
+ std::istreambuf_iterator<char>());
+}
+
+void CopyFileToErr(const std::string &Path) {
+ Printf("%s", FileToString(Path).c_str());
+}
+
+void WriteToFile(const Unit &U, const std::string &Path) {
+ // Use raw C interface because this function may be called from a sig handler.
+ FILE *Out = fopen(Path.c_str(), "w");
+ if (!Out) return;
+ fwrite(U.data(), sizeof(U[0]), U.size(), Out);
+ fclose(Out);
+}
+
+void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V,
+ long *Epoch) {
+ long E = Epoch ? *Epoch : 0;
+ for (auto &X : ListFilesInDir(Path, Epoch)) {
+ auto FilePath = DirPlusFile(Path, X);
+ if (Epoch && GetEpoch(FilePath) < E) continue;
+ V->push_back(FileToVector(FilePath));
+ }
+}
+
+std::string DirPlusFile(const std::string &DirPath,
+ const std::string &FileName) {
+ return DirPath + "/" + FileName;
+}
+
+void Printf(const char *Fmt, ...) {
+ va_list ap;
+ va_start(ap, Fmt);
+ vfprintf(stderr, Fmt, ap);
+ va_end(ap);
+}
+
+} // namespace fuzzer
diff --git a/gnu/llvm/lib/Fuzzer/FuzzerInterface.cpp b/gnu/llvm/lib/Fuzzer/FuzzerInterface.cpp
new file mode 100644
index 00000000000..bcd726fc08e
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/FuzzerInterface.cpp
@@ -0,0 +1,30 @@
+//===- FuzzerInterface.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.
+//
+//===----------------------------------------------------------------------===//
+// Parts of public interface for libFuzzer.
+//===----------------------------------------------------------------------===//
+
+
+#include "FuzzerInterface.h"
+#include "FuzzerInternal.h"
+
+namespace fuzzer {
+
+void FuzzerRandomLibc::ResetSeed(unsigned int seed) { srand(seed); }
+
+size_t FuzzerRandomLibc::Rand() { return rand(); }
+
+UserSuppliedFuzzer::UserSuppliedFuzzer(FuzzerRandomBase *Rand)
+ : Rand(Rand), MD(*Rand) {}
+
+UserSuppliedFuzzer::~UserSuppliedFuzzer() {
+ if (OwnRand)
+ delete Rand;
+}
+
+} // namespace fuzzer.
diff --git a/gnu/llvm/lib/Fuzzer/FuzzerInterface.h b/gnu/llvm/lib/Fuzzer/FuzzerInterface.h
new file mode 100644
index 00000000000..e22b27a3dd2
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/FuzzerInterface.h
@@ -0,0 +1,198 @@
+//===- 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.
+//===----------------------------------------------------------------------===//
+
+// WARNING: keep the interface free of STL or any other header-based C++ lib,
+// to avoid bad interactions between the code used in the fuzzer and
+// the code used in the target function.
+
+#ifndef LLVM_FUZZER_INTERFACE_H
+#define LLVM_FUZZER_INTERFACE_H
+
+#include <limits>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+#include <string>
+
+namespace fuzzer {
+typedef std::vector<uint8_t> Unit;
+
+/// Returns an int 0. Values other than zero are reserved for future.
+typedef int (*UserCallback)(const uint8_t *Data, size_t Size);
+/** Simple C-like interface with a single user-supplied callback.
+
+Usage:
+
+#\code
+#include "FuzzerInterface.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ DoStuffWithData(Data, Size);
+ return 0;
+}
+
+// Implement your own main() or use the one from FuzzerMain.cpp.
+int main(int argc, char **argv) {
+ InitializeMeIfNeeded();
+ return fuzzer::FuzzerDriver(argc, argv, LLVMFuzzerTestOneInput);
+}
+#\endcode
+*/
+int FuzzerDriver(int argc, char **argv, UserCallback Callback);
+
+class FuzzerRandomBase {
+ public:
+ FuzzerRandomBase(){}
+ virtual ~FuzzerRandomBase(){};
+ virtual void ResetSeed(unsigned int seed) = 0;
+ // Return a random number.
+ virtual size_t Rand() = 0;
+ // Return a random number in range [0,n).
+ size_t operator()(size_t n) { return n ? Rand() % n : 0; }
+ bool RandBool() { return Rand() % 2; }
+};
+
+class FuzzerRandomLibc : public FuzzerRandomBase {
+ public:
+ FuzzerRandomLibc(unsigned int seed) { ResetSeed(seed); }
+ void ResetSeed(unsigned int seed) override;
+ ~FuzzerRandomLibc() override {}
+ size_t Rand() override;
+};
+
+class MutationDispatcher {
+ public:
+ MutationDispatcher(FuzzerRandomBase &Rand);
+ ~MutationDispatcher();
+ /// Indicate that we are about to start a new sequence of mutations.
+ void StartMutationSequence();
+ /// Print the current sequence of mutations.
+ void PrintMutationSequence();
+ /// Mutates data by shuffling bytes.
+ size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by erasing a byte.
+ size_t Mutate_EraseByte(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by inserting a byte.
+ size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by chanding one byte.
+ size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by chanding one bit.
+ size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize);
+
+ /// Mutates data by adding a word from the manual dictionary.
+ size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size,
+ size_t MaxSize);
+
+ /// Mutates data by adding a word from the automatic dictionary.
+ size_t Mutate_AddWordFromAutoDictionary(uint8_t *Data, size_t Size,
+ size_t MaxSize);
+
+ /// Tries to find an ASCII integer in Data, changes it to another ASCII int.
+ size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize);
+
+ /// CrossOver Data with some other element of the corpus.
+ size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize);
+
+ /// Applies one of the above mutations.
+ /// Returns the new size of data which could be up to MaxSize.
+ size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize);
+
+ /// Creates a cross-over of two pieces of Data, returns its size.
+ size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2,
+ size_t Size2, uint8_t *Out, size_t MaxOutSize);
+
+ void AddWordToManualDictionary(const Unit &Word);
+
+ void AddWordToAutoDictionary(const Unit &Word, size_t PositionHint);
+ void ClearAutoDictionary();
+
+ void SetCorpus(const std::vector<Unit> *Corpus);
+
+ private:
+ FuzzerRandomBase &Rand;
+ struct Impl;
+ Impl *MDImpl;
+};
+
+// For backward compatibility only, deprecated.
+static inline size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize,
+ FuzzerRandomBase &Rand) {
+ MutationDispatcher MD(Rand);
+ return MD.Mutate(Data, Size, MaxSize);
+}
+
+/** An abstract class that allows to use user-supplied mutators with libFuzzer.
+
+Usage:
+
+#\code
+#include "FuzzerInterface.h"
+class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
+ public:
+ MyFuzzer(fuzzer::FuzzerRandomBase *Rand);
+ // Must define the target function.
+ int TargetFunction(...) { ...; return 0; }
+ // Optionally define the mutator.
+ size_t Mutate(...) { ... }
+ // Optionally define the CrossOver method.
+ size_t CrossOver(...) { ... }
+};
+
+int main(int argc, char **argv) {
+ MyFuzzer F;
+ fuzzer::FuzzerDriver(argc, argv, F);
+}
+#\endcode
+*/
+class UserSuppliedFuzzer {
+ public:
+ UserSuppliedFuzzer(FuzzerRandomBase *Rand);
+ /// Executes the target function on 'Size' bytes of 'Data'.
+ virtual int TargetFunction(const uint8_t *Data, size_t Size) = 0;
+ virtual void StartMutationSequence() { MD.StartMutationSequence(); }
+ virtual void PrintMutationSequence() { MD.PrintMutationSequence(); }
+ virtual void SetCorpus(const std::vector<Unit> *Corpus) {
+ MD.SetCorpus(Corpus);
+ }
+ /// Mutates 'Size' bytes of data in 'Data' inplace into up to 'MaxSize' bytes,
+ /// returns the new size of the data, which should be positive.
+ virtual size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+ return MD.Mutate(Data, Size, MaxSize);
+ }
+ /// Crosses 'Data1' and 'Data2', writes up to 'MaxOutSize' bytes into Out,
+ /// returns the number of bytes written, which should be positive.
+ virtual size_t CrossOver(const uint8_t *Data1, size_t Size1,
+ const uint8_t *Data2, size_t Size2,
+ uint8_t *Out, size_t MaxOutSize) {
+ return MD.CrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize);
+ }
+ virtual ~UserSuppliedFuzzer();
+
+ FuzzerRandomBase &GetRand() { return *Rand; }
+
+ MutationDispatcher &GetMD() { return MD; }
+
+ private:
+ bool OwnRand = false;
+ FuzzerRandomBase *Rand;
+ MutationDispatcher MD;
+};
+
+/// Runs the fuzzing with the UserSuppliedFuzzer.
+int FuzzerDriver(int argc, char **argv, UserSuppliedFuzzer &USF);
+
+/// More C++-ish interface.
+int FuzzerDriver(const std::vector<std::string> &Args, UserSuppliedFuzzer &USF);
+int FuzzerDriver(const std::vector<std::string> &Args, UserCallback Callback);
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_INTERFACE_H
diff --git a/gnu/llvm/lib/Fuzzer/FuzzerInternal.h b/gnu/llvm/lib/Fuzzer/FuzzerInternal.h
new file mode 100644
index 00000000000..c1e9daac980
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/FuzzerInternal.h
@@ -0,0 +1,207 @@
+//===- FuzzerInternal.h - Internal header for the Fuzzer --------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Define the main class fuzzer::Fuzzer and most functions.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_INTERNAL_H
+#define LLVM_FUZZER_INTERNAL_H
+
+#include <cassert>
+#include <climits>
+#include <chrono>
+#include <cstddef>
+#include <cstdlib>
+#include <string>
+#include <vector>
+#include <unordered_set>
+
+#include "FuzzerInterface.h"
+
+namespace fuzzer {
+using namespace std::chrono;
+
+std::string FileToString(const std::string &Path);
+Unit FileToVector(const std::string &Path);
+void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V,
+ long *Epoch);
+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 Printf(const char *Fmt, ...);
+void Print(const Unit &U, const char *PrintAfter = "");
+void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = "");
+void PrintASCII(const Unit &U, const char *PrintAfter = "");
+std::string Hash(const Unit &U);
+void SetTimer(int Seconds);
+std::string Base64(const Unit &U);
+int ExecuteCommand(const std::string &Command);
+
+// Private copy of SHA1 implementation.
+static const int kSHA1NumBytes = 20;
+// Computes SHA1 hash of 'Len' bytes in 'Data', writes kSHA1NumBytes to 'Out'.
+void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out);
+
+// Changes U to contain only ASCII (isprint+isspace) characters.
+// Returns true iff U has been changed.
+bool ToASCII(Unit &U);
+bool IsASCII(const Unit &U);
+
+int NumberOfCpuCores();
+int GetPid();
+
+// Dictionary.
+
+// Parses one dictionary entry.
+// If successfull, write the enty to Unit and returns true,
+// otherwise returns false.
+bool ParseOneDictionaryEntry(const std::string &Str, Unit *U);
+// Parses the dictionary file, fills Units, returns true iff all lines
+// were parsed succesfully.
+bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units);
+
+class Fuzzer {
+ public:
+ struct FuzzingOptions {
+ int Verbosity = 1;
+ int MaxLen = 0;
+ int UnitTimeoutSec = 300;
+ int MaxTotalTimeSec = 0;
+ bool DoCrossOver = true;
+ int MutateDepth = 5;
+ bool ExitOnFirst = false;
+ bool UseCounters = false;
+ bool UseIndirCalls = true;
+ bool UseTraces = false;
+ bool UseFullCoverageSet = false;
+ bool Reload = true;
+ bool ShuffleAtStartUp = true;
+ int PreferSmallDuringInitialShuffle = -1;
+ size_t MaxNumberOfRuns = ULONG_MAX;
+ int SyncTimeout = 600;
+ int ReportSlowUnits = 10;
+ bool OnlyASCII = false;
+ std::string OutputCorpus;
+ std::string SyncCommand;
+ std::string ArtifactPrefix = "./";
+ std::string ExactArtifactPath;
+ bool SaveArtifacts = true;
+ bool PrintNEW = true; // Print a status line when new units are found;
+ bool OutputCSV = false;
+ bool PrintNewCovPcs = false;
+ };
+ Fuzzer(UserSuppliedFuzzer &USF, FuzzingOptions Options);
+ void AddToCorpus(const Unit &U) { Corpus.push_back(U); }
+ size_t ChooseUnitIdxToMutate();
+ const Unit &ChooseUnitToMutate() { return Corpus[ChooseUnitIdxToMutate()]; };
+ void Loop();
+ void Drill();
+ void ShuffleAndMinimize();
+ void InitializeTraceState();
+ size_t CorpusSize() const { return Corpus.size(); }
+ void ReadDir(const std::string &Path, long *Epoch) {
+ Printf("Loading corpus: %s\n", Path.c_str());
+ ReadDirToVectorOfUnits(Path.c_str(), &Corpus, Epoch);
+ }
+ void RereadOutputCorpus();
+ // 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 StaticAlarmCallback();
+
+ void ExecuteCallback(const Unit &U);
+
+ // Merge Corpora[1:] into Corpora[0].
+ void Merge(const std::vector<std::string> &Corpora);
+
+ private:
+ void AlarmCallback();
+ void MutateAndTestOne();
+ void ReportNewCoverage(const Unit &U);
+ bool RunOne(const Unit &U);
+ void RunOneAndUpdateCorpus(Unit &U);
+ void WriteToOutputCorpus(const Unit &U);
+ void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix);
+ void PrintStats(const char *Where, const char *End = "\n");
+ void PrintStatusForNewUnit(const Unit &U);
+ void PrintUnitInASCII(const Unit &U, const char *PrintAfter = "");
+
+ void SyncCorpus();
+
+ size_t RecordBlockCoverage();
+ size_t RecordCallerCalleeCoverage();
+ void PrepareCoverageBeforeRun();
+ bool CheckCoverageAfterRun();
+
+
+ // Trace-based fuzzing: we run a unit with some kind of tracing
+ // enabled and record potentially useful mutations. Then
+ // We apply these mutations one by one to the unit and run it again.
+
+ // Start tracing; forget all previously proposed mutations.
+ void StartTraceRecording();
+ // Stop tracing.
+ void StopTraceRecording();
+
+ void SetDeathCallback();
+ static void StaticDeathCallback();
+ void DeathCallback();
+ Unit CurrentUnit;
+
+ size_t TotalNumberOfRuns = 0;
+ size_t TotalNumberOfExecutedTraceBasedMutations = 0;
+
+ std::vector<Unit> Corpus;
+ std::unordered_set<std::string> UnitHashesAddedToCorpus;
+
+ // For UseCounters
+ std::vector<uint8_t> CounterBitmap;
+ size_t TotalBits() { // Slow. Call it only for printing stats.
+ size_t Res = 0;
+ for (auto x : CounterBitmap) Res += __builtin_popcount(x);
+ return Res;
+ }
+
+ UserSuppliedFuzzer &USF;
+ FuzzingOptions Options;
+ system_clock::time_point ProcessStartTime = system_clock::now();
+ system_clock::time_point LastExternalSync = system_clock::now();
+ system_clock::time_point UnitStartTime;
+ long TimeOfLongestUnitInSeconds = 0;
+ long EpochOfLastReadOfOutputCorpus = 0;
+ size_t LastRecordedBlockCoverage = 0;
+ size_t LastRecordedCallerCalleeCoverage = 0;
+ size_t LastCoveragePcBufferLen = 0;
+};
+
+class SimpleUserSuppliedFuzzer: public UserSuppliedFuzzer {
+ public:
+ SimpleUserSuppliedFuzzer(FuzzerRandomBase *Rand, UserCallback Callback)
+ : UserSuppliedFuzzer(Rand), Callback(Callback) {}
+
+ virtual int TargetFunction(const uint8_t *Data, size_t Size) override {
+ return Callback(Data, Size);
+ }
+
+ private:
+ UserCallback Callback = nullptr;
+};
+
+}; // namespace fuzzer
+
+#endif // LLVM_FUZZER_INTERNAL_H
diff --git a/gnu/llvm/lib/Fuzzer/FuzzerLoop.cpp b/gnu/llvm/lib/Fuzzer/FuzzerLoop.cpp
new file mode 100644
index 00000000000..5237682ff24
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/FuzzerLoop.cpp
@@ -0,0 +1,512 @@
+//===- 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 <algorithm>
+
+#if defined(__has_include)
+# if __has_include(<sanitizer/coverage_interface.h>)
+# include <sanitizer/coverage_interface.h>
+# endif
+#endif
+
+extern "C" {
+// Re-declare some of the sanitizer functions as "weak" so that
+// libFuzzer can be linked w/o the sanitizers and sanitizer-coverage
+// (in which case it will complain at start-up time).
+__attribute__((weak)) void __sanitizer_print_stack_trace();
+__attribute__((weak)) void __sanitizer_reset_coverage();
+__attribute__((weak)) size_t __sanitizer_get_total_unique_caller_callee_pairs();
+__attribute__((weak)) size_t __sanitizer_get_total_unique_coverage();
+__attribute__((weak))
+void __sanitizer_set_death_callback(void (*callback)(void));
+__attribute__((weak)) size_t __sanitizer_get_number_of_counters();
+__attribute__((weak))
+uintptr_t __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset);
+__attribute__((weak)) uintptr_t
+__sanitizer_get_coverage_pc_buffer(uintptr_t **data);
+}
+
+namespace fuzzer {
+static const size_t kMaxUnitSizeToPrint = 256;
+
+static void MissingWeakApiFunction(const char *FnName) {
+ Printf("ERROR: %s is not defined. Exiting.\n"
+ "Did you use -fsanitize-coverage=... to build your code?\n", FnName);
+ exit(1);
+}
+
+#define CHECK_WEAK_API_FUNCTION(fn) \
+ do { \
+ if (!fn) \
+ MissingWeakApiFunction(#fn); \
+ } while (false)
+
+// Only one Fuzzer per process.
+static Fuzzer *F;
+
+Fuzzer::Fuzzer(UserSuppliedFuzzer &USF, FuzzingOptions Options)
+ : USF(USF), Options(Options) {
+ SetDeathCallback();
+ InitializeTraceState();
+ assert(!F);
+ F = this;
+}
+
+void Fuzzer::SetDeathCallback() {
+ CHECK_WEAK_API_FUNCTION(__sanitizer_set_death_callback);
+ __sanitizer_set_death_callback(StaticDeathCallback);
+}
+
+void Fuzzer::PrintUnitInASCII(const Unit &U, const char *PrintAfter) {
+ PrintASCII(U, PrintAfter);
+}
+
+void Fuzzer::StaticDeathCallback() {
+ assert(F);
+ F->DeathCallback();
+}
+
+void Fuzzer::DeathCallback() {
+ Printf("DEATH:\n");
+ if (CurrentUnit.size() <= kMaxUnitSizeToPrint) {
+ Print(CurrentUnit, "\n");
+ PrintUnitInASCII(CurrentUnit, "\n");
+ }
+ WriteUnitToFileWithPrefix(CurrentUnit, "crash-");
+}
+
+void Fuzzer::StaticAlarmCallback() {
+ assert(F);
+ F->AlarmCallback();
+}
+
+void Fuzzer::AlarmCallback() {
+ assert(Options.UnitTimeoutSec > 0);
+ size_t Seconds =
+ duration_cast<seconds>(system_clock::now() - UnitStartTime).count();
+ if (Seconds == 0) return;
+ if (Options.Verbosity >= 2)
+ Printf("AlarmCallback %zd\n", Seconds);
+ if (Seconds >= (size_t)Options.UnitTimeoutSec) {
+ Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds);
+ Printf(" and the timeout value is %d (use -timeout=N to change)\n",
+ Options.UnitTimeoutSec);
+ if (CurrentUnit.size() <= kMaxUnitSizeToPrint) {
+ Print(CurrentUnit, "\n");
+ PrintUnitInASCII(CurrentUnit, "\n");
+ }
+ WriteUnitToFileWithPrefix(CurrentUnit, "timeout-");
+ Printf("==%d== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(),
+ Seconds);
+ if (__sanitizer_print_stack_trace)
+ __sanitizer_print_stack_trace();
+ Printf("SUMMARY: libFuzzer: timeout\n");
+ exit(1);
+ }
+}
+
+void Fuzzer::PrintStats(const char *Where, const char *End) {
+ size_t Seconds = secondsSinceProcessStartUp();
+ size_t ExecPerSec = (Seconds ? TotalNumberOfRuns / Seconds : 0);
+
+ if (Options.OutputCSV) {
+ static bool csvHeaderPrinted = false;
+ if (!csvHeaderPrinted) {
+ csvHeaderPrinted = true;
+ Printf("runs,block_cov,bits,cc_cov,corpus,execs_per_sec,tbms,reason\n");
+ }
+ Printf("%zd,%zd,%zd,%zd,%zd,%zd,%zd,%s\n", TotalNumberOfRuns,
+ LastRecordedBlockCoverage, TotalBits(),
+ LastRecordedCallerCalleeCoverage, Corpus.size(), ExecPerSec,
+ TotalNumberOfExecutedTraceBasedMutations, Where);
+ }
+
+ if (!Options.Verbosity)
+ return;
+ Printf("#%zd\t%s", TotalNumberOfRuns, Where);
+ if (LastRecordedBlockCoverage)
+ Printf(" cov: %zd", LastRecordedBlockCoverage);
+ if (auto TB = TotalBits())
+ Printf(" bits: %zd", TB);
+ if (LastRecordedCallerCalleeCoverage)
+ Printf(" indir: %zd", LastRecordedCallerCalleeCoverage);
+ Printf(" units: %zd exec/s: %zd", Corpus.size(), ExecPerSec);
+ if (TotalNumberOfExecutedTraceBasedMutations)
+ Printf(" tbm: %zd", TotalNumberOfExecutedTraceBasedMutations);
+ Printf("%s", End);
+}
+
+void Fuzzer::RereadOutputCorpus() {
+ if (Options.OutputCorpus.empty()) return;
+ std::vector<Unit> AdditionalCorpus;
+ ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus,
+ &EpochOfLastReadOfOutputCorpus);
+ if (Corpus.empty()) {
+ Corpus = AdditionalCorpus;
+ return;
+ }
+ if (!Options.Reload) return;
+ if (Options.Verbosity >= 2)
+ Printf("Reload: read %zd new units.\n", AdditionalCorpus.size());
+ for (auto &X : AdditionalCorpus) {
+ if (X.size() > (size_t)Options.MaxLen)
+ X.resize(Options.MaxLen);
+ if (UnitHashesAddedToCorpus.insert(Hash(X)).second) {
+ CurrentUnit.clear();
+ CurrentUnit.insert(CurrentUnit.begin(), X.begin(), X.end());
+ if (RunOne(CurrentUnit)) {
+ Corpus.push_back(X);
+ PrintStats("RELOAD");
+ }
+ }
+ }
+}
+
+void Fuzzer::ShuffleAndMinimize() {
+ bool PreferSmall = (Options.PreferSmallDuringInitialShuffle == 1 ||
+ (Options.PreferSmallDuringInitialShuffle == -1 &&
+ USF.GetRand().RandBool()));
+ if (Options.Verbosity)
+ Printf("PreferSmall: %d\n", PreferSmall);
+ PrintStats("READ ");
+ std::vector<Unit> NewCorpus;
+ if (Options.ShuffleAtStartUp) {
+ std::random_shuffle(Corpus.begin(), Corpus.end(), USF.GetRand());
+ if (PreferSmall)
+ std::stable_sort(
+ Corpus.begin(), Corpus.end(),
+ [](const Unit &A, const Unit &B) { return A.size() < B.size(); });
+ }
+ 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);
+ if (Options.OnlyASCII)
+ ToASCII(U);
+ if (RunOne(U)) {
+ NewCorpus.push_back(U);
+ if (Options.Verbosity >= 2)
+ Printf("NEW0: %zd L %zd\n", LastRecordedBlockCoverage, U.size());
+ }
+ }
+ }
+ Corpus = NewCorpus;
+ for (auto &X : Corpus)
+ UnitHashesAddedToCorpus.insert(Hash(X));
+ PrintStats("INITED");
+}
+
+bool Fuzzer::RunOne(const Unit &U) {
+ UnitStartTime = system_clock::now();
+ TotalNumberOfRuns++;
+
+ PrepareCoverageBeforeRun();
+ ExecuteCallback(U);
+ bool Res = CheckCoverageAfterRun();
+
+ auto UnitStopTime = system_clock::now();
+ auto TimeOfUnit =
+ duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
+ if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) &&
+ secondsSinceProcessStartUp() >= 2)
+ PrintStats("pulse ");
+ if (TimeOfUnit > TimeOfLongestUnitInSeconds &&
+ TimeOfUnit >= Options.ReportSlowUnits) {
+ TimeOfLongestUnitInSeconds = TimeOfUnit;
+ Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds);
+ WriteUnitToFileWithPrefix(U, "slow-unit-");
+ }
+ return Res;
+}
+
+void Fuzzer::RunOneAndUpdateCorpus(Unit &U) {
+ if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
+ return;
+ if (Options.OnlyASCII)
+ ToASCII(U);
+ if (RunOne(U))
+ ReportNewCoverage(U);
+}
+
+void Fuzzer::ExecuteCallback(const Unit &U) {
+ const uint8_t *Data = U.data();
+ uint8_t EmptyData;
+ if (!Data)
+ Data = &EmptyData;
+ int Res = USF.TargetFunction(Data, U.size());
+ (void)Res;
+ assert(Res == 0);
+}
+
+size_t Fuzzer::RecordBlockCoverage() {
+ CHECK_WEAK_API_FUNCTION(__sanitizer_get_total_unique_coverage);
+ uintptr_t PrevCoverage = LastRecordedBlockCoverage;
+ LastRecordedBlockCoverage = __sanitizer_get_total_unique_coverage();
+
+ if (PrevCoverage == LastRecordedBlockCoverage || !Options.PrintNewCovPcs)
+ return LastRecordedBlockCoverage;
+
+ uintptr_t PrevBufferLen = LastCoveragePcBufferLen;
+ uintptr_t *CoverageBuf;
+ LastCoveragePcBufferLen = __sanitizer_get_coverage_pc_buffer(&CoverageBuf);
+ assert(CoverageBuf);
+ for (size_t i = PrevBufferLen; i < LastCoveragePcBufferLen; ++i) {
+ Printf("0x%x\n", CoverageBuf[i]);
+ }
+
+ return LastRecordedBlockCoverage;
+}
+
+size_t Fuzzer::RecordCallerCalleeCoverage() {
+ if (!Options.UseIndirCalls)
+ return 0;
+ if (!__sanitizer_get_total_unique_caller_callee_pairs)
+ return 0;
+ return LastRecordedCallerCalleeCoverage =
+ __sanitizer_get_total_unique_caller_callee_pairs();
+}
+
+void Fuzzer::PrepareCoverageBeforeRun() {
+ if (Options.UseCounters) {
+ size_t NumCounters = __sanitizer_get_number_of_counters();
+ CounterBitmap.resize(NumCounters);
+ __sanitizer_update_counter_bitset_and_clear_counters(0);
+ }
+ RecordBlockCoverage();
+ RecordCallerCalleeCoverage();
+}
+
+bool Fuzzer::CheckCoverageAfterRun() {
+ size_t OldCoverage = LastRecordedBlockCoverage;
+ size_t NewCoverage = RecordBlockCoverage();
+ size_t OldCallerCalleeCoverage = LastRecordedCallerCalleeCoverage;
+ size_t NewCallerCalleeCoverage = RecordCallerCalleeCoverage();
+ size_t NumNewBits = 0;
+ if (Options.UseCounters)
+ NumNewBits = __sanitizer_update_counter_bitset_and_clear_counters(
+ CounterBitmap.data());
+ return NewCoverage > OldCoverage ||
+ NewCallerCalleeCoverage > OldCallerCalleeCoverage || NumNewBits;
+}
+
+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)
+ Printf("Written to %s\n", Path.c_str());
+ assert(!Options.OnlyASCII || IsASCII(U));
+}
+
+void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) {
+ if (!Options.SaveArtifacts)
+ return;
+ std::string Path = Options.ArtifactPrefix + Prefix + Hash(U);
+ if (!Options.ExactArtifactPath.empty())
+ Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix.
+ WriteToFile(U, Path);
+ Printf("artifact_prefix='%s'; Test unit written to %s\n",
+ Options.ArtifactPrefix.c_str(), Path.c_str());
+ if (U.size() <= kMaxUnitSizeToPrint)
+ Printf("Base64: %s\n", Base64(U).c_str());
+}
+
+void Fuzzer::SaveCorpus() {
+ if (Options.OutputCorpus.empty()) return;
+ for (const auto &U : Corpus)
+ WriteToFile(U, DirPlusFile(Options.OutputCorpus, Hash(U)));
+ if (Options.Verbosity)
+ Printf("Written corpus of %zd files to %s\n", Corpus.size(),
+ Options.OutputCorpus.c_str());
+}
+
+void Fuzzer::PrintStatusForNewUnit(const Unit &U) {
+ if (!Options.PrintNEW)
+ return;
+ PrintStats("NEW ", "");
+ if (Options.Verbosity) {
+ Printf(" L: %zd ", U.size());
+ USF.PrintMutationSequence();
+ Printf("\n");
+ }
+}
+
+void Fuzzer::ReportNewCoverage(const Unit &U) {
+ Corpus.push_back(U);
+ UnitHashesAddedToCorpus.insert(Hash(U));
+ PrintStatusForNewUnit(U);
+ WriteToOutputCorpus(U);
+ if (Options.ExitOnFirst)
+ exit(0);
+}
+
+void Fuzzer::Merge(const std::vector<std::string> &Corpora) {
+ if (Corpora.size() <= 1) {
+ Printf("Merge requires two or more corpus dirs\n");
+ return;
+ }
+ auto InitialCorpusDir = Corpora[0];
+ ReadDir(InitialCorpusDir, nullptr);
+ Printf("Merge: running the initial corpus '%s' of %d units\n",
+ InitialCorpusDir.c_str(), Corpus.size());
+ for (auto &U : Corpus)
+ RunOne(U);
+
+ std::vector<std::string> ExtraCorpora(Corpora.begin() + 1, Corpora.end());
+
+ size_t NumTried = 0;
+ size_t NumMerged = 0;
+ for (auto &C : ExtraCorpora) {
+ Corpus.clear();
+ ReadDir(C, nullptr);
+ Printf("Merge: merging the extra corpus '%s' of %zd units\n", C.c_str(),
+ Corpus.size());
+ for (auto &U : Corpus) {
+ NumTried++;
+ if (RunOne(U)) {
+ WriteToOutputCorpus(U);
+ NumMerged++;
+ }
+ }
+ }
+ Printf("Merge: written %zd out of %zd units\n", NumMerged, NumTried);
+}
+
+void Fuzzer::MutateAndTestOne() {
+ auto &U = CurrentUnit;
+ USF.StartMutationSequence();
+
+ U = ChooseUnitToMutate();
+
+ for (int i = 0; i < Options.MutateDepth; i++) {
+ size_t Size = U.size();
+ U.resize(Options.MaxLen);
+ size_t NewSize = USF.Mutate(U.data(), Size, U.size());
+ assert(NewSize > 0 && "Mutator returned empty unit");
+ assert(NewSize <= (size_t)Options.MaxLen &&
+ "Mutator return overisized unit");
+ U.resize(NewSize);
+ if (i == 0)
+ StartTraceRecording();
+ RunOneAndUpdateCorpus(U);
+ StopTraceRecording();
+ }
+}
+
+// Returns an index of random unit from the corpus to mutate.
+// Hypothesis: units added to the corpus last are more likely to be interesting.
+// This function gives more wieght to the more recent units.
+size_t Fuzzer::ChooseUnitIdxToMutate() {
+ size_t N = Corpus.size();
+ size_t Total = (N + 1) * N / 2;
+ size_t R = USF.GetRand()(Total);
+ size_t IdxBeg = 0, IdxEnd = N;
+ // Binary search.
+ while (IdxEnd - IdxBeg >= 2) {
+ size_t Idx = IdxBeg + (IdxEnd - IdxBeg) / 2;
+ if (R > (Idx + 1) * Idx / 2)
+ IdxBeg = Idx;
+ else
+ IdxEnd = Idx;
+ }
+ assert(IdxBeg < N);
+ return IdxBeg;
+}
+
+// Experimental search heuristic: drilling.
+// - Read, shuffle, execute and minimize the corpus.
+// - Choose one random unit.
+// - Reset the coverage.
+// - Start fuzzing as if the chosen unit was the only element of the corpus.
+// - When done, reset the coverage again.
+// - Merge the newly created corpus into the original one.
+void Fuzzer::Drill() {
+ // The corpus is already read, shuffled, and minimized.
+ assert(!Corpus.empty());
+ Options.PrintNEW = false; // Don't print NEW status lines when drilling.
+
+ Unit U = ChooseUnitToMutate();
+
+ CHECK_WEAK_API_FUNCTION(__sanitizer_reset_coverage);
+ __sanitizer_reset_coverage();
+
+ std::vector<Unit> SavedCorpus;
+ SavedCorpus.swap(Corpus);
+ Corpus.push_back(U);
+ assert(Corpus.size() == 1);
+ RunOne(U);
+ PrintStats("DRILL ");
+ std::string SavedOutputCorpusPath; // Don't write new units while drilling.
+ SavedOutputCorpusPath.swap(Options.OutputCorpus);
+ Loop();
+
+ __sanitizer_reset_coverage();
+
+ PrintStats("REINIT");
+ SavedOutputCorpusPath.swap(Options.OutputCorpus);
+ for (auto &U : SavedCorpus) {
+ CurrentUnit = U;
+ RunOne(U);
+ }
+ PrintStats("MERGE ");
+ Options.PrintNEW = true;
+ size_t NumMerged = 0;
+ for (auto &U : Corpus) {
+ CurrentUnit = U;
+ if (RunOne(U)) {
+ PrintStatusForNewUnit(U);
+ NumMerged++;
+ WriteToOutputCorpus(U);
+ }
+ }
+ PrintStats("MERGED");
+ if (NumMerged && Options.Verbosity)
+ Printf("Drilling discovered %zd new units\n", NumMerged);
+}
+
+void Fuzzer::Loop() {
+ system_clock::time_point LastCorpusReload = system_clock::now();
+ if (Options.DoCrossOver)
+ USF.SetCorpus(&Corpus);
+ while (true) {
+ SyncCorpus();
+ auto Now = system_clock::now();
+ if (duration_cast<seconds>(Now - LastCorpusReload).count()) {
+ RereadOutputCorpus();
+ LastCorpusReload = Now;
+ }
+ if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
+ break;
+ if (Options.MaxTotalTimeSec > 0 &&
+ secondsSinceProcessStartUp() >
+ static_cast<size_t>(Options.MaxTotalTimeSec))
+ break;
+ // Perform several mutations and runs.
+ MutateAndTestOne();
+ }
+
+ PrintStats("DONE ", "\n");
+}
+
+void Fuzzer::SyncCorpus() {
+ if (Options.SyncCommand.empty() || Options.OutputCorpus.empty()) return;
+ auto Now = system_clock::now();
+ if (duration_cast<seconds>(Now - LastExternalSync).count() <
+ Options.SyncTimeout)
+ return;
+ LastExternalSync = Now;
+ ExecuteCommand(Options.SyncCommand + " " + Options.OutputCorpus);
+}
+
+} // namespace fuzzer
diff --git a/gnu/llvm/lib/Fuzzer/FuzzerMain.cpp b/gnu/llvm/lib/Fuzzer/FuzzerMain.cpp
new file mode 100644
index 00000000000..c5af5b05909
--- /dev/null
+++ b/gnu/llvm/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" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+
+int main(int argc, char **argv) {
+ return fuzzer::FuzzerDriver(argc, argv, LLVMFuzzerTestOneInput);
+}
diff --git a/gnu/llvm/lib/Fuzzer/FuzzerMutate.cpp b/gnu/llvm/lib/Fuzzer/FuzzerMutate.cpp
new file mode 100644
index 00000000000..30e5b43c083
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/FuzzerMutate.cpp
@@ -0,0 +1,278 @@
+//===- 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 <cstring>
+
+#include "FuzzerInternal.h"
+
+#include <algorithm>
+
+namespace fuzzer {
+
+struct Mutator {
+ size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max);
+ const char *Name;
+};
+
+struct DictionaryEntry {
+ Unit Word;
+ size_t PositionHint;
+};
+
+struct MutationDispatcher::Impl {
+ std::vector<DictionaryEntry> ManualDictionary;
+ std::vector<DictionaryEntry> AutoDictionary;
+ std::vector<Mutator> Mutators;
+ std::vector<Mutator> CurrentMutatorSequence;
+ std::vector<DictionaryEntry> CurrentDictionaryEntrySequence;
+ const std::vector<Unit> *Corpus = nullptr;
+ FuzzerRandomBase &Rand;
+
+ void Add(Mutator M) { Mutators.push_back(M); }
+ Impl(FuzzerRandomBase &Rand) : Rand(Rand) {
+ Add({&MutationDispatcher::Mutate_EraseByte, "EraseByte"});
+ Add({&MutationDispatcher::Mutate_InsertByte, "InsertByte"});
+ Add({&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"});
+ Add({&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"});
+ Add({&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"});
+ Add({&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"});
+ Add({&MutationDispatcher::Mutate_CrossOver, "CrossOver"});
+ Add({&MutationDispatcher::Mutate_AddWordFromManualDictionary,
+ "AddFromManualDict"});
+ Add({&MutationDispatcher::Mutate_AddWordFromAutoDictionary,
+ "AddFromAutoDict"});
+ }
+ void SetCorpus(const std::vector<Unit> *Corpus) { this->Corpus = Corpus; }
+ size_t AddWordFromDictionary(const std::vector<DictionaryEntry> &D,
+ uint8_t *Data, size_t Size, size_t MaxSize);
+};
+
+static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
+ 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(FuzzerRandomBase &Rand) {
+ if (Rand.RandBool()) return Rand(256);
+ const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~.";
+ return Special[Rand(sizeof(Special) - 1)];
+}
+
+size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ assert(Size);
+ size_t ShuffleAmount =
+ Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size.
+ size_t ShuffleStart = Rand(Size - ShuffleAmount);
+ assert(ShuffleStart + ShuffleAmount <= Size);
+ std::random_shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount,
+ Rand);
+ return Size;
+}
+
+size_t MutationDispatcher::Mutate_EraseByte(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ assert(Size);
+ if (Size == 1) return 0;
+ size_t Idx = Rand(Size);
+ // Erase Data[Idx].
+ memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1);
+ return Size - 1;
+}
+
+size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size == MaxSize) return 0;
+ size_t Idx = Rand(Size + 1);
+ // Insert new value at Data[Idx].
+ memmove(Data + Idx + 1, Data + Idx, Size - Idx);
+ Data[Idx] = RandCh(Rand);
+ return Size + 1;
+}
+
+size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ size_t Idx = Rand(Size);
+ Data[Idx] = RandCh(Rand);
+ return Size;
+}
+
+size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ size_t Idx = Rand(Size);
+ Data[Idx] = FlipRandomBit(Data[Idx], Rand);
+ return Size;
+}
+
+size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data,
+ size_t Size,
+ size_t MaxSize) {
+ return MDImpl->AddWordFromDictionary(MDImpl->ManualDictionary, Data, Size,
+ MaxSize);
+}
+
+size_t MutationDispatcher::Mutate_AddWordFromAutoDictionary(uint8_t *Data,
+ size_t Size,
+ size_t MaxSize) {
+ return MDImpl->AddWordFromDictionary(MDImpl->AutoDictionary, Data, Size,
+ MaxSize);
+}
+
+size_t MutationDispatcher::Impl::AddWordFromDictionary(
+ const std::vector<DictionaryEntry> &D, uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (D.empty()) return 0;
+ const DictionaryEntry &DE = D[Rand(D.size())];
+ const Unit &Word = DE.Word;
+ size_t PositionHint = DE.PositionHint;
+ bool UsePositionHint = PositionHint != std::numeric_limits<size_t>::max() &&
+ PositionHint + Word.size() < Size && Rand.RandBool();
+ if (Rand.RandBool()) { // Insert Word.
+ if (Size + Word.size() > MaxSize) return 0;
+ size_t Idx = UsePositionHint ? PositionHint : Rand(Size + 1);
+ memmove(Data + Idx + Word.size(), Data + Idx, Size - Idx);
+ memcpy(Data + Idx, Word.data(), Word.size());
+ Size += Word.size();
+ } else { // Overwrite some bytes with Word.
+ if (Word.size() > Size) return 0;
+ size_t Idx = UsePositionHint ? PositionHint : Rand(Size - Word.size());
+ memcpy(Data + Idx, Word.data(), Word.size());
+ }
+ CurrentDictionaryEntrySequence.push_back(DE);
+ return Size;
+}
+
+size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ size_t B = Rand(Size);
+ while (B < Size && !isdigit(Data[B])) B++;
+ if (B == Size) return 0;
+ size_t E = B;
+ while (E < Size && isdigit(Data[E])) E++;
+ assert(B < E);
+ // now we have digits in [B, E).
+ // strtol and friends don't accept non-zero-teminated data, parse it manually.
+ uint64_t Val = Data[B] - '0';
+ for (size_t i = B + 1; i < E; i++)
+ Val = Val * 10 + Data[i] - '0';
+
+ // Mutate the integer value.
+ switch(Rand(5)) {
+ case 0: Val++; break;
+ case 1: Val--; break;
+ case 2: Val /= 2; break;
+ case 3: Val *= 2; break;
+ case 4: Val = Rand(Val * Val); break;
+ default: assert(0);
+ }
+ // Just replace the bytes with the new ones, don't bother moving bytes.
+ for (size_t i = B; i < E; i++) {
+ size_t Idx = E + B - i - 1;
+ assert(Idx >= B && Idx < E);
+ Data[Idx] = (Val % 10) + '0';
+ Val /= 10;
+ }
+ return Size;
+}
+
+size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ auto Corpus = MDImpl->Corpus;
+ if (!Corpus || Corpus->size() < 2 || Size == 0) return 0;
+ size_t Idx = Rand(Corpus->size());
+ const Unit &Other = (*Corpus)[Idx];
+ if (Other.empty()) return 0;
+ Unit U(MaxSize);
+ size_t NewSize =
+ CrossOver(Data, Size, Other.data(), Other.size(), U.data(), U.size());
+ assert(NewSize > 0 && "CrossOver returned empty unit");
+ assert(NewSize <= MaxSize && "CrossOver returned overisized unit");
+ memcpy(Data, U.data(), NewSize);
+ return NewSize;
+}
+
+void MutationDispatcher::StartMutationSequence() {
+ MDImpl->CurrentMutatorSequence.clear();
+ MDImpl->CurrentDictionaryEntrySequence.clear();
+}
+
+void MutationDispatcher::PrintMutationSequence() {
+ Printf("MS: %zd ", MDImpl->CurrentMutatorSequence.size());
+ for (auto M : MDImpl->CurrentMutatorSequence)
+ Printf("%s-", M.Name);
+ if (!MDImpl->CurrentDictionaryEntrySequence.empty()) {
+ Printf(" DE: ");
+ for (auto DE : MDImpl->CurrentDictionaryEntrySequence) {
+ Printf("\"");
+ PrintASCII(DE.Word, "\"-");
+ }
+ }
+}
+
+// Mutates Data in place, returns new size.
+size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+ assert(MaxSize > 0);
+ assert(Size <= MaxSize);
+ if (Size == 0) {
+ for (size_t i = 0; i < MaxSize; i++)
+ Data[i] = RandCh(Rand);
+ return MaxSize;
+ }
+ assert(Size > 0);
+ // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize),
+ // in which case they will return 0.
+ // Try several times before returning un-mutated data.
+ for (int Iter = 0; Iter < 10; Iter++) {
+ size_t MutatorIdx = Rand(MDImpl->Mutators.size());
+ auto M = MDImpl->Mutators[MutatorIdx];
+ size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);
+ if (NewSize) {
+ MDImpl->CurrentMutatorSequence.push_back(M);
+ return NewSize;
+ }
+ }
+ return Size;
+}
+
+void MutationDispatcher::SetCorpus(const std::vector<Unit> *Corpus) {
+ MDImpl->SetCorpus(Corpus);
+}
+
+void MutationDispatcher::AddWordToManualDictionary(const Unit &Word) {
+ MDImpl->ManualDictionary.push_back(
+ {Word, std::numeric_limits<size_t>::max()});
+}
+
+void MutationDispatcher::AddWordToAutoDictionary(const Unit &Word,
+ size_t PositionHint) {
+ static const size_t kMaxAutoDictSize = 1 << 14;
+ if (MDImpl->AutoDictionary.size() >= kMaxAutoDictSize) return;
+ MDImpl->AutoDictionary.push_back({Word, PositionHint});
+}
+
+void MutationDispatcher::ClearAutoDictionary() {
+ MDImpl->AutoDictionary.clear();
+}
+
+MutationDispatcher::MutationDispatcher(FuzzerRandomBase &Rand) : Rand(Rand) {
+ MDImpl = new Impl(Rand);
+}
+
+MutationDispatcher::~MutationDispatcher() { delete MDImpl; }
+
+} // namespace fuzzer
diff --git a/gnu/llvm/lib/Fuzzer/FuzzerSHA1.cpp b/gnu/llvm/lib/Fuzzer/FuzzerSHA1.cpp
new file mode 100644
index 00000000000..b42a04854cd
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/FuzzerSHA1.cpp
@@ -0,0 +1,202 @@
+//===- FuzzerSHA1.h - Private copy of the SHA1 implementation ---*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This code is taken from public domain
+// (http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c)
+// and modified by adding anonymous namespace, adding an interface
+// function fuzzer::ComputeSHA1() and removing unnecessary code.
+//
+// lib/Fuzzer can not use SHA1 implementation from openssl because
+// openssl may not be available and because we may be fuzzing openssl itself.
+// For the same reason we do not want to depend on SHA1 from LLVM tree.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerInternal.h"
+
+/* This code is public-domain - it is based on libcrypt
+ * placed in the public domain by Wei Dai and other contributors.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+namespace { // Added for LibFuzzer
+
+#ifdef __BIG_ENDIAN__
+# define SHA_BIG_ENDIAN
+#elif defined __LITTLE_ENDIAN__
+/* override */
+#elif defined __BYTE_ORDER
+# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+# define SHA_BIG_ENDIAN
+# endif
+#else // ! defined __LITTLE_ENDIAN__
+# include <endian.h> // machine/endian.h
+# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+# define SHA_BIG_ENDIAN
+# endif
+#endif
+
+
+/* header */
+
+#define HASH_LENGTH 20
+#define BLOCK_LENGTH 64
+
+typedef struct sha1nfo {
+ uint32_t buffer[BLOCK_LENGTH/4];
+ uint32_t state[HASH_LENGTH/4];
+ uint32_t byteCount;
+ uint8_t bufferOffset;
+ uint8_t keyBuffer[BLOCK_LENGTH];
+ uint8_t innerHash[HASH_LENGTH];
+} sha1nfo;
+
+/* public API - prototypes - TODO: doxygen*/
+
+/**
+ */
+void sha1_init(sha1nfo *s);
+/**
+ */
+void sha1_writebyte(sha1nfo *s, uint8_t data);
+/**
+ */
+void sha1_write(sha1nfo *s, const char *data, size_t len);
+/**
+ */
+uint8_t* sha1_result(sha1nfo *s);
+
+
+/* code */
+#define SHA1_K0 0x5a827999
+#define SHA1_K20 0x6ed9eba1
+#define SHA1_K40 0x8f1bbcdc
+#define SHA1_K60 0xca62c1d6
+
+void sha1_init(sha1nfo *s) {
+ s->state[0] = 0x67452301;
+ s->state[1] = 0xefcdab89;
+ s->state[2] = 0x98badcfe;
+ s->state[3] = 0x10325476;
+ s->state[4] = 0xc3d2e1f0;
+ s->byteCount = 0;
+ s->bufferOffset = 0;
+}
+
+uint32_t sha1_rol32(uint32_t number, uint8_t bits) {
+ return ((number << bits) | (number >> (32-bits)));
+}
+
+void sha1_hashBlock(sha1nfo *s) {
+ uint8_t i;
+ uint32_t a,b,c,d,e,t;
+
+ a=s->state[0];
+ b=s->state[1];
+ c=s->state[2];
+ d=s->state[3];
+ e=s->state[4];
+ for (i=0; i<80; i++) {
+ if (i>=16) {
+ t = s->buffer[(i+13)&15] ^ s->buffer[(i+8)&15] ^ s->buffer[(i+2)&15] ^ s->buffer[i&15];
+ s->buffer[i&15] = sha1_rol32(t,1);
+ }
+ if (i<20) {
+ t = (d ^ (b & (c ^ d))) + SHA1_K0;
+ } else if (i<40) {
+ t = (b ^ c ^ d) + SHA1_K20;
+ } else if (i<60) {
+ t = ((b & c) | (d & (b | c))) + SHA1_K40;
+ } else {
+ t = (b ^ c ^ d) + SHA1_K60;
+ }
+ t+=sha1_rol32(a,5) + e + s->buffer[i&15];
+ e=d;
+ d=c;
+ c=sha1_rol32(b,30);
+ b=a;
+ a=t;
+ }
+ s->state[0] += a;
+ s->state[1] += b;
+ s->state[2] += c;
+ s->state[3] += d;
+ s->state[4] += e;
+}
+
+void sha1_addUncounted(sha1nfo *s, uint8_t data) {
+ uint8_t * const b = (uint8_t*) s->buffer;
+#ifdef SHA_BIG_ENDIAN
+ b[s->bufferOffset] = data;
+#else
+ b[s->bufferOffset ^ 3] = data;
+#endif
+ s->bufferOffset++;
+ if (s->bufferOffset == BLOCK_LENGTH) {
+ sha1_hashBlock(s);
+ s->bufferOffset = 0;
+ }
+}
+
+void sha1_writebyte(sha1nfo *s, uint8_t data) {
+ ++s->byteCount;
+ sha1_addUncounted(s, data);
+}
+
+void sha1_write(sha1nfo *s, const char *data, size_t len) {
+ for (;len--;) sha1_writebyte(s, (uint8_t) *data++);
+}
+
+void sha1_pad(sha1nfo *s) {
+ // Implement SHA-1 padding (fips180-2 §5.1.1)
+
+ // Pad with 0x80 followed by 0x00 until the end of the block
+ sha1_addUncounted(s, 0x80);
+ while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00);
+
+ // Append length in the last 8 bytes
+ sha1_addUncounted(s, 0); // We're only using 32 bit lengths
+ sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths
+ sha1_addUncounted(s, 0); // So zero pad the top bits
+ sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8
+ sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as
+ sha1_addUncounted(s, s->byteCount >> 13); // byte.
+ sha1_addUncounted(s, s->byteCount >> 5);
+ sha1_addUncounted(s, s->byteCount << 3);
+}
+
+uint8_t* sha1_result(sha1nfo *s) {
+ // Pad to complete the last block
+ sha1_pad(s);
+
+#ifndef SHA_BIG_ENDIAN
+ // Swap byte order back
+ int i;
+ for (i=0; i<5; i++) {
+ s->state[i]=
+ (((s->state[i])<<24)& 0xff000000)
+ | (((s->state[i])<<8) & 0x00ff0000)
+ | (((s->state[i])>>8) & 0x0000ff00)
+ | (((s->state[i])>>24)& 0x000000ff);
+ }
+#endif
+
+ // Return pointer to hash (20 characters)
+ return (uint8_t*) s->state;
+}
+
+} // namespace; Added for LibFuzzer
+
+// The rest is added for LibFuzzer
+void fuzzer::ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out) {
+ sha1nfo s;
+ sha1_init(&s);
+ sha1_write(&s, (const char*)Data, Len);
+ memcpy(Out, sha1_result(&s), HASH_LENGTH);
+}
diff --git a/gnu/llvm/lib/Fuzzer/FuzzerSanitizerOptions.cpp b/gnu/llvm/lib/Fuzzer/FuzzerSanitizerOptions.cpp
new file mode 100644
index 00000000000..b2f20dd4ddf
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/FuzzerSanitizerOptions.cpp
@@ -0,0 +1,19 @@
+//===- 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.
+// * enable handle_abort.
+//===----------------------------------------------------------------------===//
+extern "C" const char *__asan_default_options() {
+ return "coverage_pcs=0:coverage=1:handle_abort=1";
+}
diff --git a/gnu/llvm/lib/Fuzzer/FuzzerTraceState.cpp b/gnu/llvm/lib/Fuzzer/FuzzerTraceState.cpp
new file mode 100644
index 00000000000..b2006fa3aa4
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/FuzzerTraceState.cpp
@@ -0,0 +1,604 @@
+//===- FuzzerTraceState.cpp - Trace-based fuzzer mutator ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file implements a mutation algorithm based on instruction traces and
+// on taint analysis feedback from DFSan.
+//
+// Instruction traces are special hooks inserted by the compiler around
+// interesting instructions. Currently supported traces:
+// * __sanitizer_cov_trace_cmp -- inserted before every ICMP instruction,
+// receives the type, size and arguments of ICMP.
+//
+// Every time a traced event is intercepted we analyse the data involved
+// in the event and suggest a mutation for future executions.
+// For example if 4 bytes of data that derive from input bytes {4,5,6,7}
+// are compared with a constant 12345,
+// we try to insert 12345, 12344, 12346 into bytes
+// {4,5,6,7} of the next fuzzed inputs.
+//
+// The fuzzer can work only with the traces, or with both traces and DFSan.
+//
+// DataFlowSanitizer (DFSan) is a tool for
+// generalised dynamic data flow (taint) analysis:
+// http://clang.llvm.org/docs/DataFlowSanitizer.html .
+//
+// The approach with DFSan-based fuzzing has some similarity to
+// "Taint-based Directed Whitebox Fuzzing"
+// by Vijay Ganesh & Tim Leek & Martin Rinard:
+// http://dspace.mit.edu/openaccess-disseminate/1721.1/59320,
+// but it uses a full blown LLVM IR taint analysis and separate instrumentation
+// to analyze all of the "attack points" at once.
+//
+// Workflow with DFSan:
+// * lib/Fuzzer/Fuzzer*.cpp is compiled w/o any instrumentation.
+// * The code under test is compiled with DFSan *and* with instruction traces.
+// * Every call to HOOK(a,b) is replaced by DFSan with
+// __dfsw_HOOK(a, b, label(a), label(b)) so that __dfsw_HOOK
+// gets all the taint labels for the arguments.
+// * At the Fuzzer startup we assign a unique DFSan label
+// to every byte of the input string (Fuzzer::CurrentUnit) so that for any
+// chunk of data we know which input bytes it has derived from.
+// * The __dfsw_* functions (implemented in this file) record the
+// parameters (i.e. the application data and the corresponding taint labels)
+// in a global state.
+//
+// Parts of this code will not function when DFSan is not linked in.
+// Instead of using ifdefs and thus requiring a separate build of lib/Fuzzer
+// we redeclare the dfsan_* interface functions as weak and check if they
+// are nullptr before calling.
+// If this approach proves to be useful we may add attribute(weak) to the
+// dfsan declarations in dfsan_interface.h
+//
+// This module is in the "proof of concept" stage.
+// It is capable of solving only the simplest puzzles
+// like test/dfsan/DFSanSimpleCmpTest.cpp.
+//===----------------------------------------------------------------------===//
+
+/* Example of manual usage (-fsanitize=dataflow is optional):
+(
+ cd $LLVM/lib/Fuzzer/
+ clang -fPIC -c -g -O2 -std=c++11 Fuzzer*.cpp
+ clang++ -O0 -std=c++11 -fsanitize-coverage=edge,trace-cmp \
+ -fsanitize=dataflow \
+ test/SimpleCmpTest.cpp Fuzzer*.o
+ ./a.out -use_traces=1
+)
+*/
+
+#include "FuzzerDFSan.h"
+#include "FuzzerInternal.h"
+
+#include <algorithm>
+#include <cstring>
+#include <thread>
+#include <map>
+
+#if !LLVM_FUZZER_SUPPORTS_DFSAN
+// Stubs for dfsan for platforms where dfsan does not exist and weak
+// functions don't work.
+extern "C" {
+dfsan_label dfsan_create_label(const char *desc, void *userdata) { return 0; }
+void dfsan_set_label(dfsan_label label, void *addr, size_t size) {}
+void dfsan_add_label(dfsan_label label, void *addr, size_t size) {}
+const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label) {
+ return nullptr;
+}
+dfsan_label dfsan_read_label(const void *addr, size_t size) { return 0; }
+} // extern "C"
+#endif // !LLVM_FUZZER_SUPPORTS_DFSAN
+
+namespace fuzzer {
+
+// These values are copied from include/llvm/IR/InstrTypes.h.
+// We do not include the LLVM headers here to remain independent.
+// If these values ever change, an assertion in ComputeCmp will fail.
+enum Predicate {
+ ICMP_EQ = 32, ///< equal
+ ICMP_NE = 33, ///< not equal
+ ICMP_UGT = 34, ///< unsigned greater than
+ ICMP_UGE = 35, ///< unsigned greater or equal
+ ICMP_ULT = 36, ///< unsigned less than
+ ICMP_ULE = 37, ///< unsigned less or equal
+ ICMP_SGT = 38, ///< signed greater than
+ ICMP_SGE = 39, ///< signed greater or equal
+ ICMP_SLT = 40, ///< signed less than
+ ICMP_SLE = 41, ///< signed less or equal
+};
+
+template <class U, class S>
+bool ComputeCmp(size_t CmpType, U Arg1, U Arg2) {
+ switch(CmpType) {
+ case ICMP_EQ : return Arg1 == Arg2;
+ case ICMP_NE : return Arg1 != Arg2;
+ case ICMP_UGT: return Arg1 > Arg2;
+ case ICMP_UGE: return Arg1 >= Arg2;
+ case ICMP_ULT: return Arg1 < Arg2;
+ case ICMP_ULE: return Arg1 <= Arg2;
+ case ICMP_SGT: return (S)Arg1 > (S)Arg2;
+ case ICMP_SGE: return (S)Arg1 >= (S)Arg2;
+ case ICMP_SLT: return (S)Arg1 < (S)Arg2;
+ case ICMP_SLE: return (S)Arg1 <= (S)Arg2;
+ default: assert(0 && "unsupported CmpType");
+ }
+ return false;
+}
+
+static bool ComputeCmp(size_t CmpSize, size_t CmpType, uint64_t Arg1,
+ uint64_t Arg2) {
+ if (CmpSize == 8) return ComputeCmp<uint64_t, int64_t>(CmpType, Arg1, Arg2);
+ if (CmpSize == 4) return ComputeCmp<uint32_t, int32_t>(CmpType, Arg1, Arg2);
+ if (CmpSize == 2) return ComputeCmp<uint16_t, int16_t>(CmpType, Arg1, Arg2);
+ if (CmpSize == 1) return ComputeCmp<uint8_t, int8_t>(CmpType, Arg1, Arg2);
+ // Other size, ==
+ if (CmpType == ICMP_EQ) return Arg1 == Arg2;
+ // assert(0 && "unsupported cmp and type size combination");
+ return true;
+}
+
+// As a simplification we use the range of input bytes instead of a set of input
+// bytes.
+struct LabelRange {
+ uint16_t Beg, End; // Range is [Beg, End), thus Beg==End is an empty range.
+
+ LabelRange(uint16_t Beg = 0, uint16_t End = 0) : Beg(Beg), End(End) {}
+
+ static LabelRange Join(LabelRange LR1, LabelRange LR2) {
+ if (LR1.Beg == LR1.End) return LR2;
+ if (LR2.Beg == LR2.End) return LR1;
+ return {std::min(LR1.Beg, LR2.Beg), std::max(LR1.End, LR2.End)};
+ }
+ LabelRange &Join(LabelRange LR) {
+ return *this = Join(*this, LR);
+ }
+ static LabelRange Singleton(const dfsan_label_info *LI) {
+ uint16_t Idx = (uint16_t)(uintptr_t)LI->userdata;
+ assert(Idx > 0);
+ return {(uint16_t)(Idx - 1), Idx};
+ }
+};
+
+// For now, very simple: put Size bytes of Data at position Pos.
+struct TraceBasedMutation {
+ static const size_t kMaxSize = 28;
+ uint32_t Pos : 24;
+ uint32_t Size : 8;
+ uint8_t Data[kMaxSize];
+};
+
+const size_t TraceBasedMutation::kMaxSize;
+
+class TraceState {
+ public:
+ TraceState(UserSuppliedFuzzer &USF,
+ const Fuzzer::FuzzingOptions &Options, const Unit &CurrentUnit)
+ : USF(USF), Options(Options), CurrentUnit(CurrentUnit) {
+ // Current trace collection is not thread-friendly and it probably
+ // does not have to be such, but at least we should not crash in presence
+ // of threads. So, just ignore all traces coming from all threads but one.
+ IsMyThread = true;
+ }
+
+ LabelRange GetLabelRange(dfsan_label L);
+ void DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
+ uint64_t Arg1, uint64_t Arg2, dfsan_label L1,
+ dfsan_label L2);
+ void DFSanMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
+ const uint8_t *Data2, dfsan_label L1,
+ dfsan_label L2);
+ void DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits, uint64_t Val,
+ size_t NumCases, uint64_t *Cases, dfsan_label L);
+ void TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
+ uint64_t Arg1, uint64_t Arg2);
+ void TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
+ const uint8_t *Data2);
+
+ void TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits, uint64_t Val,
+ size_t NumCases, uint64_t *Cases);
+ int TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
+ size_t DataSize);
+ int TryToAddDesiredData(const uint8_t *PresentData,
+ const uint8_t *DesiredData, size_t DataSize);
+
+ void StartTraceRecording() {
+ if (!Options.UseTraces) return;
+ RecordingTraces = true;
+ NumMutations = 0;
+ USF.GetMD().ClearAutoDictionary();
+ }
+
+ void StopTraceRecording() {
+ if (!RecordingTraces) return;
+ RecordingTraces = false;
+ for (size_t i = 0; i < NumMutations; i++) {
+ auto &M = Mutations[i];
+ Unit U(M.Data, M.Data + M.Size);
+ if (Options.Verbosity >= 2) {
+ AutoDictUnitCounts[U]++;
+ AutoDictAdds++;
+ if ((AutoDictAdds & (AutoDictAdds - 1)) == 0) {
+ typedef std::pair<size_t, Unit> CU;
+ std::vector<CU> CountedUnits;
+ for (auto &I : AutoDictUnitCounts)
+ CountedUnits.push_back(std::make_pair(I.second, I.first));
+ std::sort(CountedUnits.begin(), CountedUnits.end(),
+ [](const CU &a, const CU &b) { return a.first > b.first; });
+ Printf("AutoDict:\n");
+ for (auto &I : CountedUnits) {
+ Printf(" %zd ", I.first);
+ PrintASCII(I.second);
+ Printf("\n");
+ }
+ }
+ }
+ USF.GetMD().AddWordToAutoDictionary(U, M.Pos);
+ }
+ }
+
+ void AddMutation(uint32_t Pos, uint32_t Size, const uint8_t *Data) {
+ if (NumMutations >= kMaxMutations) return;
+ assert(Size <= TraceBasedMutation::kMaxSize);
+ auto &M = Mutations[NumMutations++];
+ M.Pos = Pos;
+ M.Size = Size;
+ memcpy(M.Data, Data, Size);
+ }
+
+ void AddMutation(uint32_t Pos, uint32_t Size, uint64_t Data) {
+ assert(Size <= sizeof(Data));
+ AddMutation(Pos, Size, reinterpret_cast<uint8_t*>(&Data));
+ }
+
+ private:
+ bool IsTwoByteData(uint64_t Data) {
+ int64_t Signed = static_cast<int64_t>(Data);
+ Signed >>= 16;
+ return Signed == 0 || Signed == -1L;
+ }
+ bool RecordingTraces = false;
+ static const size_t kMaxMutations = 1 << 16;
+ size_t NumMutations;
+ TraceBasedMutation Mutations[kMaxMutations];
+ LabelRange LabelRanges[1 << (sizeof(dfsan_label) * 8)];
+ UserSuppliedFuzzer &USF;
+ const Fuzzer::FuzzingOptions &Options;
+ const Unit &CurrentUnit;
+ std::map<Unit, size_t> AutoDictUnitCounts;
+ size_t AutoDictAdds = 0;
+ static thread_local bool IsMyThread;
+};
+
+thread_local bool TraceState::IsMyThread;
+
+LabelRange TraceState::GetLabelRange(dfsan_label L) {
+ LabelRange &LR = LabelRanges[L];
+ if (LR.Beg < LR.End || L == 0)
+ return LR;
+ const dfsan_label_info *LI = dfsan_get_label_info(L);
+ if (LI->l1 || LI->l2)
+ return LR = LabelRange::Join(GetLabelRange(LI->l1), GetLabelRange(LI->l2));
+ return LR = LabelRange::Singleton(LI);
+}
+
+void TraceState::DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
+ uint64_t Arg1, uint64_t Arg2, dfsan_label L1,
+ dfsan_label L2) {
+ assert(ReallyHaveDFSan());
+ if (!RecordingTraces || !IsMyThread) return;
+ if (L1 == 0 && L2 == 0)
+ return; // Not actionable.
+ if (L1 != 0 && L2 != 0)
+ return; // Probably still actionable.
+ bool Res = ComputeCmp(CmpSize, CmpType, Arg1, Arg2);
+ uint64_t Data = L1 ? Arg2 : Arg1;
+ LabelRange LR = L1 ? GetLabelRange(L1) : GetLabelRange(L2);
+
+ for (size_t Pos = LR.Beg; Pos + CmpSize <= LR.End; Pos++) {
+ AddMutation(Pos, CmpSize, Data);
+ AddMutation(Pos, CmpSize, Data + 1);
+ AddMutation(Pos, CmpSize, Data - 1);
+ }
+
+ if (CmpSize > LR.End - LR.Beg)
+ AddMutation(LR.Beg, (unsigned)(LR.End - LR.Beg), Data);
+
+
+ if (Options.Verbosity >= 3)
+ Printf("DFSanCmpCallback: PC %lx S %zd T %zd A1 %llx A2 %llx R %d L1 %d L2 "
+ "%d MU %zd\n",
+ PC, CmpSize, CmpType, Arg1, Arg2, Res, L1, L2, NumMutations);
+}
+
+void TraceState::DFSanMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
+ const uint8_t *Data2, dfsan_label L1,
+ dfsan_label L2) {
+
+ assert(ReallyHaveDFSan());
+ if (!RecordingTraces || !IsMyThread) return;
+ if (L1 == 0 && L2 == 0)
+ return; // Not actionable.
+ if (L1 != 0 && L2 != 0)
+ return; // Probably still actionable.
+
+ const uint8_t *Data = L1 ? Data2 : Data1;
+ LabelRange LR = L1 ? GetLabelRange(L1) : GetLabelRange(L2);
+ for (size_t Pos = LR.Beg; Pos + CmpSize <= LR.End; Pos++) {
+ AddMutation(Pos, CmpSize, Data);
+ if (Options.Verbosity >= 3)
+ Printf("DFSanMemcmpCallback: Pos %d Size %d\n", Pos, CmpSize);
+ }
+}
+
+void TraceState::DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits,
+ uint64_t Val, size_t NumCases,
+ uint64_t *Cases, dfsan_label L) {
+ assert(ReallyHaveDFSan());
+ if (!RecordingTraces || !IsMyThread) return;
+ if (!L) return; // Not actionable.
+ LabelRange LR = GetLabelRange(L);
+ size_t ValSize = ValSizeInBits / 8;
+ bool TryShort = IsTwoByteData(Val);
+ for (size_t i = 0; i < NumCases; i++)
+ TryShort &= IsTwoByteData(Cases[i]);
+
+ for (size_t Pos = LR.Beg; Pos + ValSize <= LR.End; Pos++)
+ for (size_t i = 0; i < NumCases; i++)
+ AddMutation(Pos, ValSize, Cases[i]);
+
+ if (TryShort)
+ for (size_t Pos = LR.Beg; Pos + 2 <= LR.End; Pos++)
+ for (size_t i = 0; i < NumCases; i++)
+ AddMutation(Pos, 2, Cases[i]);
+
+ if (Options.Verbosity >= 3)
+ Printf("DFSanSwitchCallback: PC %lx Val %zd SZ %zd # %zd L %d: {%d, %d} "
+ "TryShort %d\n",
+ PC, Val, ValSize, NumCases, L, LR.Beg, LR.End, TryShort);
+}
+
+int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
+ size_t DataSize) {
+ int Res = 0;
+ const uint8_t *Beg = CurrentUnit.data();
+ const uint8_t *End = Beg + CurrentUnit.size();
+ for (const uint8_t *Cur = Beg; Cur < End; Cur++) {
+ Cur = (uint8_t *)memmem(Cur, End - Cur, &PresentData, DataSize);
+ if (!Cur)
+ break;
+ size_t Pos = Cur - Beg;
+ assert(Pos < CurrentUnit.size());
+ AddMutation(Pos, DataSize, DesiredData);
+ AddMutation(Pos, DataSize, DesiredData + 1);
+ AddMutation(Pos, DataSize, DesiredData - 1);
+ Res++;
+ }
+ return Res;
+}
+
+int TraceState::TryToAddDesiredData(const uint8_t *PresentData,
+ const uint8_t *DesiredData,
+ size_t DataSize) {
+ int Res = 0;
+ const uint8_t *Beg = CurrentUnit.data();
+ const uint8_t *End = Beg + CurrentUnit.size();
+ for (const uint8_t *Cur = Beg; Cur < End; Cur++) {
+ Cur = (uint8_t *)memmem(Cur, End - Cur, PresentData, DataSize);
+ if (!Cur)
+ break;
+ size_t Pos = Cur - Beg;
+ assert(Pos < CurrentUnit.size());
+ AddMutation(Pos, DataSize, DesiredData);
+ Res++;
+ }
+ return Res;
+}
+
+void TraceState::TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
+ uint64_t Arg1, uint64_t Arg2) {
+ if (!RecordingTraces || !IsMyThread) return;
+ if ((CmpType == ICMP_EQ || CmpType == ICMP_NE) && Arg1 == Arg2)
+ return; // No reason to mutate.
+ int Added = 0;
+ Added += TryToAddDesiredData(Arg1, Arg2, CmpSize);
+ Added += TryToAddDesiredData(Arg2, Arg1, CmpSize);
+ if (!Added && CmpSize == 4 && IsTwoByteData(Arg1) && IsTwoByteData(Arg2)) {
+ Added += TryToAddDesiredData(Arg1, Arg2, 2);
+ Added += TryToAddDesiredData(Arg2, Arg1, 2);
+ }
+ if (Options.Verbosity >= 3 && Added)
+ Printf("TraceCmp %zd/%zd: %p %zd %zd\n", CmpSize, CmpType, PC, Arg1, Arg2);
+}
+
+void TraceState::TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
+ const uint8_t *Data2) {
+ if (!RecordingTraces || !IsMyThread) return;
+ CmpSize = std::min(CmpSize, TraceBasedMutation::kMaxSize);
+ int Added2 = TryToAddDesiredData(Data1, Data2, CmpSize);
+ int Added1 = TryToAddDesiredData(Data2, Data1, CmpSize);
+ if ((Added1 || Added2) && Options.Verbosity >= 3) {
+ Printf("MemCmp Added %d%d: ", Added1, Added2);
+ if (Added1) PrintASCII(Data1, CmpSize);
+ if (Added2) PrintASCII(Data2, CmpSize);
+ Printf("\n");
+ }
+}
+
+void TraceState::TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits,
+ uint64_t Val, size_t NumCases,
+ uint64_t *Cases) {
+ if (!RecordingTraces || !IsMyThread) return;
+ size_t ValSize = ValSizeInBits / 8;
+ bool TryShort = IsTwoByteData(Val);
+ for (size_t i = 0; i < NumCases; i++)
+ TryShort &= IsTwoByteData(Cases[i]);
+
+ if (Options.Verbosity >= 3)
+ Printf("TraceSwitch: %p %zd # %zd; TryShort %d\n", PC, Val, NumCases,
+ TryShort);
+
+ for (size_t i = 0; i < NumCases; i++) {
+ TryToAddDesiredData(Val, Cases[i], ValSize);
+ if (TryShort)
+ TryToAddDesiredData(Val, Cases[i], 2);
+ }
+}
+
+static TraceState *TS;
+
+void Fuzzer::StartTraceRecording() {
+ if (!TS) return;
+ if (ReallyHaveDFSan())
+ for (size_t i = 0; i < static_cast<size_t>(Options.MaxLen); i++)
+ dfsan_set_label(i + 1, &CurrentUnit[i], 1);
+ TS->StartTraceRecording();
+}
+
+void Fuzzer::StopTraceRecording() {
+ if (!TS) return;
+ TS->StopTraceRecording();
+}
+
+void Fuzzer::InitializeTraceState() {
+ if (!Options.UseTraces) return;
+ TS = new TraceState(USF, Options, CurrentUnit);
+ CurrentUnit.resize(Options.MaxLen);
+ // The rest really requires DFSan.
+ if (!ReallyHaveDFSan()) return;
+ for (size_t i = 0; i < static_cast<size_t>(Options.MaxLen); i++) {
+ dfsan_label L = dfsan_create_label("input", (void*)(i + 1));
+ // We assume that no one else has called dfsan_create_label before.
+ if (L != i + 1) {
+ Printf("DFSan labels are not starting from 1, exiting\n");
+ exit(1);
+ }
+ }
+}
+
+static size_t InternalStrnlen(const char *S, size_t MaxLen) {
+ size_t Len = 0;
+ for (; Len < MaxLen && S[Len]; Len++) {}
+ return Len;
+}
+
+} // namespace fuzzer
+
+using fuzzer::TS;
+
+extern "C" {
+void __dfsw___sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1,
+ uint64_t Arg2, dfsan_label L0,
+ dfsan_label L1, dfsan_label L2) {
+ if (!TS) return;
+ assert(L0 == 0);
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uint64_t CmpSize = (SizeAndType >> 32) / 8;
+ uint64_t Type = (SizeAndType << 32) >> 32;
+ TS->DFSanCmpCallback(PC, CmpSize, Type, Arg1, Arg2, L1, L2);
+}
+
+void __dfsw___sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases,
+ dfsan_label L1, dfsan_label L2) {
+ if (!TS) return;
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ TS->DFSanSwitchCallback(PC, Cases[1], Val, Cases[0], Cases+2, L1);
+}
+
+void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2,
+ size_t n, dfsan_label s1_label,
+ dfsan_label s2_label, dfsan_label n_label) {
+ if (!TS) return;
+ dfsan_label L1 = dfsan_read_label(s1, n);
+ dfsan_label L2 = dfsan_read_label(s2, n);
+ TS->DFSanMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
+ reinterpret_cast<const uint8_t *>(s2), L1, L2);
+}
+
+void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2,
+ size_t n, dfsan_label s1_label,
+ dfsan_label s2_label, dfsan_label n_label) {
+ if (!TS) return;
+ n = std::min(n, fuzzer::InternalStrnlen(s1, n));
+ n = std::min(n, fuzzer::InternalStrnlen(s2, n));
+ dfsan_label L1 = dfsan_read_label(s1, n);
+ dfsan_label L2 = dfsan_read_label(s2, n);
+ TS->DFSanMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
+ reinterpret_cast<const uint8_t *>(s2), L1, L2);
+}
+
+void dfsan_weak_hook_strcmp(void *caller_pc, const char *s1, const char *s2,
+ dfsan_label s1_label, dfsan_label s2_label) {
+ if (!TS) return;
+ size_t Len1 = strlen(s1);
+ size_t Len2 = strlen(s2);
+ size_t N = std::min(Len1, Len2);
+ if (N <= 1) return; // Not interesting.
+ dfsan_label L1 = dfsan_read_label(s1, Len1);
+ dfsan_label L2 = dfsan_read_label(s2, Len2);
+ TS->DFSanMemcmpCallback(N, reinterpret_cast<const uint8_t *>(s1),
+ reinterpret_cast<const uint8_t *>(s2), L1, L2);
+}
+
+// We may need to avoid defining weak hooks to stay compatible with older clang.
+#ifndef LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
+# define LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS 1
+#endif
+
+#if LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
+void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
+ const void *s2, size_t n, int result) {
+ if (!TS) return;
+ if (result == 0) return; // No reason to mutate.
+ if (n <= 1) return; // Not interesting.
+ TS->TraceMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
+ reinterpret_cast<const uint8_t *>(s2));
+}
+
+void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
+ const char *s2, size_t n, int result) {
+ if (!TS) return;
+ if (result == 0) return; // No reason to mutate.
+ size_t Len1 = fuzzer::InternalStrnlen(s1, n);
+ size_t Len2 = fuzzer::InternalStrnlen(s2, n);
+ n = std::min(n, Len1);
+ n = std::min(n, Len2);
+ if (n <= 1) return; // Not interesting.
+ TS->TraceMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
+ reinterpret_cast<const uint8_t *>(s2));
+}
+
+void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
+ const char *s2, int result) {
+ if (!TS) return;
+ if (result == 0) return; // No reason to mutate.
+ size_t Len1 = strlen(s1);
+ size_t Len2 = strlen(s2);
+ size_t N = std::min(Len1, Len2);
+ if (N <= 1) return; // Not interesting.
+ TS->TraceMemcmpCallback(N, reinterpret_cast<const uint8_t *>(s1),
+ reinterpret_cast<const uint8_t *>(s2));
+}
+
+#endif // LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
+
+__attribute__((visibility("default")))
+void __sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1,
+ uint64_t Arg2) {
+ if (!TS) return;
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ uint64_t CmpSize = (SizeAndType >> 32) / 8;
+ uint64_t Type = (SizeAndType << 32) >> 32;
+ TS->TraceCmpCallback(PC, CmpSize, Type, Arg1, Arg2);
+}
+
+__attribute__((visibility("default")))
+void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
+ if (!TS) return;
+ uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+ TS->TraceSwitchCallback(PC, Cases[1], Val, Cases[0], Cases + 2);
+}
+
+} // extern "C"
diff --git a/gnu/llvm/lib/Fuzzer/FuzzerUtil.cpp b/gnu/llvm/lib/Fuzzer/FuzzerUtil.cpp
new file mode 100644
index 00000000000..d7226cfce96
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/FuzzerUtil.cpp
@@ -0,0 +1,212 @@
+//===- 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 <sstream>
+#include <iomanip>
+#include <sys/time.h>
+#include <cassert>
+#include <cstring>
+#include <signal.h>
+#include <sstream>
+#include <unistd.h>
+
+namespace fuzzer {
+
+void Print(const Unit &v, const char *PrintAfter) {
+ for (auto x : v)
+ Printf("0x%x,", (unsigned) x);
+ Printf("%s", PrintAfter);
+}
+
+void PrintASCIIByte(uint8_t Byte) {
+ if (Byte == '\\')
+ Printf("\\\\");
+ else if (Byte == '"')
+ Printf("\\\"");
+ else if (Byte >= 32 && Byte < 127)
+ Printf("%c", Byte);
+ else
+ Printf("\\x%02x", Byte);
+}
+
+void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) {
+ for (size_t i = 0; i < Size; i++)
+ PrintASCIIByte(Data[i]);
+ Printf("%s", PrintAfter);
+}
+
+void PrintASCII(const Unit &U, const char *PrintAfter) {
+ for (auto X : U)
+ PrintASCIIByte(X);
+ Printf("%s", PrintAfter);
+}
+
+std::string Hash(const Unit &U) {
+ uint8_t Hash[kSHA1NumBytes];
+ ComputeSHA1(U.data(), U.size(), Hash);
+ std::stringstream SS;
+ for (int i = 0; i < kSHA1NumBytes; i++)
+ SS << std::hex << std::setfill('0') << std::setw(2) << (unsigned)Hash[i];
+ return SS.str();
+}
+
+static void AlarmHandler(int, siginfo_t *, void *) {
+ Fuzzer::StaticAlarmCallback();
+}
+
+void SetTimer(int Seconds) {
+ struct itimerval T {{Seconds, 0}, {Seconds, 0}};
+ 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);
+}
+
+int NumberOfCpuCores() {
+ FILE *F = popen("nproc", "r");
+ int N = 0;
+ fscanf(F, "%d", &N);
+ fclose(F);
+ return N;
+}
+
+int ExecuteCommand(const std::string &Command) {
+ return system(Command.c_str());
+}
+
+bool ToASCII(Unit &U) {
+ bool Changed = false;
+ for (auto &X : U) {
+ auto NewX = X;
+ NewX &= 127;
+ if (!isspace(NewX) && !isprint(NewX))
+ NewX = ' ';
+ Changed |= NewX != X;
+ X = NewX;
+ }
+ return Changed;
+}
+
+bool IsASCII(const Unit &U) {
+ for (auto X : U)
+ if (!(isprint(X) || isspace(X))) return false;
+ return true;
+}
+
+bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) {
+ U->clear();
+ if (Str.empty()) return false;
+ size_t L = 0, R = Str.size() - 1; // We are parsing the range [L,R].
+ // Skip spaces from both sides.
+ while (L < R && isspace(Str[L])) L++;
+ while (R > L && isspace(Str[R])) R--;
+ if (R - L < 2) return false;
+ // Check the closing "
+ if (Str[R] != '"') return false;
+ R--;
+ // Find the opening "
+ while (L < R && Str[L] != '"') L++;
+ if (L >= R) return false;
+ assert(Str[L] == '\"');
+ L++;
+ assert(L <= R);
+ for (size_t Pos = L; Pos <= R; Pos++) {
+ uint8_t V = (uint8_t)Str[Pos];
+ if (!isprint(V) && !isspace(V)) return false;
+ if (V =='\\') {
+ // Handle '\\'
+ if (Pos + 1 <= R && (Str[Pos + 1] == '\\' || Str[Pos + 1] == '"')) {
+ U->push_back(Str[Pos + 1]);
+ Pos++;
+ continue;
+ }
+ // Handle '\xAB'
+ if (Pos + 3 <= R && Str[Pos + 1] == 'x'
+ && isxdigit(Str[Pos + 2]) && isxdigit(Str[Pos + 3])) {
+ char Hex[] = "0xAA";
+ Hex[2] = Str[Pos + 2];
+ Hex[3] = Str[Pos + 3];
+ U->push_back(strtol(Hex, nullptr, 16));
+ Pos += 3;
+ continue;
+ }
+ return false; // Invalid escape.
+ } else {
+ // Any other character.
+ U->push_back(V);
+ }
+ }
+ return true;
+}
+
+bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units) {
+ if (Text.empty()) {
+ Printf("ParseDictionaryFile: file does not exist or is empty\n");
+ return false;
+ }
+ std::istringstream ISS(Text);
+ Units->clear();
+ Unit U;
+ int LineNo = 0;
+ std::string S;
+ while (std::getline(ISS, S, '\n')) {
+ LineNo++;
+ size_t Pos = 0;
+ while (Pos < S.size() && isspace(S[Pos])) Pos++; // Skip spaces.
+ if (Pos == S.size()) continue; // Empty line.
+ if (S[Pos] == '#') continue; // Comment line.
+ if (ParseOneDictionaryEntry(S, &U)) {
+ Units->push_back(U);
+ } else {
+ Printf("ParseDictionaryFile: error in line %d\n\t\t%s\n", LineNo,
+ S.c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+int GetPid() { return getpid(); }
+
+
+std::string Base64(const Unit &U) {
+ static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+ std::string Res;
+ size_t i;
+ for (i = 0; i + 2 < U.size(); i += 3) {
+ uint32_t x = (U[i] << 16) + (U[i + 1] << 8) + U[i + 2];
+ Res += Table[(x >> 18) & 63];
+ Res += Table[(x >> 12) & 63];
+ Res += Table[(x >> 6) & 63];
+ Res += Table[x & 63];
+ }
+ if (i + 1 == U.size()) {
+ uint32_t x = (U[i] << 16);
+ Res += Table[(x >> 18) & 63];
+ Res += Table[(x >> 12) & 63];
+ Res += "==";
+ } else if (i + 2 == U.size()) {
+ uint32_t x = (U[i] << 16) + (U[i + 1] << 8);
+ Res += Table[(x >> 18) & 63];
+ Res += Table[(x >> 12) & 63];
+ Res += Table[(x >> 6) & 63];
+ Res += "=";
+ }
+ return Res;
+}
+
+} // namespace fuzzer
diff --git a/gnu/llvm/lib/Fuzzer/README.txt b/gnu/llvm/lib/Fuzzer/README.txt
new file mode 100644
index 00000000000..79f49b55090
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/README.txt
@@ -0,0 +1,2 @@
+Move to http://llvm.org/docs/LibFuzzer.html
+
diff --git a/gnu/llvm/lib/Fuzzer/cxx.dict b/gnu/llvm/lib/Fuzzer/cxx.dict
new file mode 100644
index 00000000000..41350f47558
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/cxx.dict
@@ -0,0 +1,122 @@
+"++"
+"--"
+"<<"
+">>"
+"+="
+"-="
+"*="
+"/="
+">>="
+"<<="
+"&="
+"|="
+"^="
+"%="
+"!="
+"&&"
+"||"
+"=="
+">="
+"<="
+"->"
+"alignas"
+"alignof"
+"and"
+"and_eq"
+"asm"
+"auto"
+"bitand"
+"bitor"
+"bool"
+"break"
+"case"
+"catch"
+"char"
+"char16_t"
+"char32_t"
+"class"
+"compl"
+"concept"
+"const"
+"constexpr"
+"const_cast"
+"continue"
+"decltype"
+"default"
+"delete"
+"do"
+"double"
+"dynamic_cast"
+"else"
+"enum"
+"explicit"
+"export"
+"extern"
+"false"
+"float"
+"for"
+"friend"
+"goto"
+"if"
+"inline"
+"int"
+"long"
+"mutable"
+"namespace"
+"new"
+"noexcept"
+"not"
+"not_eq"
+"nullptr"
+"operator"
+"or"
+"or_eq"
+"private"
+"protected"
+"public"
+"register"
+"reinterpret_cast"
+"requires"
+"return"
+"short"
+"signed"
+"sizeof"
+"static"
+"static_assert"
+"static_cast"
+"struct"
+"switch"
+"template"
+"this"
+"thread_local"
+"throw"
+"true"
+"try"
+"typedef"
+"typeid"
+"typename"
+"union"
+"unsigned"
+"using"
+"virtual"
+"void"
+"volatile"
+"wchar_t"
+"while"
+"xor"
+"xor_eq"
+"if"
+"elif"
+"else"
+"endif"
+"defined"
+"ifdef"
+"ifndef"
+"define"
+"undef"
+"include"
+"line"
+"error"
+"pragma"
+"override"
+"final"
diff --git a/gnu/llvm/lib/Fuzzer/pull_and_push_fuzz_corpus.sh b/gnu/llvm/lib/Fuzzer/pull_and_push_fuzz_corpus.sh
new file mode 100755
index 00000000000..05c322c6e5b
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/pull_and_push_fuzz_corpus.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# A simple script to synchronise a fuzz test corpus
+# with an external git repository.
+# Usage:
+# pull_and_push_fuzz_corpus.sh DIR
+# It assumes that DIR is inside a git repo and push
+# can be done w/o typing a password.
+cd $1
+git add *
+git commit -m "fuzz test corpus"
+git pull --rebase --no-edit
+for((attempt=0; attempt<5; attempt++)); do
+ echo GIT PUSH $1 ATTEMPT $attempt
+ if $(git push); then break; fi
+ git pull --rebase --no-edit
+done
+
diff --git a/gnu/llvm/lib/Fuzzer/test/CMakeLists.txt b/gnu/llvm/lib/Fuzzer/test/CMakeLists.txt
new file mode 100644
index 00000000000..cd0b167eb38
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/CMakeLists.txt
@@ -0,0 +1,118 @@
+# 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 "${LIBFUZZER_FLAGS_BASE} -O0 -fsanitize-coverage=edge,indirect-calls")
+
+set(DFSanTests
+ MemcmpTest
+ SimpleCmpTest
+ StrcmpTest
+ StrncmpTest
+ SwitchTest
+ )
+
+set(Tests
+ CallerCalleeTest
+ CounterTest
+ FourIndependentBranchesTest
+ FullCoverageSetTest
+ MemcmpTest
+ NullDerefTest
+ SimpleCmpTest
+ SimpleDictionaryTest
+ SimpleHashTest
+ SimpleTest
+ StrcmpTest
+ StrncmpTest
+ SwitchTest
+ ThreadedTest
+ TimeoutTest
+ )
+
+set(CustomMainTests
+ UserSuppliedFuzzerTest
+ )
+
+set(UninstrumentedTests
+ UninstrumentedTest
+ )
+
+set(TraceBBTests
+ SimpleTest
+ )
+
+set(TestBinaries)
+
+foreach(Test ${Tests})
+ add_executable(LLVMFuzzer-${Test}
+ ${Test}.cpp
+ )
+ target_link_libraries(LLVMFuzzer-${Test}
+ LLVMFuzzer
+ )
+ set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test})
+endforeach()
+
+foreach(Test ${CustomMainTests})
+ add_executable(LLVMFuzzer-${Test}
+ ${Test}.cpp
+ )
+ target_link_libraries(LLVMFuzzer-${Test}
+ LLVMFuzzerNoMain
+ )
+ 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:LLVMFuzzerNoMainObjects>
+ )
+
+target_link_libraries(LLVMFuzzer-Unittest
+ gtest
+ gtest_main
+ )
+
+set(TestBinaries ${TestBinaries} LLVMFuzzer-Unittest)
+
+add_subdirectory(dfsan)
+
+foreach(Test ${DFSanTests})
+ set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test}-DFSan)
+endforeach()
+
+add_subdirectory(uninstrumented)
+
+foreach(Test ${UninstrumentedTests})
+ set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test}-Uninstrumented)
+endforeach()
+
+add_subdirectory(trace-bb)
+
+foreach(Test ${TraceBBTests})
+ set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test}-TraceBB)
+endforeach()
+
+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/gnu/llvm/lib/Fuzzer/test/CallerCalleeTest.cpp b/gnu/llvm/lib/Fuzzer/test/CallerCalleeTest.cpp
new file mode 100644
index 00000000000..150b2fc0405
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/CallerCalleeTest.cpp
@@ -0,0 +1,56 @@
+// Simple test for a fuzzer.
+// Try to find the target using the indirect caller-callee pairs.
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <cstring>
+#include <iostream>
+
+typedef void (*F)();
+static F t[256];
+
+void f34() {
+ std::cerr << "BINGO\n";
+ exit(1);
+}
+void f23() { t[(unsigned)'d'] = f34;}
+void f12() { t[(unsigned)'c'] = f23;}
+void f01() { t[(unsigned)'b'] = f12;}
+void f00() {}
+
+static F t0[256] = {
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+ f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00,
+};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ if (Size < 4) return 0;
+ // Spoof the counters.
+ for (int i = 0; i < 200; i++) {
+ f23();
+ f12();
+ f01();
+ }
+ memcpy(t, t0, sizeof(t));
+ t[(unsigned)'a'] = f01;
+ t[Data[0]]();
+ t[Data[1]]();
+ t[Data[2]]();
+ t[Data[3]]();
+ return 0;
+}
+
diff --git a/gnu/llvm/lib/Fuzzer/test/CounterTest.cpp b/gnu/llvm/lib/Fuzzer/test/CounterTest.cpp
new file mode 100644
index 00000000000..b61f419c499
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/CounterTest.cpp
@@ -0,0 +1,15 @@
+// Test for a fuzzer: must find the case where a particular basic block is
+// executed many times.
+#include <iostream>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ int Num = 0;
+ for (size_t i = 0; i < Size; i++)
+ if (Data[i] == 'A' + i)
+ Num++;
+ if (Num >= 4) {
+ std::cerr << "BINGO!\n";
+ exit(1);
+ }
+ return 0;
+}
diff --git a/gnu/llvm/lib/Fuzzer/test/FourIndependentBranchesTest.cpp b/gnu/llvm/lib/Fuzzer/test/FourIndependentBranchesTest.cpp
new file mode 100644
index 00000000000..6007dd4a027
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/FourIndependentBranchesTest.cpp
@@ -0,0 +1,19 @@
+// Simple test for a fuzzer. The fuzzer must find the string "FUZZ".
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <iostream>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ int bits = 0;
+ if (Size > 0 && Data[0] == 'F') bits |= 1;
+ if (Size > 1 && Data[1] == 'U') bits |= 2;
+ if (Size > 2 && Data[2] == 'Z') bits |= 4;
+ if (Size > 3 && Data[3] == 'Z') bits |= 8;
+ if (bits == 15) {
+ std::cerr << "BINGO!\n";
+ exit(1);
+ }
+ return 0;
+}
+
diff --git a/gnu/llvm/lib/Fuzzer/test/FullCoverageSetTest.cpp b/gnu/llvm/lib/Fuzzer/test/FullCoverageSetTest.cpp
new file mode 100644
index 00000000000..a868084a0ce
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/FullCoverageSetTest.cpp
@@ -0,0 +1,21 @@
+// Simple test for a fuzzer. The fuzzer must find the string "FUZZER".
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <iostream>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ int bits = 0;
+ if (Size > 0 && Data[0] == 'F') bits |= 1;
+ if (Size > 1 && Data[1] == 'U') bits |= 2;
+ if (Size > 2 && Data[2] == 'Z') bits |= 4;
+ if (Size > 3 && Data[3] == 'Z') bits |= 8;
+ if (Size > 4 && Data[4] == 'E') bits |= 16;
+ if (Size > 5 && Data[5] == 'R') bits |= 32;
+ if (bits == 63) {
+ std::cerr << "BINGO!\n";
+ exit(1);
+ }
+ return 0;
+}
+
diff --git a/gnu/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp b/gnu/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp
new file mode 100644
index 00000000000..b33e0c96145
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp
@@ -0,0 +1,402 @@
+#include "FuzzerInternal.h"
+#include "gtest/gtest.h"
+#include <set>
+
+using namespace fuzzer;
+
+// For now, have LLVMFuzzerTestOneInput just to make it link.
+// Later we may want to make unittests that actually call LLVMFuzzerTestOneInput.
+extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ abort();
+}
+
+TEST(Fuzzer, CrossOver) {
+ FuzzerRandomLibc Rand(0);
+ MutationDispatcher MD(Rand);
+ Unit A({0, 1, 2}), B({5, 6, 7});
+ Unit C;
+ Unit Expected[] = {
+ { 0 },
+ { 0, 1 },
+ { 0, 5 },
+ { 0, 1, 2 },
+ { 0, 1, 5 },
+ { 0, 5, 1 },
+ { 0, 5, 6 },
+ { 0, 1, 2, 5 },
+ { 0, 1, 5, 2 },
+ { 0, 1, 5, 6 },
+ { 0, 5, 1, 2 },
+ { 0, 5, 1, 6 },
+ { 0, 5, 6, 1 },
+ { 0, 5, 6, 7 },
+ { 0, 1, 2, 5, 6 },
+ { 0, 1, 5, 2, 6 },
+ { 0, 1, 5, 6, 2 },
+ { 0, 1, 5, 6, 7 },
+ { 0, 5, 1, 2, 6 },
+ { 0, 5, 1, 6, 2 },
+ { 0, 5, 1, 6, 7 },
+ { 0, 5, 6, 1, 2 },
+ { 0, 5, 6, 1, 7 },
+ { 0, 5, 6, 7, 1 },
+ { 0, 1, 2, 5, 6, 7 },
+ { 0, 1, 5, 2, 6, 7 },
+ { 0, 1, 5, 6, 2, 7 },
+ { 0, 1, 5, 6, 7, 2 },
+ { 0, 5, 1, 2, 6, 7 },
+ { 0, 5, 1, 6, 2, 7 },
+ { 0, 5, 1, 6, 7, 2 },
+ { 0, 5, 6, 1, 2, 7 },
+ { 0, 5, 6, 1, 7, 2 },
+ { 0, 5, 6, 7, 1, 2 }
+ };
+ for (size_t Len = 1; Len < 8; Len++) {
+ std::set<Unit> FoundUnits, ExpectedUnitsWitThisLength;
+ for (int Iter = 0; Iter < 3000; Iter++) {
+ C.resize(Len);
+ size_t NewSize = MD.CrossOver(A.data(), A.size(), B.data(), B.size(),
+ C.data(), C.size());
+ C.resize(NewSize);
+ FoundUnits.insert(C);
+ }
+ for (const Unit &U : Expected)
+ if (U.size() <= Len)
+ ExpectedUnitsWitThisLength.insert(U);
+ EXPECT_EQ(ExpectedUnitsWitThisLength, FoundUnits);
+ }
+}
+
+TEST(Fuzzer, Hash) {
+ uint8_t A[] = {'a', 'b', 'c'};
+ fuzzer::Unit U(A, A + sizeof(A));
+ EXPECT_EQ("a9993e364706816aba3e25717850c26c9cd0d89d", fuzzer::Hash(U));
+ U.push_back('d');
+ EXPECT_EQ("81fe8bfe87576c3ecb22426f8e57847382917acf", fuzzer::Hash(U));
+}
+
+typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size,
+ size_t MaxSize);
+
+void TestEraseByte(Mutator M, int NumIter) {
+ uint8_t REM0[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t REM1[8] = {0x00, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t REM2[8] = {0x00, 0x11, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t REM3[8] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x77};
+ uint8_t REM4[8] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x66, 0x77};
+ uint8_t REM5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x66, 0x77};
+ uint8_t REM6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x77};
+ uint8_t REM7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+ FuzzerRandomLibc Rand(0);
+ MutationDispatcher MD(Rand);
+ int FoundMask = 0;
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ size_t NewSize = (MD.*M)(T, sizeof(T), sizeof(T));
+ if (NewSize == 7 && !memcmp(REM0, T, 7)) FoundMask |= 1 << 0;
+ if (NewSize == 7 && !memcmp(REM1, T, 7)) FoundMask |= 1 << 1;
+ if (NewSize == 7 && !memcmp(REM2, T, 7)) FoundMask |= 1 << 2;
+ if (NewSize == 7 && !memcmp(REM3, T, 7)) FoundMask |= 1 << 3;
+ if (NewSize == 7 && !memcmp(REM4, T, 7)) FoundMask |= 1 << 4;
+ if (NewSize == 7 && !memcmp(REM5, T, 7)) FoundMask |= 1 << 5;
+ if (NewSize == 7 && !memcmp(REM6, T, 7)) FoundMask |= 1 << 6;
+ if (NewSize == 7 && !memcmp(REM7, T, 7)) FoundMask |= 1 << 7;
+ }
+ EXPECT_EQ(FoundMask, 255);
+}
+
+TEST(FuzzerMutate, EraseByte1) {
+ TestEraseByte(&MutationDispatcher::Mutate_EraseByte, 100);
+}
+TEST(FuzzerMutate, EraseByte2) {
+ TestEraseByte(&MutationDispatcher::Mutate, 1000);
+}
+
+void TestInsertByte(Mutator M, int NumIter) {
+ FuzzerRandomLibc Rand(0);
+ MutationDispatcher MD(Rand);
+ int FoundMask = 0;
+ uint8_t INS0[8] = {0xF1, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+ uint8_t INS1[8] = {0x00, 0xF2, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+ uint8_t INS2[8] = {0x00, 0x11, 0xF3, 0x22, 0x33, 0x44, 0x55, 0x66};
+ uint8_t INS3[8] = {0x00, 0x11, 0x22, 0xF4, 0x33, 0x44, 0x55, 0x66};
+ uint8_t INS4[8] = {0x00, 0x11, 0x22, 0x33, 0xF5, 0x44, 0x55, 0x66};
+ uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF6, 0x55, 0x66};
+ uint8_t INS6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF7, 0x66};
+ uint8_t INS7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF8};
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+ size_t NewSize = (MD.*M)(T, 7, 8);
+ if (NewSize == 8 && !memcmp(INS0, T, 8)) FoundMask |= 1 << 0;
+ if (NewSize == 8 && !memcmp(INS1, T, 8)) FoundMask |= 1 << 1;
+ if (NewSize == 8 && !memcmp(INS2, T, 8)) FoundMask |= 1 << 2;
+ if (NewSize == 8 && !memcmp(INS3, T, 8)) FoundMask |= 1 << 3;
+ if (NewSize == 8 && !memcmp(INS4, T, 8)) FoundMask |= 1 << 4;
+ if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5;
+ if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6;
+ if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7;
+ }
+ EXPECT_EQ(FoundMask, 255);
+}
+
+TEST(FuzzerMutate, InsertByte1) {
+ TestInsertByte(&MutationDispatcher::Mutate_InsertByte, 1 << 15);
+}
+TEST(FuzzerMutate, InsertByte2) {
+ TestInsertByte(&MutationDispatcher::Mutate, 1 << 17);
+}
+
+void TestChangeByte(Mutator M, int NumIter) {
+ FuzzerRandomLibc Rand(0);
+ MutationDispatcher MD(Rand);
+ int FoundMask = 0;
+ uint8_t CH0[8] = {0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH1[8] = {0x00, 0xF1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH2[8] = {0x00, 0x11, 0xF2, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH3[8] = {0x00, 0x11, 0x22, 0xF3, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0xF4, 0x55, 0x66, 0x77};
+ uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF5, 0x66, 0x77};
+ uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF5, 0x77};
+ uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7};
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ size_t NewSize = (MD.*M)(T, 8, 9);
+ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
+ if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
+ if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
+ if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
+ if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4;
+ if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
+ if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
+ if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
+ }
+ EXPECT_EQ(FoundMask, 255);
+}
+
+TEST(FuzzerMutate, ChangeByte1) {
+ TestChangeByte(&MutationDispatcher::Mutate_ChangeByte, 1 << 15);
+}
+TEST(FuzzerMutate, ChangeByte2) {
+ TestChangeByte(&MutationDispatcher::Mutate, 1 << 17);
+}
+
+void TestChangeBit(Mutator M, int NumIter) {
+ FuzzerRandomLibc Rand(0);
+ MutationDispatcher MD(Rand);
+ int FoundMask = 0;
+ uint8_t CH0[8] = {0x01, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH1[8] = {0x00, 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH2[8] = {0x00, 0x11, 0x02, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH3[8] = {0x00, 0x11, 0x22, 0x37, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x54, 0x55, 0x66, 0x77};
+ uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x54, 0x66, 0x77};
+ uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x76, 0x77};
+ uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7};
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ size_t NewSize = (MD.*M)(T, 8, 9);
+ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
+ if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
+ if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
+ if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
+ if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4;
+ if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
+ if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
+ if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
+ }
+ EXPECT_EQ(FoundMask, 255);
+}
+
+TEST(FuzzerMutate, ChangeBit1) {
+ TestChangeBit(&MutationDispatcher::Mutate_ChangeBit, 1 << 16);
+}
+TEST(FuzzerMutate, ChangeBit2) {
+ TestChangeBit(&MutationDispatcher::Mutate, 1 << 18);
+}
+
+void TestShuffleBytes(Mutator M, int NumIter) {
+ FuzzerRandomLibc Rand(0);
+ MutationDispatcher MD(Rand);
+ int FoundMask = 0;
+ uint8_t CH0[7] = {0x00, 0x22, 0x11, 0x33, 0x44, 0x55, 0x66};
+ uint8_t CH1[7] = {0x11, 0x00, 0x33, 0x22, 0x44, 0x55, 0x66};
+ uint8_t CH2[7] = {0x00, 0x33, 0x11, 0x22, 0x44, 0x55, 0x66};
+ uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x33};
+ uint8_t CH4[7] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x44, 0x66};
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+ size_t NewSize = (MD.*M)(T, 7, 7);
+ if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0;
+ if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1;
+ if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2;
+ if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3;
+ if (NewSize == 7 && !memcmp(CH4, T, 7)) FoundMask |= 1 << 4;
+ }
+ EXPECT_EQ(FoundMask, 31);
+}
+
+TEST(FuzzerMutate, ShuffleBytes1) {
+ TestShuffleBytes(&MutationDispatcher::Mutate_ShuffleBytes, 1 << 15);
+}
+TEST(FuzzerMutate, ShuffleBytes2) {
+ TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 19);
+}
+
+void TestAddWordFromDictionary(Mutator M, int NumIter) {
+ FuzzerRandomLibc Rand(0);
+ MutationDispatcher MD(Rand);
+ uint8_t Word1[4] = {0xAA, 0xBB, 0xCC, 0xDD};
+ uint8_t Word2[3] = {0xFF, 0xEE, 0xEF};
+ MD.AddWordToManualDictionary(Unit(Word1, Word1 + sizeof(Word1)));
+ MD.AddWordToManualDictionary(Unit(Word2, Word2 + sizeof(Word2)));
+ int FoundMask = 0;
+ uint8_t CH0[7] = {0x00, 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD};
+ uint8_t CH1[7] = {0x00, 0x11, 0xAA, 0xBB, 0xCC, 0xDD, 0x22};
+ uint8_t CH2[7] = {0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22};
+ uint8_t CH3[7] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x11, 0x22};
+ uint8_t CH4[6] = {0x00, 0x11, 0x22, 0xFF, 0xEE, 0xEF};
+ uint8_t CH5[6] = {0x00, 0x11, 0xFF, 0xEE, 0xEF, 0x22};
+ uint8_t CH6[6] = {0x00, 0xFF, 0xEE, 0xEF, 0x11, 0x22};
+ uint8_t CH7[6] = {0xFF, 0xEE, 0xEF, 0x00, 0x11, 0x22};
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[7] = {0x00, 0x11, 0x22};
+ size_t NewSize = (MD.*M)(T, 3, 7);
+ if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0;
+ if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1;
+ if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2;
+ if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3;
+ if (NewSize == 6 && !memcmp(CH4, T, 6)) FoundMask |= 1 << 4;
+ if (NewSize == 6 && !memcmp(CH5, T, 6)) FoundMask |= 1 << 5;
+ if (NewSize == 6 && !memcmp(CH6, T, 6)) FoundMask |= 1 << 6;
+ if (NewSize == 6 && !memcmp(CH7, T, 6)) FoundMask |= 1 << 7;
+ }
+ EXPECT_EQ(FoundMask, 255);
+}
+
+TEST(FuzzerMutate, AddWordFromDictionary1) {
+ TestAddWordFromDictionary(
+ &MutationDispatcher::Mutate_AddWordFromManualDictionary, 1 << 15);
+}
+
+TEST(FuzzerMutate, AddWordFromDictionary2) {
+ TestAddWordFromDictionary(&MutationDispatcher::Mutate, 1 << 15);
+}
+
+void TestAddWordFromDictionaryWithHint(Mutator M, int NumIter) {
+ FuzzerRandomLibc Rand(0);
+ MutationDispatcher MD(Rand);
+ uint8_t Word[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xFF, 0xEE, 0xEF};
+ size_t PosHint = 7777;
+ MD.AddWordToAutoDictionary(Unit(Word, Word + sizeof(Word)), PosHint);
+ int FoundMask = 0;
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[10000];
+ memset(T, 0, sizeof(T));
+ size_t NewSize = (MD.*M)(T, 9000, 10000);
+ if (NewSize >= PosHint + sizeof(Word) &&
+ !memcmp(Word, T + PosHint, sizeof(Word)))
+ FoundMask = 1;
+ }
+ EXPECT_EQ(FoundMask, 1);
+}
+
+TEST(FuzzerMutate, AddWordFromDictionaryWithHint1) {
+ TestAddWordFromDictionaryWithHint(
+ &MutationDispatcher::Mutate_AddWordFromAutoDictionary, 1 << 5);
+}
+
+TEST(FuzzerMutate, AddWordFromDictionaryWithHint2) {
+ TestAddWordFromDictionaryWithHint(&MutationDispatcher::Mutate, 1 << 10);
+}
+
+void TestChangeASCIIInteger(Mutator M, int NumIter) {
+ FuzzerRandomLibc Rand(0);
+ MutationDispatcher MD(Rand);
+
+ uint8_t CH0[8] = {'1', '2', '3', '4', '5', '6', '7', '7'};
+ uint8_t CH1[8] = {'1', '2', '3', '4', '5', '6', '7', '9'};
+ uint8_t CH2[8] = {'2', '4', '6', '9', '1', '3', '5', '6'};
+ uint8_t CH3[8] = {'0', '6', '1', '7', '2', '8', '3', '9'};
+ int FoundMask = 0;
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};
+ size_t NewSize = (MD.*M)(T, 8, 8);
+ /**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
+ else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
+ else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
+ else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
+ else if (NewSize == 8) FoundMask |= 1 << 4;
+ }
+ EXPECT_EQ(FoundMask, 31);
+}
+
+TEST(FuzzerMutate, ChangeASCIIInteger1) {
+ TestChangeASCIIInteger(&MutationDispatcher::Mutate_ChangeASCIIInteger,
+ 1 << 15);
+}
+
+TEST(FuzzerMutate, ChangeASCIIInteger2) {
+ TestChangeASCIIInteger(&MutationDispatcher::Mutate, 1 << 15);
+}
+
+
+TEST(FuzzerDictionary, ParseOneDictionaryEntry) {
+ Unit U;
+ EXPECT_FALSE(ParseOneDictionaryEntry("", &U));
+ EXPECT_FALSE(ParseOneDictionaryEntry(" ", &U));
+ EXPECT_FALSE(ParseOneDictionaryEntry("\t ", &U));
+ EXPECT_FALSE(ParseOneDictionaryEntry(" \" ", &U));
+ EXPECT_FALSE(ParseOneDictionaryEntry(" zz\" ", &U));
+ EXPECT_FALSE(ParseOneDictionaryEntry(" \"zz ", &U));
+ EXPECT_FALSE(ParseOneDictionaryEntry(" \"\" ", &U));
+ EXPECT_TRUE(ParseOneDictionaryEntry("\"a\"", &U));
+ EXPECT_EQ(U, Unit({'a'}));
+ EXPECT_TRUE(ParseOneDictionaryEntry("\"abc\"", &U));
+ EXPECT_EQ(U, Unit({'a', 'b', 'c'}));
+ EXPECT_TRUE(ParseOneDictionaryEntry("abc=\"abc\"", &U));
+ EXPECT_EQ(U, Unit({'a', 'b', 'c'}));
+ EXPECT_FALSE(ParseOneDictionaryEntry("\"\\\"", &U));
+ EXPECT_TRUE(ParseOneDictionaryEntry("\"\\\\\"", &U));
+ EXPECT_EQ(U, Unit({'\\'}));
+ EXPECT_TRUE(ParseOneDictionaryEntry("\"\\xAB\"", &U));
+ EXPECT_EQ(U, Unit({0xAB}));
+ EXPECT_TRUE(ParseOneDictionaryEntry("\"\\xABz\\xDE\"", &U));
+ EXPECT_EQ(U, Unit({0xAB, 'z', 0xDE}));
+ EXPECT_TRUE(ParseOneDictionaryEntry("\"#\"", &U));
+ EXPECT_EQ(U, Unit({'#'}));
+ EXPECT_TRUE(ParseOneDictionaryEntry("\"\\\"\"", &U));
+ EXPECT_EQ(U, Unit({'"'}));
+}
+
+TEST(FuzzerDictionary, ParseDictionaryFile) {
+ std::vector<Unit> Units;
+ EXPECT_FALSE(ParseDictionaryFile("zzz\n", &Units));
+ EXPECT_FALSE(ParseDictionaryFile("", &Units));
+ EXPECT_TRUE(ParseDictionaryFile("\n", &Units));
+ EXPECT_EQ(Units.size(), 0U);
+ EXPECT_TRUE(ParseDictionaryFile("#zzzz a b c d\n", &Units));
+ EXPECT_EQ(Units.size(), 0U);
+ EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units));
+ EXPECT_EQ(Units.size(), 0U);
+ EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units));
+ EXPECT_EQ(Units.size(), 0U);
+ EXPECT_TRUE(ParseDictionaryFile(" #zzzz\naaa=\"aa\"", &Units));
+ EXPECT_EQ(Units, std::vector<Unit>({Unit({'a', 'a'})}));
+ EXPECT_TRUE(
+ ParseDictionaryFile(" #zzzz\naaa=\"aa\"\n\nabc=\"abc\"", &Units));
+ EXPECT_EQ(Units,
+ std::vector<Unit>({Unit({'a', 'a'}), Unit({'a', 'b', 'c'})}));
+}
+
+TEST(FuzzerUtil, Base64) {
+ EXPECT_EQ("", Base64({}));
+ EXPECT_EQ("YQ==", Base64({'a'}));
+ EXPECT_EQ("eA==", Base64({'x'}));
+ EXPECT_EQ("YWI=", Base64({'a', 'b'}));
+ EXPECT_EQ("eHk=", Base64({'x', 'y'}));
+ EXPECT_EQ("YWJj", Base64({'a', 'b', 'c'}));
+ EXPECT_EQ("eHl6", Base64({'x', 'y', 'z'}));
+ EXPECT_EQ("YWJjeA==", Base64({'a', 'b', 'c', 'x'}));
+ EXPECT_EQ("YWJjeHk=", Base64({'a', 'b', 'c', 'x', 'y'}));
+ EXPECT_EQ("YWJjeHl6", Base64({'a', 'b', 'c', 'x', 'y', 'z'}));
+}
diff --git a/gnu/llvm/lib/Fuzzer/test/MemcmpTest.cpp b/gnu/llvm/lib/Fuzzer/test/MemcmpTest.cpp
new file mode 100644
index 00000000000..c19c95717bb
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/MemcmpTest.cpp
@@ -0,0 +1,28 @@
+// Simple test for a fuzzer. The fuzzer must find a particular string.
+#include <cstring>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ // TODO: check other sizes.
+ if (Size >= 8 && memcmp(Data, "01234567", 8) == 0) {
+ if (Size >= 12 && memcmp(Data + 8, "ABCD", 4) == 0) {
+ if (Size >= 14 && memcmp(Data + 12, "XY", 2) == 0) {
+ if (Size >= 16 && memcmp(Data + 14, "KLM", 3) == 0) {
+ if (Size >= 27 && memcmp(Data + 17, "ABCDE-GHIJ", 10) == 0){
+ fprintf(stderr, "BINGO %zd\n", Size);
+ for (size_t i = 0; i < Size; i++) {
+ uint8_t C = Data[i];
+ if (C >= 32 && C < 127)
+ fprintf(stderr, "%c", C);
+ }
+ fprintf(stderr, "\n");
+ exit(1);
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
diff --git a/gnu/llvm/lib/Fuzzer/test/NullDerefTest.cpp b/gnu/llvm/lib/Fuzzer/test/NullDerefTest.cpp
new file mode 100644
index 00000000000..200c56ccbbc
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/NullDerefTest.cpp
@@ -0,0 +1,23 @@
+// 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" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ if (Size > 0 && Data[0] == 'H') {
+ Sink = 1;
+ if (Size > 1 && Data[1] == 'i') {
+ Sink = 2;
+ if (Size > 2 && Data[2] == '!') {
+ std::cout << "Found the target, dereferencing NULL\n";
+ *Null = 1;
+ }
+ }
+ }
+ return 0;
+}
+
diff --git a/gnu/llvm/lib/Fuzzer/test/SimpleCmpTest.cpp b/gnu/llvm/lib/Fuzzer/test/SimpleCmpTest.cpp
new file mode 100644
index 00000000000..8568c737efb
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/SimpleCmpTest.cpp
@@ -0,0 +1,31 @@
+// Simple test for a fuzzer. The fuzzer must find several narrow ranges.
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <cstdio>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ if (Size < 14) return 0;
+ uint64_t x = 0;
+ int64_t y = 0;
+ int z = 0;
+ unsigned short a = 0;
+ memcpy(&x, Data, 8);
+ memcpy(&y, Data + Size - 8, 8);
+ memcpy(&z, Data + Size / 2, sizeof(z));
+ memcpy(&a, Data + Size / 2 + 4, sizeof(a));
+
+ if (x > 1234567890 &&
+ x < 1234567895 &&
+ y >= 987654321 &&
+ y <= 987654325 &&
+ z < -10000 &&
+ z >= -10005 &&
+ z != -10003 &&
+ a == 4242) {
+ fprintf(stderr, "BINGO; Found the target: size %zd (%zd, %zd, %d, %d), exiting.\n",
+ Size, x, y, z, a);
+ exit(1);
+ }
+ return 0;
+}
diff --git a/gnu/llvm/lib/Fuzzer/test/SimpleDictionaryTest.cpp b/gnu/llvm/lib/Fuzzer/test/SimpleDictionaryTest.cpp
new file mode 100644
index 00000000000..b9cb2f0270a
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/SimpleDictionaryTest.cpp
@@ -0,0 +1,26 @@
+// Simple test for a fuzzer.
+// The fuzzer must find a string based on dictionary words:
+// "Elvis"
+// "Presley"
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <cstring>
+#include <iostream>
+
+static volatile int Zero = 0;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ const char *Expected = "ElvisPresley";
+ if (Size < strlen(Expected)) return 0;
+ size_t Match = 0;
+ for (size_t i = 0; Expected[i]; i++)
+ if (Expected[i] + Zero == Data[i])
+ Match++;
+ if (Match == strlen(Expected)) {
+ std::cout << "BINGO; Found the target, exiting\n";
+ exit(1);
+ }
+ return 0;
+}
+
diff --git a/gnu/llvm/lib/Fuzzer/test/SimpleHashTest.cpp b/gnu/llvm/lib/Fuzzer/test/SimpleHashTest.cpp
new file mode 100644
index 00000000000..5bab3fa7f64
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/SimpleHashTest.cpp
@@ -0,0 +1,37 @@
+// This test computes a checksum of the data (all but the last 4 bytes),
+// and then compares the last 4 bytes with the computed value.
+// A fuzzer with cmp traces is expected to defeat this check.
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <cstdio>
+
+// A modified jenkins_one_at_a_time_hash initialized by non-zero,
+// so that simple_hash(0) != 0. See also
+// https://en.wikipedia.org/wiki/Jenkins_hash_function
+static uint32_t simple_hash(const uint8_t *Data, size_t Size) {
+ uint32_t Hash = 0x12039854;
+ for (uint32_t i = 0; i < Size; i++) {
+ Hash += Data[i];
+ Hash += (Hash << 10);
+ Hash ^= (Hash >> 6);
+ }
+ Hash += (Hash << 3);
+ Hash ^= (Hash >> 11);
+ Hash += (Hash << 15);
+ return Hash;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ if (Size < 14)
+ return 0;
+
+ uint32_t Hash = simple_hash(&Data[0], Size - 4);
+ uint32_t Want = reinterpret_cast<const uint32_t *>(&Data[Size - 4])[0];
+ if (Hash != Want)
+ return 0;
+ fprintf(stderr, "BINGO; simple_hash defeated: %x == %x\n", (unsigned int)Hash,
+ (unsigned int)Want);
+ exit(1);
+ return 0;
+}
diff --git a/gnu/llvm/lib/Fuzzer/test/SimpleTest.cpp b/gnu/llvm/lib/Fuzzer/test/SimpleTest.cpp
new file mode 100644
index 00000000000..04225a889f5
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/SimpleTest.cpp
@@ -0,0 +1,24 @@
+// Simple test for a fuzzer. The fuzzer must find the string "Hi!".
+#include <assert.h>
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <iostream>
+
+static volatile int Sink;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ assert(Data);
+ if (Size > 0 && Data[0] == 'H') {
+ Sink = 1;
+ if (Size > 1 && Data[1] == 'i') {
+ Sink = 2;
+ if (Size > 2 && Data[2] == '!') {
+ std::cout << "BINGO; Found the target, exiting\n";
+ exit(0);
+ }
+ }
+ }
+ return 0;
+}
+
diff --git a/gnu/llvm/lib/Fuzzer/test/StrcmpTest.cpp b/gnu/llvm/lib/Fuzzer/test/StrcmpTest.cpp
new file mode 100644
index 00000000000..835819ae2f4
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/StrcmpTest.cpp
@@ -0,0 +1,29 @@
+// Break through a series of strcmp.
+#include <cstring>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cassert>
+
+bool Eq(const uint8_t *Data, size_t Size, const char *Str) {
+ char Buff[1024];
+ size_t Len = strlen(Str);
+ if (Size < Len) return false;
+ if (Len >= sizeof(Buff)) return false;
+ memcpy(Buff, (char*)Data, Len);
+ Buff[Len] = 0;
+ int res = strcmp(Buff, Str);
+ return res == 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ if (Eq(Data, Size, "AAA") &&
+ Size >= 3 && Eq(Data + 3, Size - 3, "BBBB") &&
+ Size >= 7 && Eq(Data + 7, Size - 7, "CCCCCC") &&
+ Size >= 14 && Data[13] == 42
+ ) {
+ fprintf(stderr, "BINGO\n");
+ exit(1);
+ }
+ return 0;
+}
diff --git a/gnu/llvm/lib/Fuzzer/test/StrncmpTest.cpp b/gnu/llvm/lib/Fuzzer/test/StrncmpTest.cpp
new file mode 100644
index 00000000000..55344d75e0b
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/StrncmpTest.cpp
@@ -0,0 +1,25 @@
+// Simple test for a fuzzer. The fuzzer must find a particular string.
+#include <cstring>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+
+static volatile int sink;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ // TODO: check other sizes.
+ char *S = (char*)Data;
+ if (Size >= 8 && strncmp(S, "123", 8))
+ sink = 1;
+ if (Size >= 8 && strncmp(S, "01234567", 8) == 0) {
+ if (Size >= 12 && strncmp(S + 8, "ABCD", 4) == 0) {
+ if (Size >= 14 && strncmp(S + 12, "XY", 2) == 0) {
+ if (Size >= 16 && strncmp(S + 14, "KLM", 3) == 0) {
+ fprintf(stderr, "BINGO\n");
+ exit(1);
+ }
+ }
+ }
+ }
+ return 0;
+}
diff --git a/gnu/llvm/lib/Fuzzer/test/SwitchTest.cpp b/gnu/llvm/lib/Fuzzer/test/SwitchTest.cpp
new file mode 100644
index 00000000000..5de7fff7452
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/SwitchTest.cpp
@@ -0,0 +1,55 @@
+// Simple test for a fuzzer. The fuzzer must find the interesting switch value.
+#include <cstdint>
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+#include <cstddef>
+
+static volatile int Sink;
+
+template<class T>
+bool Switch(const uint8_t *Data, size_t Size) {
+ T X;
+ if (Size < sizeof(X)) return false;
+ memcpy(&X, Data, sizeof(X));
+ switch (X) {
+ case 1: Sink = __LINE__; break;
+ case 101: Sink = __LINE__; break;
+ case 1001: Sink = __LINE__; break;
+ case 10001: Sink = __LINE__; break;
+ case 100001: Sink = __LINE__; break;
+ case 1000001: Sink = __LINE__; break;
+ case 10000001: Sink = __LINE__; break;
+ case 100000001: return true;
+ }
+ return false;
+}
+
+bool ShortSwitch(const uint8_t *Data, size_t Size) {
+ short X;
+ if (Size < sizeof(short)) return false;
+ memcpy(&X, Data, sizeof(short));
+ switch(X) {
+ case 42: Sink = __LINE__; break;
+ case 402: Sink = __LINE__; break;
+ case 4002: Sink = __LINE__; break;
+ case 5002: Sink = __LINE__; break;
+ case 7002: Sink = __LINE__; break;
+ case 9002: Sink = __LINE__; break;
+ case 14002: Sink = __LINE__; break;
+ case 21402: return true;
+ }
+ return false;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ if (Size >= 4 && Switch<int>(Data, Size) &&
+ Size >= 12 && Switch<uint64_t>(Data + 4, Size - 4) &&
+ Size >= 14 && ShortSwitch(Data + 12, 2)
+ ) {
+ fprintf(stderr, "BINGO; Found the target, exiting\n");
+ exit(1);
+ }
+ return 0;
+}
+
diff --git a/gnu/llvm/lib/Fuzzer/test/ThreadedTest.cpp b/gnu/llvm/lib/Fuzzer/test/ThreadedTest.cpp
new file mode 100644
index 00000000000..7aa114a41f3
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/ThreadedTest.cpp
@@ -0,0 +1,23 @@
+// Threaded test for a fuzzer. The fuzzer should not crash.
+#include <assert.h>
+#include <cstdint>
+#include <cstddef>
+#include <cstring>
+#include <thread>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ if (Size < 8) return 0;
+ assert(Data);
+ auto C = [&] {
+ size_t Res = 0;
+ for (size_t i = 0; i < Size / 2; i++)
+ Res += memcmp(Data, Data + Size / 2, 4);
+ return Res;
+ };
+ std::thread T[] = {std::thread(C), std::thread(C), std::thread(C),
+ std::thread(C), std::thread(C), std::thread(C)};
+ for (auto &X : T)
+ X.join();
+ return 0;
+}
+
diff --git a/gnu/llvm/lib/Fuzzer/test/TimeoutTest.cpp b/gnu/llvm/lib/Fuzzer/test/TimeoutTest.cpp
new file mode 100644
index 00000000000..71790ded95a
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/TimeoutTest.cpp
@@ -0,0 +1,23 @@
+// 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" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ if (Size > 0 && Data[0] == 'H') {
+ Sink = 1;
+ if (Size > 1 && Data[1] == 'i') {
+ Sink = 2;
+ if (Size > 2 && Data[2] == '!') {
+ Sink = 2;
+ while (Sink)
+ ;
+ }
+ }
+ }
+ return 0;
+}
+
diff --git a/gnu/llvm/lib/Fuzzer/test/UninstrumentedTest.cpp b/gnu/llvm/lib/Fuzzer/test/UninstrumentedTest.cpp
new file mode 100644
index 00000000000..c1730198d83
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/UninstrumentedTest.cpp
@@ -0,0 +1,8 @@
+// This test should not be instrumented.
+#include <cstdint>
+#include <cstddef>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ return 0;
+}
+
diff --git a/gnu/llvm/lib/Fuzzer/test/UserSuppliedFuzzerTest.cpp b/gnu/llvm/lib/Fuzzer/test/UserSuppliedFuzzerTest.cpp
new file mode 100644
index 00000000000..59f83b57bfa
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/UserSuppliedFuzzerTest.cpp
@@ -0,0 +1,51 @@
+// Simple test for a fuzzer.
+// The fuzzer must find the string "Hi!" preceded by a magic value.
+// Uses UserSuppliedFuzzer which ensures that the magic is present.
+#include <cstdint>
+#include <cassert>
+#include <cstdlib>
+#include <cstddef>
+#include <cstring>
+#include <iostream>
+
+#include "FuzzerInterface.h"
+
+static const uint64_t kMagic = 8860221463604ULL;
+
+class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
+ public:
+ MyFuzzer(fuzzer::FuzzerRandomBase *Rand)
+ : fuzzer::UserSuppliedFuzzer(Rand) {}
+ int TargetFunction(const uint8_t *Data, size_t Size) {
+ if (Size <= 10) return 0;
+ if (memcmp(Data, &kMagic, sizeof(kMagic))) return 0;
+ // It's hard to get here w/o advanced fuzzing techniques (e.g. cmp tracing).
+ // So, we simply 'fix' the data in the custom mutator.
+ if (Data[8] == 'H') {
+ if (Data[9] == 'i') {
+ if (Data[10] == '!') {
+ std::cout << "BINGO; Found the target, exiting\n";
+ exit(1);
+ }
+ }
+ }
+ return 0;
+ }
+ // Custom mutator.
+ virtual size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+ assert(MaxSize > sizeof(kMagic));
+ if (Size < sizeof(kMagic))
+ Size = sizeof(kMagic);
+ // "Fix" the data, then mutate.
+ memcpy(Data, &kMagic, std::min(MaxSize, sizeof(kMagic)));
+ return fuzzer::UserSuppliedFuzzer::Mutate(
+ Data + sizeof(kMagic), Size - sizeof(kMagic), MaxSize - sizeof(kMagic));
+ }
+ // No need to redefine CrossOver() here.
+};
+
+int main(int argc, char **argv) {
+ fuzzer::FuzzerRandomLibc Rand(0);
+ MyFuzzer F(&Rand);
+ fuzzer::FuzzerDriver(argc, argv, F);
+}
diff --git a/gnu/llvm/lib/Fuzzer/test/dfsan/CMakeLists.txt b/gnu/llvm/lib/Fuzzer/test/dfsan/CMakeLists.txt
new file mode 100644
index 00000000000..2b49831fcdb
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/dfsan/CMakeLists.txt
@@ -0,0 +1,14 @@
+# These tests depend on both coverage and dfsan instrumentation.
+
+set(CMAKE_CXX_FLAGS_RELEASE
+ "${LIBFUZZER_FLAGS_BASE} -O0 -fno-sanitize=all -fsanitize=dataflow")
+
+foreach(Test ${DFSanTests})
+ add_executable(LLVMFuzzer-${Test}-DFSan
+ ../${Test}.cpp
+ )
+ target_link_libraries(LLVMFuzzer-${Test}-DFSan
+ LLVMFuzzer
+ )
+endforeach()
+
diff --git a/gnu/llvm/lib/Fuzzer/test/dict1.txt b/gnu/llvm/lib/Fuzzer/test/dict1.txt
new file mode 100644
index 00000000000..520d0cc7b7d
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/dict1.txt
@@ -0,0 +1,4 @@
+# Dictionary for SimpleDictionaryTest
+
+a="Elvis"
+b="Presley"
diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer-dfsan.test b/gnu/llvm/lib/Fuzzer/test/fuzzer-dfsan.test
new file mode 100644
index 00000000000..567086ed65a
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/fuzzer-dfsan.test
@@ -0,0 +1,23 @@
+CHECK1: BINGO
+CHECK2: BINGO
+CHECK3: BINGO
+CHECK4: BINGO
+
+CHECK_DFSanCmpCallback: DFSanCmpCallback: PC
+CHECK_DFSanSwitchCallback: DFSanSwitchCallback: PC
+CHECK_DFSanMemcmpCallback: DFSanMemcmpCallback: Pos
+
+RUN: not LLVMFuzzer-SimpleCmpTest-DFSan -use_traces=1 -seed=1 -runs=1000000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK1
+RUN: LLVMFuzzer-SimpleCmpTest-DFSan -use_traces=1 -seed=1 -runs=100 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanCmpCallback
+
+RUN: not LLVMFuzzer-MemcmpTest-DFSan -use_traces=1 -seed=1 -runs=10000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK2
+RUN: LLVMFuzzer-MemcmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanMemcmpCallback
+
+RUN: not LLVMFuzzer-StrncmpTest-DFSan -use_traces=1 -seed=1 -runs=10000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK3
+RUN: LLVMFuzzer-StrncmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanMemcmpCallback
+
+RUN: not LLVMFuzzer-StrcmpTest-DFSan -use_traces=1 -seed=1 -runs=10000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK3
+RUN: LLVMFuzzer-StrcmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanMemcmpCallback
+
+RUN: not LLVMFuzzer-SwitchTest-DFSan -use_traces=1 -seed=1 -runs=100000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK4
+RUN: LLVMFuzzer-SwitchTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanSwitchCallback
diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer-dict.test b/gnu/llvm/lib/Fuzzer/test/fuzzer-dict.test
new file mode 100644
index 00000000000..dec002f6a37
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/fuzzer-dict.test
@@ -0,0 +1,6 @@
+CHECK: BINGO
+Done1000000: Done 1000000 runs in
+
+RUN: not LLVMFuzzer-SimpleDictionaryTest -dict=%S/dict1.txt -seed=1 -runs=1000003 2>&1 | FileCheck %s
+RUN: LLVMFuzzer-SimpleDictionaryTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000
+
diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer-drill.test b/gnu/llvm/lib/Fuzzer/test/fuzzer-drill.test
new file mode 100644
index 00000000000..b2fc1fecd27
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/fuzzer-drill.test
@@ -0,0 +1,8 @@
+CHECK: BINGO
+RUN: rm -rf FourIndependentBranchesTestCORPUS
+RUN: mkdir FourIndependentBranchesTestCORPUS
+RUN: LLVMFuzzer-FourIndependentBranchesTest -seed=1 -runs=100000 FourIndependentBranchesTestCORPUS
+RUN: not LLVMFuzzer-FourIndependentBranchesTest -runs=100000 -drill=1 -jobs=200 FourIndependentBranchesTestCORPUS 2>&1 | FileCheck %s
+RUN: rm -rf FourIndependentBranchesTestCORPUS
+
+
diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer-threaded.test b/gnu/llvm/lib/Fuzzer/test/fuzzer-threaded.test
new file mode 100644
index 00000000000..c58a33456cc
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/fuzzer-threaded.test
@@ -0,0 +1,7 @@
+CHECK: Done 1000 runs in
+
+RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s
+RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s
+RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s
+RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s
+
diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer-timeout.test b/gnu/llvm/lib/Fuzzer/test/fuzzer-timeout.test
new file mode 100644
index 00000000000..c3a9e8a3a9e
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/fuzzer-timeout.test
@@ -0,0 +1,13 @@
+RUN: not LLVMFuzzer-TimeoutTest -timeout=1 2>&1 | FileCheck %s --check-prefix=TimeoutTest
+TimeoutTest: ALARM: working on the last Unit for
+TimeoutTest: Test unit written to ./timeout-
+TimeoutTest: == ERROR: libFuzzer: timeout after
+TimeoutTest: #0
+TimeoutTest: #1
+TimeoutTest: #2
+TimeoutTest: SUMMARY: libFuzzer: timeout
+
+RUN: not LLVMFuzzer-TimeoutTest -timeout=1 -test_single_input=%S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInputTimeoutTest
+SingleInputTimeoutTest: ALARM: working on the last Unit for
+SingleInputTimeoutTest-NOT: Test unit written to ./timeout-
+
diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer-traces.test b/gnu/llvm/lib/Fuzzer/test/fuzzer-traces.test
new file mode 100644
index 00000000000..3b8639b8e94
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/fuzzer-traces.test
@@ -0,0 +1,20 @@
+CHECK: BINGO
+Done1000000: Done 1000000 runs in
+Done10000000: Done 10000000 runs in
+
+RUN: not LLVMFuzzer-SimpleCmpTest -use_traces=1 -seed=1 -runs=10000001 2>&1 | FileCheck %s
+
+RUN: not LLVMFuzzer-MemcmpTest -use_traces=1 -seed=4294967295 -runs=100000 2>&1 | FileCheck %s
+RUN: LLVMFuzzer-MemcmpTest -seed=4294967295 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000
+
+RUN: not LLVMFuzzer-StrncmpTest -use_traces=1 -seed=1 -runs=100000 2>&1 | FileCheck %s
+RUN: LLVMFuzzer-StrncmpTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000
+
+RUN: not LLVMFuzzer-StrcmpTest -use_traces=1 -seed=1 -runs=200000 2>&1 | FileCheck %s
+RUN: LLVMFuzzer-StrcmpTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000
+
+RUN: not LLVMFuzzer-SwitchTest -use_traces=1 -seed=1 -runs=1000002 2>&1 | FileCheck %s
+RUN: LLVMFuzzer-SwitchTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000
+
+RUN: not LLVMFuzzer-SimpleHashTest -use_traces=1 -seed=1 -runs=10000000 2>&1 | FileCheck %s
+RUN: LLVMFuzzer-SimpleHashTest -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=Done10000000
diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer.test b/gnu/llvm/lib/Fuzzer/test/fuzzer.test
new file mode 100644
index 00000000000..c63014f59d6
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/fuzzer.test
@@ -0,0 +1,36 @@
+CHECK: BINGO
+Done1000000: Done 1000000 runs in
+
+RUN: LLVMFuzzer-SimpleTest 2>&1 | FileCheck %s
+RUN: not LLVMFuzzer-NullDerefTest -test_single_input=%S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInput
+SingleInput-NOT: Test unit written to ./crash-
+
+RUN: LLVMFuzzer-SimpleCmpTest -max_total_time=1 2>&1 | FileCheck %s --check-prefix=MaxTotalTime
+MaxTotalTime: Done {{.*}} runs in {{.}} second(s)
+
+RUN: not LLVMFuzzer-NullDerefTest 2>&1 | FileCheck %s --check-prefix=NullDerefTest
+NullDerefTest: Test unit written to ./crash-
+RUN: not LLVMFuzzer-NullDerefTest -artifact_prefix=ZZZ 2>&1 | FileCheck %s --check-prefix=NullDerefTestPrefix
+NullDerefTestPrefix: Test unit written to ZZZcrash-
+RUN: not LLVMFuzzer-NullDerefTest -artifact_prefix=ZZZ -exact_artifact_path=FOOBAR 2>&1 | FileCheck %s --check-prefix=NullDerefTestExactPath
+NullDerefTestExactPath: Test unit written to FOOBAR
+
+#not LLVMFuzzer-FullCoverageSetTest -timeout=15 -seed=1 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s
+
+RUN: not LLVMFuzzer-CounterTest -use_counters=1 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s
+
+RUN: not LLVMFuzzer-CallerCalleeTest -cross_over=0 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s
+# This one is flaky, may actually find the goal even w/o use_indir_calls.
+# LLVMFuzzer-CallerCalleeTest -use_indir_calls=0 -cross_over=0 -max_len=6 -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000
+
+
+RUN: not LLVMFuzzer-UserSuppliedFuzzerTest -seed=1 -timeout=15 2>&1 | FileCheck %s
+
+RUN: not LLVMFuzzer-UninstrumentedTest-Uninstrumented 2>&1 | FileCheck %s --check-prefix=UNINSTRUMENTED
+UNINSTRUMENTED: ERROR: __sanitizer_set_death_callback is not defined. Exiting.
+
+RUN: LLVMFuzzer-SimpleTest -print_new_cov_pcs=1 2>&1 | FileCheck %s --check-prefix=PCS
+PCS:{{^0x[a-f0-9]+}}
+PCS:NEW
+PCS:BINGO
+
diff --git a/gnu/llvm/lib/Fuzzer/test/hi.txt b/gnu/llvm/lib/Fuzzer/test/hi.txt
new file mode 100644
index 00000000000..2f9031f0ec7
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/hi.txt
@@ -0,0 +1 @@
+Hi! \ No newline at end of file
diff --git a/gnu/llvm/lib/Fuzzer/test/lit.cfg b/gnu/llvm/lib/Fuzzer/test/lit.cfg
new file mode 100644
index 00000000000..2140a97668b
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/lit.cfg
@@ -0,0 +1,15 @@
+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 and current exec dir.
+llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
+if (not llvm_tools_dir) or (not os.path.exists(llvm_tools_dir)):
+ lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % llvm_tools_dir)
+path = os.path.pathsep.join((llvm_tools_dir, config.test_exec_root,
+ config.environment['PATH']))
+config.environment['PATH'] = path
+
diff --git a/gnu/llvm/lib/Fuzzer/test/lit.site.cfg.in b/gnu/llvm/lib/Fuzzer/test/lit.site.cfg.in
new file mode 100644
index 00000000000..e520db8e881
--- /dev/null
+++ b/gnu/llvm/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/gnu/llvm/lib/Fuzzer/test/merge.test b/gnu/llvm/lib/Fuzzer/test/merge.test
new file mode 100644
index 00000000000..57ecc141bbf
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/merge.test
@@ -0,0 +1,29 @@
+CHECK: BINGO
+
+RUN: rm -rf %tmp/T1 %tmp/T2
+RUN: mkdir -p %tmp/T1 %tmp/T2
+RUN: echo F..... > %tmp/T1/1
+RUN: echo .U.... > %tmp/T1/2
+RUN: echo ..Z... > %tmp/T1/3
+
+# T1 has 3 elements, T2 is empty.
+RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK1
+CHECK1: Merge: running the initial corpus {{.*}} of 3 units
+CHECK1: Merge: written 0 out of 0 units
+
+RUN: echo ...Z.. > %tmp/T2/1
+RUN: echo ....E. > %tmp/T2/2
+RUN: echo .....R > %tmp/T2/3
+RUN: echo F..... > %tmp/T2/a
+RUN: echo .U.... > %tmp/T2/b
+RUN: echo ..Z... > %tmp/T2/c
+
+# T1 has 3 elements, T2 has 6 elements, only 3 are new.
+RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK2
+CHECK2: Merge: running the initial corpus {{.*}} of 3 units
+CHECK2: Merge: written 3 out of 6 units
+
+# Now, T1 has 6 units and T2 has no new interesting units.
+RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK3
+CHECK3: Merge: running the initial corpus {{.*}} of 6 units
+CHECK3: Merge: written 0 out of 6 units
diff --git a/gnu/llvm/lib/Fuzzer/test/trace-bb/CMakeLists.txt b/gnu/llvm/lib/Fuzzer/test/trace-bb/CMakeLists.txt
new file mode 100644
index 00000000000..99af019565b
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/trace-bb/CMakeLists.txt
@@ -0,0 +1,14 @@
+# These tests are not instrumented with coverage.
+
+set(CMAKE_CXX_FLAGS_RELEASE
+ "${LIBFUZZER_FLAGS_BASE} -fsanitize-coverage=edge,trace-bb")
+
+foreach(Test ${TraceBBTests})
+ add_executable(LLVMFuzzer-${Test}-TraceBB
+ ../${Test}.cpp
+ )
+ target_link_libraries(LLVMFuzzer-${Test}-TraceBB
+ LLVMFuzzer
+ )
+endforeach()
+
diff --git a/gnu/llvm/lib/Fuzzer/test/uninstrumented/CMakeLists.txt b/gnu/llvm/lib/Fuzzer/test/uninstrumented/CMakeLists.txt
new file mode 100644
index 00000000000..443ba3716f6
--- /dev/null
+++ b/gnu/llvm/lib/Fuzzer/test/uninstrumented/CMakeLists.txt
@@ -0,0 +1,14 @@
+# These tests are not instrumented with coverage.
+
+set(CMAKE_CXX_FLAGS_RELEASE
+ "${LIBFUZZER_FLAGS_BASE} -O0 -fno-sanitize=all")
+
+foreach(Test ${UninstrumentedTests})
+ add_executable(LLVMFuzzer-${Test}-Uninstrumented
+ ../${Test}.cpp
+ )
+ target_link_libraries(LLVMFuzzer-${Test}-Uninstrumented
+ LLVMFuzzer
+ )
+endforeach()
+
diff --git a/gnu/llvm/lib/Fuzzer/test/unit/lit.cfg b/gnu/llvm/lib/Fuzzer/test/unit/lit.cfg
new file mode 100644
index 00000000000..0cc31939c55
--- /dev/null
+++ b/gnu/llvm/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/gnu/llvm/lib/Fuzzer/test/unit/lit.site.cfg.in b/gnu/llvm/lib/Fuzzer/test/unit/lit.site.cfg.in
new file mode 100644
index 00000000000..114daf474b6
--- /dev/null
+++ b/gnu/llvm/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")