summaryrefslogtreecommitdiff
path: root/chromium/third_party/libFuzzer
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2016-08-01 12:59:39 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2016-08-04 12:40:43 +0000
commit28b1110370900897ab652cb420c371fab8857ad4 (patch)
tree41b32127d23b0df4f2add2a27e12dc87bddb260e /chromium/third_party/libFuzzer
parent399c965b6064c440ddcf4015f5f8e9d131c7a0a6 (diff)
downloadqtwebengine-chromium-28b1110370900897ab652cb420c371fab8857ad4.tar.gz
BASELINE: Update Chromium to 53.0.2785.41
Also adds a few extra files for extensions. Change-Id: Iccdd55d98660903331cf8b7b29188da781830af4 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/libFuzzer')
-rw-r--r--chromium/third_party/libFuzzer/BUILD.gn17
-rw-r--r--chromium/third_party/libFuzzer/src/CMakeLists.txt13
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerDriver.cpp44
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def46
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerExtFunctions.h33
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerExtFunctionsDlsym.cpp49
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerExtFunctionsWeak.cpp50
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerFlags.def8
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerFnAdapter.h1
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerIO.cpp3
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerInterface.cpp20
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerInterface.h89
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerInternal.h122
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerLoop.cpp445
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerMain.cpp6
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerMutate.cpp84
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp54
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerTracePC.h37
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp52
-rw-r--r--chromium/third_party/libFuzzer/src/FuzzerUtil.cpp60
-rw-r--r--chromium/third_party/libFuzzer/src/afl/afl_driver.cpp111
21 files changed, 963 insertions, 381 deletions
diff --git a/chromium/third_party/libFuzzer/BUILD.gn b/chromium/third_party/libFuzzer/BUILD.gn
index 449114f922b..208a02042a6 100644
--- a/chromium/third_party/libFuzzer/BUILD.gn
+++ b/chromium/third_party/libFuzzer/BUILD.gn
@@ -5,12 +5,14 @@
source_set("libfuzzer") {
# libfuzzer should be compiled without coverage (infinite loop in trace_cmp).
configs -= [ "//build/config/sanitizers:default_sanitizer_flags" ]
- configs += [ "//build/config/sanitizers:default_sanitizer_flags_but_coverage" ]
+ configs +=
+ [ "//build/config/sanitizers:default_sanitizer_flags_but_coverage" ]
sources = [
"src/FuzzerCrossOver.cpp",
"src/FuzzerDriver.cpp",
+ "src/FuzzerExtFunctionsDlsym.cpp",
+ "src/FuzzerExtFunctionsWeak.cpp",
"src/FuzzerIO.cpp",
- "src/FuzzerInterface.cpp",
"src/FuzzerLoop.cpp",
"src/FuzzerMain.cpp",
"src/FuzzerMutate.cpp",
@@ -20,3 +22,14 @@ source_set("libfuzzer") {
"src/FuzzerUtil.cpp",
]
}
+
+source_set("afl_driver") {
+ # AFL should be compiled without coverage (infinite loop in trace_cmp).
+ configs -= [ "//build/config/sanitizers:default_sanitizer_flags" ]
+ configs +=
+ [ "//build/config/sanitizers:default_sanitizer_flags_but_coverage" ]
+
+ sources = [
+ "src/afl/afl_driver.cpp",
+ ]
+}
diff --git a/chromium/third_party/libFuzzer/src/CMakeLists.txt b/chromium/third_party/libFuzzer/src/CMakeLists.txt
index 16620b06e71..16a769fafb9 100644
--- a/chromium/third_party/libFuzzer/src/CMakeLists.txt
+++ b/chromium/third_party/libFuzzer/src/CMakeLists.txt
@@ -1,12 +1,19 @@
-set(LIBFUZZER_FLAGS_BASE "${CMAKE_CXX_FLAGS_RELEASE}")
+set(LIBFUZZER_FLAGS_BASE "${CMAKE_CXX_FLAGS}")
# Disable the coverage and sanitizer instrumentation for the fuzzer itself.
-set(CMAKE_CXX_FLAGS_RELEASE "${LIBFUZZER_FLAGS_BASE} -O2 -fno-sanitize=all -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters -Werror")
+set(CMAKE_CXX_FLAGS "${LIBFUZZER_FLAGS_BASE} -fno-sanitize=all -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters -Werror")
if( LLVM_USE_SANITIZE_COVERAGE )
+ if(NOT "${LLVM_USE_SANITIZER}" STREQUAL "Address")
+ message(FATAL_ERROR
+ "LibFuzzer and its tests require LLVM_USE_SANITIZER=Address and "
+ "LLVM_USE_SANITIZE_COVERAGE=YES to be set."
+ )
+ endif()
add_library(LLVMFuzzerNoMainObjects OBJECT
FuzzerCrossOver.cpp
- FuzzerInterface.cpp
FuzzerTraceState.cpp
FuzzerDriver.cpp
+ FuzzerExtFunctionsDlsym.cpp
+ FuzzerExtFunctionsWeak.cpp
FuzzerIO.cpp
FuzzerLoop.cpp
FuzzerMutate.cpp
diff --git a/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp b/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp
index db520790823..08a5e19ce75 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp
+++ b/chromium/third_party/libFuzzer/src/FuzzerDriver.cpp
@@ -163,8 +163,9 @@ static bool ParseOneFlag(const char *Param) {
}
}
}
- PrintHelp();
- exit(1);
+ Printf("\n\nWARNING: unrecognized flag '%s'; "
+ "use -help=1 to list all flags\n\n", Param);
+ return true;
}
// We don't use any library to minimize dependencies.
@@ -189,7 +190,7 @@ static std::mutex Mu;
static void PulseThread() {
while (true) {
- std::this_thread::sleep_for(std::chrono::seconds(600));
+ SleepSeconds(600);
std::lock_guard<std::mutex> Lock(Mu);
Printf("pulse...\n");
}
@@ -234,6 +235,21 @@ static int RunInMultipleProcesses(const std::vector<std::string> &Args,
return HasErrors ? 1 : 0;
}
+static void RssThread(Fuzzer *F, size_t RssLimitMb) {
+ while (true) {
+ SleepSeconds(1);
+ size_t Peak = GetPeakRSSMb();
+ if (Peak > RssLimitMb)
+ F->RssLimitCallback();
+ }
+}
+
+static void StartRssThread(Fuzzer *F, size_t RssLimitMb) {
+ if (!RssLimitMb) return;
+ std::thread T(RssThread, F, RssLimitMb);
+ T.detach();
+}
+
int RunOneTest(Fuzzer *F, const char *InputFilePath) {
Unit U = FileToVector(InputFilePath);
Unit PreciseSizedU(U);
@@ -250,9 +266,13 @@ static bool AllInputsAreFiles() {
return true;
}
-static int FuzzerDriver(const std::vector<std::string> &Args,
- UserCallback Callback) {
+int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
using namespace fuzzer;
+ assert(argc && argv && "Argument pointers cannot be nullptr");
+ EF = new ExternalFunctions();
+ if (EF->LLVMFuzzerInitialize)
+ EF->LLVMFuzzerInitialize(argc, argv);
+ const std::vector<std::string> Args(*argv, *argv + *argc);
assert(!Args.empty());
ProgName = new std::string(Args[0]);
ParseFlags(Args);
@@ -295,6 +315,7 @@ static int FuzzerDriver(const std::vector<std::string> &Args,
Options.OnlyASCII = Flags.only_ascii;
Options.OutputCSV = Flags.output_csv;
Options.DetectLeaks = Flags.detect_leaks;
+ Options.RssLimitMb = Flags.rss_limit_mb;
if (Flags.runs >= 0)
Options.MaxNumberOfRuns = Flags.runs;
if (!Inputs->empty())
@@ -314,6 +335,8 @@ static int FuzzerDriver(const std::vector<std::string> &Args,
Options.SaveArtifacts = !DoPlainRun;
Options.PrintNewCovPcs = Flags.print_new_cov_pcs;
Options.PrintFinalStats = Flags.print_final_stats;
+ Options.TruncateUnits = Flags.truncate_units;
+ Options.PruneCorpus = Flags.prune_corpus;
unsigned Seed = Flags.seed;
// Initialize Seed.
@@ -331,6 +354,8 @@ static int FuzzerDriver(const std::vector<std::string> &Args,
if (U.size() <= Word::GetMaxSize())
MD.AddWordToManualDictionary(Word(U.data(), U.size()));
+ StartRssThread(&F, Flags.rss_limit_mb);
+
// Timer
if (Flags.timeout > 0)
SetTimer(Flags.timeout / 2 + 1);
@@ -349,11 +374,12 @@ static int FuzzerDriver(const std::vector<std::string> &Args,
Inputs->size(), Runs);
for (auto &Path : *Inputs) {
auto StartTime = system_clock::now();
+ Printf("Running: %s\n", Path.c_str());
for (int Iter = 0; Iter < Runs; Iter++)
RunOneTest(&F, Path.c_str());
auto StopTime = system_clock::now();
auto MS = duration_cast<milliseconds>(StopTime - StartTime).count();
- Printf("%s: %zd ms\n", Path.c_str(), (long)MS);
+ Printf("Executed %s in %zd ms\n", Path.c_str(), (long)MS);
}
F.PrintFinalStats();
exit(0);
@@ -397,9 +423,7 @@ static int FuzzerDriver(const std::vector<std::string> &Args,
exit(0); // Don't let F destroy itself.
}
-int FuzzerDriver(int argc, char **argv, UserCallback Callback) {
- std::vector<std::string> Args(argv, argv + argc);
- return FuzzerDriver(Args, Callback);
-}
+// Storage for global ExternalFunctions object.
+ExternalFunctions *EF = nullptr;
} // namespace fuzzer
diff --git a/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def b/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def
new file mode 100644
index 00000000000..f7dcf9b54fb
--- /dev/null
+++ b/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.def
@@ -0,0 +1,46 @@
+//===- FuzzerExtFunctions.def - External functions --------------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This defines the external function pointers that
+// ``fuzzer::ExternalFunctions`` should contain and try to initialize. The
+// EXT_FUNC macro must be defined at the point of inclusion. The signature of
+// the macro is:
+//
+// EXT_FUNC(<name>, <return_type>, <function_signature>, <warn_if_missing>)
+//===----------------------------------------------------------------------===//
+
+// Optional user functions
+EXT_FUNC(LLVMFuzzerInitialize, int, (int *argc, char ***argv), false);
+EXT_FUNC(LLVMFuzzerCustomMutator, size_t,
+ (uint8_t * Data, size_t Size, size_t MaxSize, unsigned int Seed),
+ false);
+EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t,
+ (const uint8_t * Data1, size_t Size1,
+ const uint8_t * Data2, size_t Size2,
+ uint8_t * Out, size_t MaxOutSize, unsigned int Seed),
+ false);
+
+// Sanitizer functions
+EXT_FUNC(__lsan_enable, void, (), false);
+EXT_FUNC(__lsan_disable, void, (), false);
+EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false);
+EXT_FUNC(__sanitizer_get_coverage_pc_buffer, uintptr_t, (uintptr_t**), true);
+EXT_FUNC(__sanitizer_get_number_of_counters, size_t, (), false);
+EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int,
+ (void (*malloc_hook)(const volatile void *, size_t),
+ void (*free_hook)(const volatile void *)),
+ false);
+EXT_FUNC(__sanitizer_get_total_unique_caller_callee_pairs, size_t, (), false);
+EXT_FUNC(__sanitizer_get_total_unique_coverage, size_t, (), true);
+EXT_FUNC(__sanitizer_print_memory_profile, int, (size_t), false);
+EXT_FUNC(__sanitizer_print_stack_trace, void, (), true);
+EXT_FUNC(__sanitizer_reset_coverage, void, (), true);
+EXT_FUNC(__sanitizer_set_death_callback, void, (void (*)(void)), true);
+EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false);
+EXT_FUNC(__sanitizer_update_counter_bitset_and_clear_counters, uintptr_t,
+ (uint8_t*), false);
diff --git a/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.h b/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.h
new file mode 100644
index 00000000000..2ec86cb9231
--- /dev/null
+++ b/chromium/third_party/libFuzzer/src/FuzzerExtFunctions.h
@@ -0,0 +1,33 @@
+//===- FuzzerExtFunctions.h - Interface to external functions ---*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Defines an interface to (possibly optional) functions.
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_FUZZER_EXT_FUNCTIONS_H
+#define LLVM_FUZZER_EXT_FUNCTIONS_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace fuzzer {
+
+struct ExternalFunctions {
+ // Initialize function pointers. Functions that are not available will be set
+ // to nullptr. Do not call this constructor before ``main()`` has been
+ // entered.
+ ExternalFunctions();
+
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
+ RETURN_TYPE(*NAME) FUNC_SIG = nullptr
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+};
+} // namespace fuzzer
+#endif
diff --git a/chromium/third_party/libFuzzer/src/FuzzerExtFunctionsDlsym.cpp b/chromium/third_party/libFuzzer/src/FuzzerExtFunctionsDlsym.cpp
new file mode 100644
index 00000000000..7b9681a6193
--- /dev/null
+++ b/chromium/third_party/libFuzzer/src/FuzzerExtFunctionsDlsym.cpp
@@ -0,0 +1,49 @@
+//===- FuzzerExtFunctionsDlsym.cpp - Interface to external functions ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Implementation for operating systems that support dlsym(). We only use it on
+// Apple platforms for now. We don't use this approach on Linux because it
+// requires that clients of LibFuzzer pass ``--export-dynamic`` to the linker.
+// That is a complication we don't wish to expose to clients right now.
+//===----------------------------------------------------------------------===//
+#include "FuzzerInternal.h"
+#if LIBFUZZER_APPLE
+
+#include "FuzzerExtFunctions.h"
+#include <dlfcn.h>
+
+using namespace fuzzer;
+
+template <typename T>
+static T GetFnPtr(const char *FnName, bool WarnIfMissing) {
+ dlerror(); // Clear any previous errors.
+ void *Fn = dlsym(RTLD_DEFAULT, FnName);
+ if (Fn == nullptr) {
+ if (WarnIfMissing) {
+ const char *ErrorMsg = dlerror();
+ Printf("WARNING: Failed to find function \"%s\".", FnName);
+ if (ErrorMsg)
+ Printf(" Reason %s.", ErrorMsg);
+ Printf("\n");
+ }
+ }
+ return reinterpret_cast<T>(Fn);
+}
+
+namespace fuzzer {
+
+ExternalFunctions::ExternalFunctions() {
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
+ this->NAME = GetFnPtr<decltype(ExternalFunctions::NAME)>(#NAME, WARN)
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+}
+} // namespace fuzzer
+#endif // LIBFUZZER_APPLE
diff --git a/chromium/third_party/libFuzzer/src/FuzzerExtFunctionsWeak.cpp b/chromium/third_party/libFuzzer/src/FuzzerExtFunctionsWeak.cpp
new file mode 100644
index 00000000000..75c0ed9f830
--- /dev/null
+++ b/chromium/third_party/libFuzzer/src/FuzzerExtFunctionsWeak.cpp
@@ -0,0 +1,50 @@
+//===- FuzzerExtFunctionsWeak.cpp - Interface to external functions -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Implementation for Linux. This relies on the linker's support for weak
+// symbols. We don't use this approach on Apple platforms because it requires
+// clients of LibFuzzer to pass ``-U _<symbol_name>`` to the linker to allow
+// weak symbols to be undefined. That is a complication we don't want to expose
+// to clients right now.
+//===----------------------------------------------------------------------===//
+#include "FuzzerInternal.h"
+#if LIBFUZZER_LINUX
+
+#include "FuzzerExtFunctions.h"
+
+extern "C" {
+// Declare these symbols as weak to allow them to be optionally defined.
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
+ __attribute__((weak)) RETURN_TYPE NAME FUNC_SIG
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+}
+
+using namespace fuzzer;
+
+static void CheckFnPtr(void *FnPtr, const char *FnName, bool WarnIfMissing) {
+ if (FnPtr == nullptr && WarnIfMissing) {
+ Printf("WARNING: Failed to find function \"%s\".\n", FnName);
+ }
+}
+
+namespace fuzzer {
+
+ExternalFunctions::ExternalFunctions() {
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
+ this->NAME = ::NAME; \
+ CheckFnPtr((void *)::NAME, #NAME, WARN);
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+}
+} // namespace fuzzer
+#endif // LIBFUZZER_LINUX
diff --git a/chromium/third_party/libFuzzer/src/FuzzerFlags.def b/chromium/third_party/libFuzzer/src/FuzzerFlags.def
index 86b203ce0ce..2945152ae70 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerFlags.def
+++ b/chromium/third_party/libFuzzer/src/FuzzerFlags.def
@@ -35,7 +35,8 @@ FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total "
"time in seconds to run the fuzzer.")
FUZZER_FLAG_INT(help, 0, "Print help.")
FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be "
- "merged into the 1-st corpus. Only interesting units will be taken.")
+ "merged into the 1-st corpus. Only interesting units will be taken. "
+ "This flag can be used to minimize a corpus.")
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")
@@ -81,6 +82,11 @@ FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; "
"Be careful, this will also close e.g. asan's stderr/stdout.")
FUZZER_FLAG_INT(detect_leaks, 1, "If 1, and if LeakSanitizer is enabled "
"try to detect memory leaks during fuzzing (i.e. not only at shut down).")
+FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon"
+ "reaching this limit of RSS memory usage.")
+FUZZER_FLAG_INT(truncate_units, 0, "Try truncated units when loading corpus.")
+FUZZER_FLAG_INT(prune_corpus, 1, "Prune corpus items without new coverage when "
+ "loading corpus.")
FUZZER_DEPRECATED_FLAG(exit_on_first)
FUZZER_DEPRECATED_FLAG(save_minimized_corpus)
diff --git a/chromium/third_party/libFuzzer/src/FuzzerFnAdapter.h b/chromium/third_party/libFuzzer/src/FuzzerFnAdapter.h
index ae121d238dc..eb2c219b870 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerFnAdapter.h
+++ b/chromium/third_party/libFuzzer/src/FuzzerFnAdapter.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <algorithm>
+#include <string>
#include <tuple>
#include <vector>
diff --git a/chromium/third_party/libFuzzer/src/FuzzerIO.cpp b/chromium/third_party/libFuzzer/src/FuzzerIO.cpp
index ac35d736bbf..0e0c4e989cc 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerIO.cpp
+++ b/chromium/third_party/libFuzzer/src/FuzzerIO.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
// IO functions.
//===----------------------------------------------------------------------===//
+#include "FuzzerExtFunctions.h"
#include "FuzzerInternal.h"
#include <iterator>
#include <fstream>
@@ -122,6 +123,8 @@ void DupAndCloseStderr() {
FILE *NewOutputFile = fdopen(OutputFd, "w");
if (NewOutputFile) {
OutputFile = NewOutputFile;
+ if (EF->__sanitizer_set_report_fd)
+ EF->__sanitizer_set_report_fd(reinterpret_cast<void *>(OutputFd));
close(2);
}
}
diff --git a/chromium/third_party/libFuzzer/src/FuzzerInterface.cpp b/chromium/third_party/libFuzzer/src/FuzzerInterface.cpp
deleted file mode 100644
index 5de7d614429..00000000000
--- a/chromium/third_party/libFuzzer/src/FuzzerInterface.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-//===- 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"
-#include <random>
-
-namespace fuzzer {
-
-
-} // namespace fuzzer.
diff --git a/chromium/third_party/libFuzzer/src/FuzzerInterface.h b/chromium/third_party/libFuzzer/src/FuzzerInterface.h
index 30620e51396..d47e20e3a2b 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerInterface.h
+++ b/chromium/third_party/libFuzzer/src/FuzzerInterface.h
@@ -6,75 +6,62 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-// Define the interface between the Fuzzer and the library being tested.
+// Define the interface between libFuzzer 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.
+// NOTE: the libFuzzer interface is thin and in the majority of cases
+// you should not include this file into your target. In 95% of cases
+// all you need is to define the following function in your file:
+// extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+
+// WARNING: keep the interface in C.
#ifndef LLVM_FUZZER_INTERFACE_H
#define LLVM_FUZZER_INTERFACE_H
-#include <cstddef>
-#include <cstdint>
+#include <stddef.h>
+#include <stdint.h>
-// Plain C interface. Should be sufficient for most uses.
+#ifdef __cplusplus
extern "C" {
-// The target function, mandatory.
+#endif // __cplusplus
+
+// Mandatory user-provided target function.
+// Executes the code under test with [Data, Data+Size) as the input.
+// libFuzzer will invoke this function *many* times with different inputs.
// Must return 0.
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
-// The initialization function, optional.
+
+// Optional user-provided initialization function.
+// If provided, this function will be called by libFuzzer once at startup.
+// It may read and modify argc/argv.
+// Must return 0.
int LLVMFuzzerInitialize(int *argc, char ***argv);
-// Custom mutator, optional.
-// Mutates raw data in [Data, Data+Size] inplace.
+
+// Optional user-provided custom mutator.
+// Mutates raw data in [Data, Data+Size) inplace.
// Returns the new size, which is not greater than MaxSize.
// Given the same Seed produces the same mutation.
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize,
unsigned int Seed);
-} // extern "C"
-
-namespace fuzzer {
-
-/// 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.
+// Optional user-provided custom cross-over function.
+// Combines pieces of Data1 & Data2 together into Out.
+// Returns the new size, which is not greater than MaxOutSize.
+// Should produce the same mutation given the same Seed.
+size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1,
+ const uint8_t *Data2, size_t Size2,
+ uint8_t *Out, size_t MaxOutSize,
+ unsigned int Seed);
-Usage:
-
-#\code
-#include "FuzzerInterface.h"
-
-int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
- DoStuffWithData(Data, Size);
- return 0;
-}
-
-// Optional.
-// Define this only if you need to read/modify argc/argv at startup
-// and you are using libFuzzer's main().
-// Must return 0.
-int LLVMFuzzerInitialize(int *argc, char ***argv) {
- ReadAndMaybeModify(argc, argv);
- return 0;
-}
-
-// Implement your own main() or use the one from FuzzerMain.cpp.
-// *NOT* recommended for most cases.
-int main(int argc, char **argv) {
- InitializeMeIfNeeded();
- return fuzzer::FuzzerDriver(argc, argv, LLVMFuzzerTestOneInput);
-}
-#\endcode
-*/
-int FuzzerDriver(int argc, char **argv, UserCallback Callback);
-
-// Mutates raw data in [Data, Data+Size] inplace.
+// Experimental, may go away in future.
+// libFuzzer-provided function to be used inside LLVMFuzzerTestOneInput.
+// Mutates raw data in [Data, Data+Size) inplace.
// Returns the new size, which is not greater than MaxSize.
-// Can be used inside the user-supplied LLVMFuzzerTestOneInput.
-size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize);
+size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
-} // namespace fuzzer
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
#endif // LLVM_FUZZER_INTERFACE_H
diff --git a/chromium/third_party/libFuzzer/src/FuzzerInternal.h b/chromium/third_party/libFuzzer/src/FuzzerInternal.h
index a34bfec57c1..6fb429e705e 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerInternal.h
+++ b/chromium/third_party/libFuzzer/src/FuzzerInternal.h
@@ -13,6 +13,7 @@
#define LLVM_FUZZER_INTERNAL_H
#include <algorithm>
+#include <atomic>
#include <cassert>
#include <chrono>
#include <climits>
@@ -24,9 +25,26 @@
#include <unordered_set>
#include <vector>
+#include "FuzzerExtFunctions.h"
#include "FuzzerInterface.h"
+#include "FuzzerTracePC.h"
+
+// Platform detection.
+#ifdef __linux__
+#define LIBFUZZER_LINUX 1
+#define LIBFUZZER_APPLE 0
+#elif __APPLE__
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_APPLE 1
+#else
+#error "Support for your platform has not been implemented"
+#endif
namespace fuzzer {
+
+typedef int (*UserCallback)(const uint8_t *Data, size_t Size);
+int FuzzerDriver(int *argc, char ***argv, UserCallback Callback);
+
using namespace std::chrono;
typedef std::vector<uint8_t> Unit;
typedef std::vector<Unit> UnitVector;
@@ -106,16 +124,11 @@ void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out);
// Returns true iff U has been changed.
bool ToASCII(uint8_t *Data, size_t Size);
bool IsASCII(const Unit &U);
+bool IsASCII(const uint8_t *Data, size_t Size);
int NumberOfCpuCores();
int GetPid();
-
-// Clears the current PC Map.
-void PcMapResetCurrent();
-// Merges the current PC Map into the combined one, and clears the former.
-void PcMapMergeCurrentToCombined();
-// Returns the size of the combined PC Map.
-size_t PcMapCombinedSize();
+void SleepSeconds(int Seconds);
class Random {
public:
@@ -192,7 +205,7 @@ private:
class MutationDispatcher {
public:
- MutationDispatcher(Random &Rand) : Rand(Rand) {}
+ MutationDispatcher(Random &Rand);
~MutationDispatcher() {}
/// Indicate that we are about to start a new sequence of mutations.
void StartMutationSequence();
@@ -200,6 +213,10 @@ public:
void PrintMutationSequence();
/// Indicate that the current sequence of mutations was successfull.
void RecordSuccessfulMutationSequence();
+ /// Mutates data by invoking user-provided mutator.
+ size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by invoking user-provided crossover.
+ size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize);
/// Mutates data by shuffling bytes.
size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize);
/// Mutates data by erasing a byte.
@@ -229,9 +246,12 @@ public:
/// 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.
+ /// Applies one of the configured mutations.
/// Returns the new size of data which could be up to MaxSize.
size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Applies one of the default mutations. Provided as a service
+ /// to mutation authors.
+ size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize);
/// Creates a cross-over of two pieces of Data, returns its size.
size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2,
@@ -256,6 +276,8 @@ private:
size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size,
size_t MaxSize);
+ size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize,
+ const std::vector<Mutator> &Mutators);
Random &Rand;
// Dictionary provided by the user via -dict=DICT_FILE.
@@ -271,7 +293,8 @@ private:
const std::vector<Unit> *Corpus = nullptr;
std::vector<uint8_t> MutateInPlaceHere;
- static Mutator Mutators[];
+ std::vector<Mutator> Mutators;
+ std::vector<Mutator> DefaultMutators;
};
class Fuzzer {
@@ -283,6 +306,7 @@ public:
int TimeoutExitCode = 77;
int ErrorExitCode = 77;
int MaxTotalTimeSec = 0;
+ int RssLimitMb = 0;
bool DoCrossOver = true;
int MutateDepth = 5;
bool UseCounters = false;
@@ -305,7 +329,38 @@ public:
bool PrintNewCovPcs = false;
bool PrintFinalStats = false;
bool DetectLeaks = true;
+ bool TruncateUnits = false;
+ bool PruneCorpus = true;
+ };
+
+ // Aggregates all available coverage measurements.
+ struct Coverage {
+ Coverage() { Reset(); }
+
+ void Reset() {
+ BlockCoverage = 0;
+ CallerCalleeCoverage = 0;
+ PcMapBits = 0;
+ CounterBitmapBits = 0;
+ PcBufferLen = 0;
+ CounterBitmap.clear();
+ PCMap.Reset();
+ }
+
+ std::string DebugString() const;
+
+ size_t BlockCoverage;
+ size_t CallerCalleeCoverage;
+
+ size_t PcBufferLen;
+ // Precalculated number of bits in CounterBitmap.
+ size_t CounterBitmapBits;
+ std::vector<uint8_t> CounterBitmap;
+ // Precalculated number of bits in PCMap.
+ size_t PcMapBits;
+ PcCoverageMap PCMap;
};
+
Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options);
void AddToCorpus(const Unit &U) {
Corpus.push_back(U);
@@ -313,6 +368,7 @@ public:
}
size_t ChooseUnitIdxToMutate();
const Unit &ChooseUnitToMutate() { return Corpus[ChooseUnitIdxToMutate()]; };
+ void TruncateUnits(std::vector<Unit> *NewCorpus);
void Loop();
void Drill();
void ShuffleAndMinimize();
@@ -353,6 +409,13 @@ public:
MutationDispatcher &GetMD() { return MD; }
void PrintFinalStats();
void SetMaxLen(size_t MaxLen);
+ void RssLimitCallback();
+
+ // Public for tests.
+ void ResetCoverage();
+
+ bool InFuzzingThread() const { return IsMyThread; }
+ size_t GetCurrentUnitInFuzzingThead(const uint8_t **Data) const;
private:
void AlarmCallback();
@@ -361,24 +424,20 @@ private:
void MutateAndTestOne();
void ReportNewCoverage(const Unit &U);
bool RunOne(const Unit &U) { return RunOne(U.data(), U.size()); }
- void RunOneAndUpdateCorpus(uint8_t *Data, size_t Size);
+ void RunOneAndUpdateCorpus(const uint8_t *Data, size_t Size);
void WriteToOutputCorpus(const Unit &U);
void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix);
void PrintStats(const char *Where, const char *End = "\n");
void PrintStatusForNewUnit(const Unit &U);
void ShuffleCorpus(UnitVector *V);
- void TryDetectingAMemoryLeak(uint8_t *Data, size_t Size);
- void CheckForMemoryLeaks();
+ void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
+ bool DuringInitialCorpusExecution);
// Updates the probability distribution for the units in the corpus.
// Must be called whenever the corpus or unit weights are changed.
void UpdateCorpusDistribution();
- size_t RecordBlockCoverage();
- size_t RecordCallerCalleeCoverage();
- void PrepareCoverageBeforeRun();
- bool CheckCoverageAfterRun();
- void ResetCoverage();
+ bool UpdateMaxCoverage();
// Trace-based fuzzing: we run a unit with some kind of tracing
// enabled and record potentially useful mutations. Then
@@ -394,8 +453,9 @@ private:
void DumpCurrentUnit(const char *Prefix);
void DeathCallback();
+ void LazyAllocateCurrentUnitData();
uint8_t *CurrentUnitData = nullptr;
- size_t CurrentUnitSize = 0;
+ std::atomic<size_t> CurrentUnitSize;
size_t TotalNumberOfRuns = 0;
size_t NumberOfNewUnitsAdded = 0;
@@ -406,17 +466,6 @@ private:
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;
- }
-
- std::vector<uint8_t> MutateInPlaceHere;
-
std::piecewise_constant_distribution<double> CorpusDistribution;
UserCallback CB;
MutationDispatcher &MD;
@@ -425,12 +474,17 @@ private:
system_clock::time_point UnitStartTime;
long TimeOfLongestUnitInSeconds = 0;
long EpochOfLastReadOfOutputCorpus = 0;
- size_t LastRecordedBlockCoverage = 0;
- size_t LastRecordedPcMapSize = 0;
- size_t LastRecordedCallerCalleeCoverage = 0;
- size_t LastCoveragePcBufferLen = 0;
+
+ // Maximum recorded coverage.
+ Coverage MaxCoverage;
+
+ // Need to know our own thread.
+ static thread_local bool IsMyThread;
};
+// Global interface to functions that may or may not be available.
+extern ExternalFunctions *EF;
+
}; // namespace fuzzer
#endif // LLVM_FUZZER_INTERNAL_H
diff --git a/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp b/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp
index 3b0b339bf9c..51cb8703c26 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp
+++ b/chromium/third_party/libFuzzer/src/FuzzerLoop.cpp
@@ -31,54 +31,119 @@
#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);
-
-__attribute__((weak)) size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
- size_t MaxSize,
- unsigned int Seed);
-__attribute__((weak)) void __sanitizer_malloc_hook(void *ptr, size_t size);
-__attribute__((weak)) void __sanitizer_free_hook(void *ptr);
-__attribute__((weak)) void __lsan_enable();
-__attribute__((weak)) void __lsan_disable();
-__attribute__((weak)) int __lsan_do_recoverable_leak_check();
-}
-
namespace fuzzer {
static const size_t kMaxUnitSizeToPrint = 256;
+static const size_t TruncateMaxRuns = 1000;
+
+thread_local bool Fuzzer::IsMyThread;
-static void MissingWeakApiFunction(const char *FnName) {
+static void MissingExternalApiFunction(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) \
+#define CHECK_EXTERNAL_FUNCTION(fn) \
do { \
- if (!fn) \
- MissingWeakApiFunction(#fn); \
+ if (!(EF->fn)) \
+ MissingExternalApiFunction(#fn); \
} while (false)
// Only one Fuzzer per process.
static Fuzzer *F;
-size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
- assert(F);
- return F->GetMD().Mutate(Data, Size, MaxSize);
+struct CoverageController {
+ static void Reset() {
+ CHECK_EXTERNAL_FUNCTION(__sanitizer_reset_coverage);
+ EF->__sanitizer_reset_coverage();
+ PcMapResetCurrent();
+ }
+
+ static void ResetCounters(const Fuzzer::FuzzingOptions &Options) {
+ if (Options.UseCounters) {
+ EF->__sanitizer_update_counter_bitset_and_clear_counters(0);
+ }
+ }
+
+ static void Prepare(const Fuzzer::FuzzingOptions &Options,
+ Fuzzer::Coverage *C) {
+ if (Options.UseCounters) {
+ size_t NumCounters = EF->__sanitizer_get_number_of_counters();
+ C->CounterBitmap.resize(NumCounters);
+ }
+ }
+
+ // Records data to a maximum coverage tracker. Returns true if additional
+ // coverage was discovered.
+ static bool RecordMax(const Fuzzer::FuzzingOptions &Options,
+ Fuzzer::Coverage *C) {
+ bool Res = false;
+
+ uint64_t NewBlockCoverage = EF->__sanitizer_get_total_unique_coverage();
+ if (NewBlockCoverage > C->BlockCoverage) {
+ Res = true;
+ C->BlockCoverage = NewBlockCoverage;
+ }
+
+ if (Options.UseIndirCalls &&
+ EF->__sanitizer_get_total_unique_caller_callee_pairs) {
+ uint64_t NewCallerCalleeCoverage =
+ EF->__sanitizer_get_total_unique_caller_callee_pairs();
+ if (NewCallerCalleeCoverage > C->CallerCalleeCoverage) {
+ Res = true;
+ C->CallerCalleeCoverage = NewCallerCalleeCoverage;
+ }
+ }
+
+ if (Options.UseCounters) {
+ uint64_t CounterDelta =
+ EF->__sanitizer_update_counter_bitset_and_clear_counters(
+ C->CounterBitmap.data());
+ if (CounterDelta > 0) {
+ Res = true;
+ C->CounterBitmapBits += CounterDelta;
+ }
+ }
+
+ uint64_t NewPcMapBits = PcMapMergeInto(&C->PCMap);
+ if (NewPcMapBits > C->PcMapBits) {
+ Res = true;
+ C->PcMapBits = NewPcMapBits;
+ }
+
+ uintptr_t *CoverageBuf;
+ uint64_t NewPcBufferLen =
+ EF->__sanitizer_get_coverage_pc_buffer(&CoverageBuf);
+ if (NewPcBufferLen > C->PcBufferLen) {
+ Res = true;
+ C->PcBufferLen = NewPcBufferLen;
+ }
+
+ return Res;
+ }
+};
+
+// Leak detection is expensive, so we first check if there were more mallocs
+// than frees (using the sanitizer malloc hooks) and only then try to call lsan.
+struct MallocFreeTracer {
+ void Start() {
+ Mallocs = 0;
+ Frees = 0;
+ }
+ // Returns true if there were more mallocs than frees.
+ bool Stop() { return Mallocs > Frees; }
+ std::atomic<size_t> Mallocs;
+ std::atomic<size_t> Frees;
+};
+
+static MallocFreeTracer AllocTracer;
+
+void MallocHook(const volatile void *ptr, size_t size) {
+ AllocTracer.Mallocs++;
+}
+void FreeHook(const volatile void *ptr) {
+ AllocTracer.Frees++;
}
Fuzzer::Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options)
@@ -87,11 +152,20 @@ Fuzzer::Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options)
InitializeTraceState();
assert(!F);
F = this;
+ ResetCoverage();
+ IsMyThread = true;
+ if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks)
+ EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);
+}
+
+void Fuzzer::LazyAllocateCurrentUnitData() {
+ if (CurrentUnitData || Options.MaxLen == 0) return;
+ CurrentUnitData = new uint8_t[Options.MaxLen];
}
void Fuzzer::SetDeathCallback() {
- CHECK_WEAK_API_FUNCTION(__sanitizer_set_death_callback);
- __sanitizer_set_death_callback(StaticDeathCallback);
+ CHECK_EXTERNAL_FUNCTION(__sanitizer_set_death_callback);
+ EF->__sanitizer_set_death_callback(StaticDeathCallback);
}
void Fuzzer::StaticDeathCallback() {
@@ -100,18 +174,18 @@ void Fuzzer::StaticDeathCallback() {
}
void Fuzzer::DumpCurrentUnit(const char *Prefix) {
- if (CurrentUnitSize <= kMaxUnitSizeToPrint) {
- PrintHexArray(CurrentUnitData, CurrentUnitSize, "\n");
- PrintASCII(CurrentUnitData, CurrentUnitSize, "\n");
+ if (!CurrentUnitData) return; // Happens when running individual inputs.
+ size_t UnitSize = CurrentUnitSize;
+ if (UnitSize <= kMaxUnitSizeToPrint) {
+ PrintHexArray(CurrentUnitData, UnitSize, "\n");
+ PrintASCII(CurrentUnitData, UnitSize, "\n");
}
- WriteUnitToFileWithPrefix(
- {CurrentUnitData, CurrentUnitData + CurrentUnitSize}, Prefix);
+ WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize},
+ Prefix);
}
NO_SANITIZE_MEMORY
void Fuzzer::DeathCallback() {
- if (!CurrentUnitSize) return;
- Printf("DEATH:\n");
DumpCurrentUnit("crash-");
PrintFinalStats();
}
@@ -133,8 +207,8 @@ void Fuzzer::StaticInterruptCallback() {
void Fuzzer::CrashCallback() {
Printf("==%d== ERROR: libFuzzer: deadly signal\n", GetPid());
- if (__sanitizer_print_stack_trace)
- __sanitizer_print_stack_trace();
+ if (EF->__sanitizer_print_stack_trace)
+ EF->__sanitizer_print_stack_trace();
Printf("NOTE: libFuzzer has rudimentary signal handlers.\n"
" Combine libFuzzer with AddressSanitizer or similar for better "
"crash reports.\n");
@@ -153,6 +227,7 @@ void Fuzzer::InterruptCallback() {
NO_SANITIZE_MEMORY
void Fuzzer::AlarmCallback() {
assert(Options.UnitTimeoutSec > 0);
+ if (!InFuzzingThread()) return;
if (!CurrentUnitSize)
return; // We have not started running units yet.
size_t Seconds =
@@ -168,14 +243,27 @@ void Fuzzer::AlarmCallback() {
DumpCurrentUnit("timeout-");
Printf("==%d== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(),
Seconds);
- if (__sanitizer_print_stack_trace)
- __sanitizer_print_stack_trace();
+ if (EF->__sanitizer_print_stack_trace)
+ EF->__sanitizer_print_stack_trace();
Printf("SUMMARY: libFuzzer: timeout\n");
PrintFinalStats();
_Exit(Options.TimeoutExitCode); // Stop right now.
}
}
+void Fuzzer::RssLimitCallback() {
+ Printf(
+ "==%d== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n",
+ GetPid(), GetPeakRSSMb(), Options.RssLimitMb);
+ Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
+ if (EF->__sanitizer_print_memory_profile)
+ EF->__sanitizer_print_memory_profile(50);
+ DumpCurrentUnit("oom-");
+ Printf("SUMMARY: libFuzzer: out-of-memory\n");
+ PrintFinalStats();
+ _Exit(Options.ErrorExitCode); // Stop right now.
+}
+
void Fuzzer::PrintStats(const char *Where, const char *End) {
size_t ExecPerSec = execPerSec();
if (Options.OutputCSV) {
@@ -185,22 +273,21 @@ void Fuzzer::PrintStats(const char *Where, const char *End) {
Printf("runs,block_cov,bits,cc_cov,corpus,execs_per_sec,tbms,reason\n");
}
Printf("%zd,%zd,%zd,%zd,%zd,%zd,%s\n", TotalNumberOfRuns,
- LastRecordedBlockCoverage, TotalBits(),
- LastRecordedCallerCalleeCoverage, Corpus.size(), ExecPerSec,
- Where);
+ MaxCoverage.BlockCoverage, MaxCoverage.CounterBitmapBits,
+ MaxCoverage.CallerCalleeCoverage, Corpus.size(), ExecPerSec, Where);
}
if (!Options.Verbosity)
return;
Printf("#%zd\t%s", TotalNumberOfRuns, Where);
- if (LastRecordedBlockCoverage)
- Printf(" cov: %zd", LastRecordedBlockCoverage);
- if (LastRecordedPcMapSize)
- Printf(" path: %zd", LastRecordedPcMapSize);
- if (auto TB = TotalBits())
+ if (MaxCoverage.BlockCoverage)
+ Printf(" cov: %zd", MaxCoverage.BlockCoverage);
+ if (MaxCoverage.PcMapBits)
+ Printf(" path: %zd", MaxCoverage.PcMapBits);
+ if (auto TB = MaxCoverage.CounterBitmapBits)
Printf(" bits: %zd", TB);
- if (LastRecordedCallerCalleeCoverage)
- Printf(" indir: %zd", LastRecordedCallerCalleeCoverage);
+ if (MaxCoverage.CallerCalleeCoverage)
+ Printf(" indir: %zd", MaxCoverage.CallerCalleeCoverage);
Printf(" units: %zd exec/s: %zd", Corpus.size(), ExecPerSec);
Printf("%s", End);
}
@@ -265,33 +352,99 @@ void Fuzzer::ShuffleCorpus(UnitVector *V) {
});
}
+// Tries random prefixes of corpus items.
+// Prefix length is chosen according to exponential distribution
+// to sample short lengths much more heavily.
+void Fuzzer::TruncateUnits(std::vector<Unit> *NewCorpus) {
+ size_t MaxCorpusLen = 0;
+ for (const auto &U : Corpus)
+ MaxCorpusLen = std::max(MaxCorpusLen, U.size());
+
+ if (MaxCorpusLen <= 1)
+ return;
+
+ // 50% of exponential distribution is Log[2]/lambda.
+ // Choose lambda so that median is MaxCorpusLen / 2.
+ double Lambda = 2.0 * log(2.0) / static_cast<double>(MaxCorpusLen);
+ std::exponential_distribution<> Dist(Lambda);
+ std::vector<double> Sizes;
+ size_t TruncatePoints = std::max(1ul, TruncateMaxRuns / Corpus.size());
+ Sizes.reserve(TruncatePoints);
+ for (size_t I = 0; I < TruncatePoints; ++I) {
+ Sizes.push_back(Dist(MD.GetRand().Get_mt19937()) + 1);
+ }
+ std::sort(Sizes.begin(), Sizes.end());
+
+ for (size_t S : Sizes) {
+ for (const auto &U : Corpus) {
+ if (S < U.size() && RunOne(U.data(), S)) {
+ Unit U1(U.begin(), U.begin() + S);
+ NewCorpus->push_back(U1);
+ WriteToOutputCorpus(U1);
+ PrintStatusForNewUnit(U1);
+ }
+ }
+ }
+ PrintStats("TRUNC ");
+}
+
void Fuzzer::ShuffleAndMinimize() {
PrintStats("READ ");
std::vector<Unit> NewCorpus;
if (Options.ShuffleAtStartUp)
ShuffleCorpus(&Corpus);
+ if (Options.TruncateUnits) {
+ ResetCoverage();
+ TruncateUnits(&NewCorpus);
+ ResetCoverage();
+ }
+
for (const auto &U : Corpus) {
- if (RunOne(U)) {
+ bool NewCoverage = RunOne(U);
+ if (!Options.PruneCorpus || NewCoverage) {
NewCorpus.push_back(U);
if (Options.Verbosity >= 2)
- Printf("NEW0: %zd L %zd\n", LastRecordedBlockCoverage, U.size());
+ Printf("NEW0: %zd L %zd\n", MaxCoverage.BlockCoverage, U.size());
}
+ TryDetectingAMemoryLeak(U.data(), U.size(),
+ /*DuringInitialCorpusExecution*/ true);
}
Corpus = NewCorpus;
UpdateCorpusDistribution();
for (auto &X : Corpus)
UnitHashesAddedToCorpus.insert(Hash(X));
PrintStats("INITED");
- CheckForMemoryLeaks();
+ if (Corpus.empty()) {
+ Printf("ERROR: no interesting inputs were found. "
+ "Is the code instrumented for coverage? Exiting.\n");
+ exit(1);
+ }
+}
+
+bool Fuzzer::UpdateMaxCoverage() {
+ uintptr_t PrevBufferLen = MaxCoverage.PcBufferLen;
+ bool Res = CoverageController::RecordMax(Options, &MaxCoverage);
+
+ if (Options.PrintNewCovPcs && PrevBufferLen != MaxCoverage.PcBufferLen) {
+ uintptr_t *CoverageBuf;
+ EF->__sanitizer_get_coverage_pc_buffer(&CoverageBuf);
+ assert(CoverageBuf);
+ for (size_t I = PrevBufferLen; I < MaxCoverage.PcBufferLen; ++I) {
+ Printf("%p\n", CoverageBuf[I]);
+ }
+ }
+
+ return Res;
}
bool Fuzzer::RunOne(const uint8_t *Data, size_t Size) {
TotalNumberOfRuns++;
- PrepareCoverageBeforeRun();
+ // TODO(aizatsky): this Reset call seems to be not needed.
+ CoverageController::ResetCounters(Options);
ExecuteCallback(Data, Size);
- bool Res = CheckCoverageAfterRun();
+ bool Res = UpdateMaxCoverage();
auto UnitStopTime = system_clock::now();
auto TimeOfUnit =
@@ -308,118 +461,58 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size) {
return Res;
}
-void Fuzzer::RunOneAndUpdateCorpus(uint8_t *Data, size_t Size) {
+void Fuzzer::RunOneAndUpdateCorpus(const uint8_t *Data, size_t Size) {
if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
return;
- if (Options.OnlyASCII)
- ToASCII(Data, Size);
if (RunOne(Data, Size))
ReportNewCoverage({Data, Data + Size});
}
-// Leak detection is expensive, so we first check if there were more mallocs
-// than frees (using the sanitizer malloc hooks) and only then try to call lsan.
-struct MallocFreeTracer {
- void Start() {
- Mallocs = 0;
- Frees = 0;
- }
- // Returns true if there were more mallocs than frees.
- bool Stop() { return Mallocs > Frees; }
- size_t Mallocs;
- size_t Frees;
-};
-
-static thread_local MallocFreeTracer AllocTracer;
-
-extern "C" {
-void __sanitizer_malloc_hook(void *ptr, size_t size) { AllocTracer.Mallocs++; }
-void __sanitizer_free_hook(void *ptr) { AllocTracer.Frees++; }
-} // extern "C"
+size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
+ assert(InFuzzingThread());
+ *Data = CurrentUnitData;
+ return CurrentUnitSize;
+}
void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
+ assert(InFuzzingThread());
+ LazyAllocateCurrentUnitData();
UnitStartTime = system_clock::now();
// We copy the contents of Unit into a separate heap buffer
// so that we reliably find buffer overflows in it.
std::unique_ptr<uint8_t[]> DataCopy(new uint8_t[Size]);
memcpy(DataCopy.get(), Data, Size);
+ if (CurrentUnitData && CurrentUnitData != Data)
+ memcpy(CurrentUnitData, Data, Size);
AssignTaintLabels(DataCopy.get(), Size);
- CurrentUnitData = DataCopy.get();
CurrentUnitSize = Size;
AllocTracer.Start();
int Res = CB(DataCopy.get(), Size);
(void)Res;
HasMoreMallocsThanFrees = AllocTracer.Stop();
CurrentUnitSize = 0;
- CurrentUnitData = nullptr;
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("%p\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;
- size_t OldPcMapSize = LastRecordedPcMapSize;
- PcMapMergeCurrentToCombined();
- size_t NewPcMapSize = PcMapCombinedSize();
- LastRecordedPcMapSize = NewPcMapSize;
- if (NewPcMapSize > OldPcMapSize)
- return true;
- if (Options.UseCounters)
- NumNewBits = __sanitizer_update_counter_bitset_and_clear_counters(
- CounterBitmap.data());
- return NewCoverage > OldCoverage ||
- NewCallerCalleeCoverage > OldCallerCalleeCoverage || NumNewBits;
+std::string Fuzzer::Coverage::DebugString() const {
+ std::string Result =
+ std::string("Coverage{") + "BlockCoverage=" +
+ std::to_string(BlockCoverage) + " CallerCalleeCoverage=" +
+ std::to_string(CallerCalleeCoverage) + " CounterBitmapBits=" +
+ std::to_string(CounterBitmapBits) + " PcMapBits=" +
+ std::to_string(PcMapBits) + "}";
+ return Result;
}
void Fuzzer::WriteToOutputCorpus(const Unit &U) {
+ if (Options.OnlyASCII)
+ assert(IsASCII(U));
if (Options.OutputCorpus.empty())
return;
std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
WriteToFile(U, Path);
if (Options.Verbosity >= 2)
Printf("Written to %s\n", Path.c_str());
- assert(!Options.OnlyASCII || IsASCII(U));
}
void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) {
@@ -491,9 +584,10 @@ UnitVector Fuzzer::FindExtraUnits(const UnitVector &Initial,
PrintStats(Stat);
size_t NewSize = Corpus.size();
+ assert(NewSize <= OldSize);
Res.swap(Corpus);
- if (NewSize == OldSize)
+ if (NewSize + 5 >= OldSize)
break;
OldSize = NewSize;
}
@@ -527,35 +621,20 @@ void Fuzzer::Merge(const std::vector<std::string> &Corpora) {
Printf("=== Merge: written %zd units\n", Res.size());
}
-// Tries to call lsan, and if there are leaks exits. We call this right after
-// the initial corpus was read because if there are leaky inputs in the corpus
-// further fuzzing will likely hit OOMs.
-void Fuzzer::CheckForMemoryLeaks() {
- if (!Options.DetectLeaks) return;
- if (!__lsan_do_recoverable_leak_check)
- return;
- if (__lsan_do_recoverable_leak_check()) {
- Printf("==%d== ERROR: libFuzzer: initial corpus triggers memory leaks.\n"
- "Exiting now. Use -detect_leaks=0 to disable leak detection here.\n"
- "LeakSanitizer will still check for leaks at the process exit.\n",
- GetPid());
- PrintFinalStats();
- _Exit(Options.ErrorExitCode);
- }
-}
-
// Tries detecting a memory leak on the particular input that we have just
// executed before calling this function.
-void Fuzzer::TryDetectingAMemoryLeak(uint8_t *Data, size_t Size) {
+void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
+ bool DuringInitialCorpusExecution) {
if (!HasMoreMallocsThanFrees) return; // mallocs==frees, a leak is unlikely.
if (!Options.DetectLeaks) return;
- if (!&__lsan_enable || !&__lsan_disable || !__lsan_do_recoverable_leak_check)
+ if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) ||
+ !(EF->__lsan_do_recoverable_leak_check))
return; // No lsan.
// Run the target once again, but with lsan disabled so that if there is
// a real leak we do not report it twice.
- __lsan_disable();
- RunOneAndUpdateCorpus(Data, Size);
- __lsan_enable();
+ EF->__lsan_disable();
+ RunOne(Data, Size);
+ EF->__lsan_enable();
if (!HasMoreMallocsThanFrees) return; // a leak is unlikely.
if (NumberOfLeakDetectionAttempts++ > 1000) {
Options.DetectLeaks = false;
@@ -568,8 +647,10 @@ void Fuzzer::TryDetectingAMemoryLeak(uint8_t *Data, size_t Size) {
}
// Now perform the actual lsan pass. This is expensive and we must ensure
// we don't call it too often.
- if (__lsan_do_recoverable_leak_check()) { // Leak is found, report it.
- CurrentUnitData = Data;
+ if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it.
+ if (DuringInitialCorpusExecution)
+ Printf("\nINFO: a leak has been found in the initial corpus.\n\n");
+ Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n");
CurrentUnitSize = Size;
DumpCurrentUnit("leak-");
PrintFinalStats();
@@ -578,30 +659,30 @@ void Fuzzer::TryDetectingAMemoryLeak(uint8_t *Data, size_t Size) {
}
void Fuzzer::MutateAndTestOne() {
+ LazyAllocateCurrentUnitData();
MD.StartMutationSequence();
auto &U = ChooseUnitToMutate();
- MutateInPlaceHere.resize(Options.MaxLen);
+ assert(CurrentUnitData);
size_t Size = U.size();
assert(Size <= Options.MaxLen && "Oversized Unit");
- memcpy(MutateInPlaceHere.data(), U.data(), Size);
+ memcpy(CurrentUnitData, U.data(), Size);
for (int i = 0; i < Options.MutateDepth; i++) {
size_t NewSize = 0;
- if (LLVMFuzzerCustomMutator)
- NewSize = LLVMFuzzerCustomMutator(MutateInPlaceHere.data(), Size,
- Options.MaxLen, MD.GetRand().Rand());
- else
- NewSize = MD.Mutate(MutateInPlaceHere.data(), Size, Options.MaxLen);
+ NewSize = MD.Mutate(CurrentUnitData, Size, Options.MaxLen);
assert(NewSize > 0 && "Mutator returned empty unit");
assert(NewSize <= Options.MaxLen &&
"Mutator return overisized unit");
Size = NewSize;
+ if (Options.OnlyASCII)
+ ToASCII(CurrentUnitData, Size);
if (i == 0)
StartTraceRecording();
- RunOneAndUpdateCorpus(MutateInPlaceHere.data(), Size);
+ RunOneAndUpdateCorpus(CurrentUnitData, Size);
StopTraceRecording();
- TryDetectingAMemoryLeak(MutateInPlaceHere.data(), Size);
+ TryDetectingAMemoryLeak(CurrentUnitData, Size,
+ /*DuringInitialCorpusExecution*/ false);
}
}
@@ -616,9 +697,9 @@ size_t Fuzzer::ChooseUnitIdxToMutate() {
}
void Fuzzer::ResetCoverage() {
- CHECK_WEAK_API_FUNCTION(__sanitizer_reset_coverage);
- __sanitizer_reset_coverage();
- CounterBitmap.clear();
+ CoverageController::Reset();
+ MaxCoverage.Reset();
+ CoverageController::Prepare(Options, &MaxCoverage);
}
// Experimental search heuristic: drilling.
@@ -704,3 +785,11 @@ void Fuzzer::UpdateCorpusDistribution() {
}
} // namespace fuzzer
+
+extern "C" {
+
+size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+ assert(fuzzer::F);
+ return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize);
+}
+} // extern "C"
diff --git a/chromium/third_party/libFuzzer/src/FuzzerMain.cpp b/chromium/third_party/libFuzzer/src/FuzzerMain.cpp
index 0d5c1132ea5..55f1687b5f0 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerMain.cpp
+++ b/chromium/third_party/libFuzzer/src/FuzzerMain.cpp
@@ -15,12 +15,8 @@
extern "C" {
// This function should be defined by the user.
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
-// This function may optionally be defined by the user.
-__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
} // extern "C"
int main(int argc, char **argv) {
- if (LLVMFuzzerInitialize)
- LLVMFuzzerInitialize(&argc, &argv);
- return fuzzer::FuzzerDriver(argc, argv, LLVMFuzzerTestOneInput);
+ return fuzzer::FuzzerDriver(&argc, &argv, LLVMFuzzerTestOneInput);
}
diff --git a/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp b/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp
index bc10f1af49f..bd82c0dee59 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp
+++ b/chromium/third_party/libFuzzer/src/FuzzerMutate.cpp
@@ -18,21 +18,34 @@ namespace fuzzer {
const size_t Dictionary::kMaxDictSize;
-MutationDispatcher::Mutator MutationDispatcher::Mutators[] = {
- {&MutationDispatcher::Mutate_EraseByte, "EraseByte"},
- {&MutationDispatcher::Mutate_InsertByte, "InsertByte"},
- {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"},
- {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"},
- {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"},
- {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"},
- {&MutationDispatcher::Mutate_CrossOver, "CrossOver"},
- {&MutationDispatcher::Mutate_AddWordFromManualDictionary,
- "AddFromManualDict"},
- {&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary,
- "AddFromTempAutoDict"},
- {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
- "AddFromPersAutoDict"},
-};
+MutationDispatcher::MutationDispatcher(Random &Rand) : Rand(Rand) {
+ DefaultMutators.insert(
+ DefaultMutators.begin(),
+ {
+ {&MutationDispatcher::Mutate_EraseByte, "EraseByte"},
+ {&MutationDispatcher::Mutate_InsertByte, "InsertByte"},
+ {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"},
+ {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"},
+ {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"},
+ {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"},
+ {&MutationDispatcher::Mutate_CrossOver, "CrossOver"},
+ {&MutationDispatcher::Mutate_AddWordFromManualDictionary,
+ "AddFromManualDict"},
+ {&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary,
+ "AddFromTempAutoDict"},
+ {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
+ "AddFromPersAutoDict"},
+ });
+
+ if (EF->LLVMFuzzerCustomMutator)
+ Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
+ else
+ Mutators = DefaultMutators;
+
+ if (EF->LLVMFuzzerCustomCrossOver)
+ Mutators.push_back(
+ {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"});
+}
static char FlipRandomBit(char X, Random &Rand) {
int Bit = Rand(8);
@@ -52,6 +65,30 @@ static char RandCh(Random &Rand) {
return Special[Rand(sizeof(Special) - 1)];
}
+size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand());
+}
+
+size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (!Corpus || Corpus->size() < 2 || Size == 0)
+ return 0;
+ size_t Idx = Rand(Corpus->size());
+ const Unit &Other = (*Corpus)[Idx];
+ if (Other.empty())
+ return 0;
+ MutateInPlaceHere.resize(MaxSize);
+ auto &U = MutateInPlaceHere;
+ size_t NewSize = EF->LLVMFuzzerCustomCrossOver(
+ Data, Size, Other.data(), Other.size(), U.data(), U.size(), Rand.Rand());
+ if (!NewSize)
+ return 0;
+ assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit");
+ memcpy(Data, U.data(), NewSize);
+ return NewSize;
+}
+
size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
size_t MaxSize) {
assert(Size);
@@ -230,8 +267,19 @@ void MutationDispatcher::PrintMutationSequence() {
}
}
-// Mutates Data in place, returns new size.
size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+ return MutateImpl(Data, Size, MaxSize, Mutators);
+}
+
+size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ return MutateImpl(Data, Size, MaxSize, DefaultMutators);
+}
+
+// Mutates Data in place, returns new size.
+size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,
+ size_t MaxSize,
+ const std::vector<Mutator> &Mutators) {
assert(MaxSize > 0);
assert(Size <= MaxSize);
if (Size == 0) {
@@ -244,9 +292,7 @@ size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t 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 NumMutators = sizeof(Mutators) / sizeof(Mutators[0]);
- size_t MutatorIdx = Rand(NumMutators);
- auto M = Mutators[MutatorIdx];
+ auto M = Mutators[Rand(Mutators.size())];
size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);
if (NewSize) {
CurrentMutatorSequence.push_back(M);
diff --git a/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp b/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp
index 1afd6e392fd..46c43d0c17f 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp
+++ b/chromium/third_party/libFuzzer/src/FuzzerTracePC.cpp
@@ -15,45 +15,57 @@
#include "FuzzerInternal.h"
namespace fuzzer {
-static const size_t kMapSizeInBits = 65371; // Prime.
-static const size_t kMapSizeInBitsAligned = 65536; // 2^16
-static const size_t kBitsInWord =(sizeof(uintptr_t) * 8);
-static const size_t kMapSizeInWords = kMapSizeInBitsAligned / kBitsInWord;
-static uintptr_t CurrentMap[kMapSizeInWords] __attribute__((aligned(512)));
-static uintptr_t CombinedMap[kMapSizeInWords] __attribute__((aligned(512)));
-static size_t CombinedMapSize;
+
+void PcCoverageMap::Reset() { memset(Map, 0, sizeof(Map)); }
+
+void PcCoverageMap::Update(uintptr_t Addr) {
+ uintptr_t Idx = Addr % kMapSizeInBits;
+ uintptr_t WordIdx = Idx / kBitsInWord;
+ uintptr_t BitIdx = Idx % kBitsInWord;
+ Map[WordIdx] |= 1UL << BitIdx;
+}
+
+size_t PcCoverageMap::MergeFrom(const PcCoverageMap &Other) {
+ uintptr_t Res = 0;
+ for (size_t i = 0; i < kMapSizeInWords; i++)
+ Res += __builtin_popcountl(Map[i] |= Other.Map[i]);
+ return Res;
+}
+
+static PcCoverageMap CurrentMap;
static thread_local uintptr_t Prev;
void PcMapResetCurrent() {
if (Prev) {
Prev = 0;
- memset(CurrentMap, 0, sizeof(CurrentMap));
+ CurrentMap.Reset();
}
}
-void PcMapMergeCurrentToCombined() {
- if (!Prev) return;
- uintptr_t Res = 0;
- for (size_t i = 0; i < kMapSizeInWords; i++)
- Res += __builtin_popcountl(CombinedMap[i] |= CurrentMap[i]);
- CombinedMapSize = Res;
+size_t PcMapMergeInto(PcCoverageMap *Map) {
+ if (!Prev)
+ return 0;
+ return Map->MergeFrom(CurrentMap);
}
-size_t PcMapCombinedSize() { return CombinedMapSize; }
-
static void HandlePC(uint32_t PC) {
// We take 12 bits of PC and mix it with the previous PCs.
uintptr_t Next = (Prev << 5) ^ (PC & 4095);
- uintptr_t Idx = Next % kMapSizeInBits;
- uintptr_t WordIdx = Idx / kBitsInWord;
- uintptr_t BitIdx = Idx % kBitsInWord;
- CurrentMap[WordIdx] |= 1UL << BitIdx;
+ CurrentMap.Update(Next);
Prev = Next;
}
} // namespace fuzzer
-extern "C" void __sanitizer_cov_trace_pc() {
+extern "C" {
+void __sanitizer_cov_trace_pc() {
fuzzer::HandlePC(static_cast<uint32_t>(
reinterpret_cast<uintptr_t>(__builtin_return_address(0))));
}
+
+void __sanitizer_cov_trace_pc_indir(int *) {
+ // Stub to allow linking with code built with
+ // -fsanitize=indirect-calls,trace-pc.
+ // This isn't used currently.
+}
+}
diff --git a/chromium/third_party/libFuzzer/src/FuzzerTracePC.h b/chromium/third_party/libFuzzer/src/FuzzerTracePC.h
new file mode 100644
index 00000000000..47280ba7faa
--- /dev/null
+++ b/chromium/third_party/libFuzzer/src/FuzzerTracePC.h
@@ -0,0 +1,37 @@
+//===- FuzzerTracePC.h - INTERNAL - Path tracer. --------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Trace PCs.
+// This module implements __sanitizer_cov_trace_pc, a callback required
+// for -fsanitize-coverage=trace-pc instrumentation.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_TRACE_PC_H
+#define LLVM_FUZZER_TRACE_PC_H
+
+namespace fuzzer {
+struct PcCoverageMap {
+ static const size_t kMapSizeInBits = 65371; // Prime.
+ static const size_t kMapSizeInBitsAligned = 65536; // 2^16
+ static const size_t kBitsInWord = (sizeof(uintptr_t) * 8);
+ static const size_t kMapSizeInWords = kMapSizeInBitsAligned / kBitsInWord;
+
+ void Reset();
+ inline void Update(uintptr_t Addr);
+ size_t MergeFrom(const PcCoverageMap &Other);
+
+ uintptr_t Map[kMapSizeInWords] __attribute__((aligned(512)));
+};
+
+// Clears the current PC Map.
+void PcMapResetCurrent();
+// Merges the current PC Map into the combined one, and clears the former.
+size_t PcMapMergeInto(PcCoverageMap *Map);
+}
+
+#endif
diff --git a/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp b/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp
index 8123407e98c..3ee69e43aba 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp
+++ b/chromium/third_party/libFuzzer/src/FuzzerTraceState.cpp
@@ -174,15 +174,9 @@ static bool RecordingMemcmp = false;
class TraceState {
public:
- TraceState(MutationDispatcher &MD, const Fuzzer::FuzzingOptions &Options,
- uint8_t **CurrentUnitData, size_t *CurrentUnitSize)
- : MD(MD), Options(Options), CurrentUnitData(CurrentUnitData),
- CurrentUnitSize(CurrentUnitSize) {
- // 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;
- }
+ TraceState(MutationDispatcher &MD, const Fuzzer::FuzzingOptions &Options,
+ const Fuzzer *F)
+ : MD(MD), Options(Options), F(F) {}
LabelRange GetLabelRange(dfsan_label L);
void DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
@@ -201,12 +195,13 @@ class TraceState {
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);
+ size_t DataSize);
int TryToAddDesiredData(const uint8_t *PresentData,
const uint8_t *DesiredData, size_t DataSize);
void StartTraceRecording() {
- if (!Options.UseTraces && !Options.UseMemcmp) return;
+ if (!Options.UseTraces && !Options.UseMemcmp)
+ return;
RecordingTraces = Options.UseTraces;
RecordingMemcmp = Options.UseMemcmp;
NumMutations = 0;
@@ -293,14 +288,11 @@ class TraceState {
size_t LastDfsanLabel = 0;
MutationDispatcher &MD;
const Fuzzer::FuzzingOptions &Options;
- uint8_t **CurrentUnitData;
- size_t *CurrentUnitSize;
+ const Fuzzer *F;
std::map<Word, 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];
@@ -316,7 +308,7 @@ void TraceState::DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
uint64_t Arg1, uint64_t Arg2, dfsan_label L1,
dfsan_label L2) {
assert(ReallyHaveDFSan());
- if (!RecordingTraces || !IsMyThread) return;
+ if (!RecordingTraces || !F->InFuzzingThread()) return;
if (L1 == 0 && L2 == 0)
return; // Not actionable.
if (L1 != 0 && L2 != 0)
@@ -346,7 +338,7 @@ void TraceState::DFSanMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
dfsan_label L2) {
assert(ReallyHaveDFSan());
- if (!RecordingMemcmp || !IsMyThread) return;
+ if (!RecordingMemcmp || !F->InFuzzingThread()) return;
if (L1 == 0 && L2 == 0)
return; // Not actionable.
if (L1 != 0 && L2 != 0)
@@ -365,7 +357,7 @@ void TraceState::DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits,
uint64_t Val, size_t NumCases,
uint64_t *Cases, dfsan_label L) {
assert(ReallyHaveDFSan());
- if (!RecordingTraces || !IsMyThread) return;
+ if (!RecordingTraces || !F->InFuzzingThread()) return;
if (!L) return; // Not actionable.
LabelRange LR = GetLabelRange(L);
size_t ValSize = ValSizeInBits / 8;
@@ -391,15 +383,17 @@ void TraceState::DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits,
int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
size_t DataSize) {
if (NumMutations >= kMaxMutations || !WantToHandleOneMoreMutation()) return 0;
+ const uint8_t *UnitData;
+ auto UnitSize = F->GetCurrentUnitInFuzzingThead(&UnitData);
int Res = 0;
- const uint8_t *Beg = *CurrentUnitData;
- const uint8_t *End = Beg + *CurrentUnitSize;
+ const uint8_t *Beg = UnitData;
+ const uint8_t *End = Beg + UnitSize;
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 < *CurrentUnitSize);
+ assert(Pos < UnitSize);
AddMutation(Pos, DataSize, DesiredData);
AddMutation(Pos, DataSize, DesiredData + 1);
AddMutation(Pos, DataSize, DesiredData - 1);
@@ -412,15 +406,17 @@ int TraceState::TryToAddDesiredData(const uint8_t *PresentData,
const uint8_t *DesiredData,
size_t DataSize) {
if (NumMutations >= kMaxMutations || !WantToHandleOneMoreMutation()) return 0;
+ const uint8_t *UnitData;
+ auto UnitSize = F->GetCurrentUnitInFuzzingThead(&UnitData);
int Res = 0;
- const uint8_t *Beg = *CurrentUnitData;
- const uint8_t *End = Beg + *CurrentUnitSize;
+ const uint8_t *Beg = UnitData;
+ const uint8_t *End = Beg + UnitSize;
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 < *CurrentUnitSize);
+ assert(Pos < UnitSize);
AddMutation(Pos, DataSize, DesiredData);
Res++;
}
@@ -429,7 +425,7 @@ int TraceState::TryToAddDesiredData(const uint8_t *PresentData,
void TraceState::TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
uint64_t Arg1, uint64_t Arg2) {
- if (!RecordingTraces || !IsMyThread) return;
+ if (!RecordingTraces || !F->InFuzzingThread()) return;
if ((CmpType == ICMP_EQ || CmpType == ICMP_NE) && Arg1 == Arg2)
return; // No reason to mutate.
int Added = 0;
@@ -445,7 +441,7 @@ void TraceState::TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
void TraceState::TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
const uint8_t *Data2) {
- if (!RecordingMemcmp || !IsMyThread) return;
+ if (!RecordingMemcmp || !F->InFuzzingThread()) return;
CmpSize = std::min(CmpSize, Word::GetMaxSize());
int Added2 = TryToAddDesiredData(Data1, Data2, CmpSize);
int Added1 = TryToAddDesiredData(Data2, Data1, CmpSize);
@@ -460,7 +456,7 @@ void TraceState::TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
void TraceState::TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits,
uint64_t Val, size_t NumCases,
uint64_t *Cases) {
- if (!RecordingTraces || !IsMyThread) return;
+ if (!RecordingTraces || !F->InFuzzingThread()) return;
size_t ValSize = ValSizeInBits / 8;
bool TryShort = IsTwoByteData(Val);
for (size_t i = 0; i < NumCases; i++)
@@ -499,7 +495,7 @@ void Fuzzer::AssignTaintLabels(uint8_t *Data, size_t Size) {
void Fuzzer::InitializeTraceState() {
if (!Options.UseTraces && !Options.UseMemcmp) return;
- TS = new TraceState(MD, Options, &CurrentUnitData, &CurrentUnitSize);
+ TS = new TraceState(MD, Options, this);
}
static size_t InternalStrnlen(const char *S, size_t MaxLen) {
diff --git a/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp b/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp
index d5335616a83..c2ae94c4d3d 100644
--- a/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp
+++ b/chromium/third_party/libFuzzer/src/FuzzerUtil.cpp
@@ -14,12 +14,16 @@
#include <iomanip>
#include <sys/resource.h>
#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
#include <cassert>
+#include <chrono>
#include <cstring>
#include <signal.h>
#include <sstream>
#include <unistd.h>
#include <errno.h>
+#include <thread>
namespace fuzzer {
@@ -109,11 +113,36 @@ void SetSigIntHandler() { SetSigaction(SIGINT, InterruptHandler); }
void SetSigTermHandler() { SetSigaction(SIGTERM, InterruptHandler); }
int NumberOfCpuCores() {
- FILE *F = popen("nproc", "r");
- int N = 0;
- if (fscanf(F, "%d", &N) != 1)
+ const char *CmdLine = nullptr;
+ if (LIBFUZZER_LINUX) {
+ CmdLine = "nproc";
+ } else if (LIBFUZZER_APPLE) {
+ CmdLine = "sysctl -n hw.ncpu";
+ } else {
+ assert(0 && "NumberOfCpuCores() is not implemented for your platform");
+ }
+
+ FILE *F = popen(CmdLine, "r");
+ int N = 1;
+ if (!F || fscanf(F, "%d", &N) != 1) {
+ Printf("WARNING: Failed to parse output of command \"%s\" in %s(). "
+ "Assuming CPU count of 1.\n",
+ CmdLine, __func__);
+ N = 1;
+ }
+
+ if (pclose(F)) {
+ Printf("WARNING: Executing command \"%s\" failed in %s(). "
+ "Assuming CPU count of 1.\n",
+ CmdLine, __func__);
+ N = 1;
+ }
+ if (N < 1) {
+ Printf("WARNING: Reported CPU count (%d) from command \"%s\" was invalid "
+ "in %s(). Assuming CPU count of 1.\n",
+ N, CmdLine, __func__);
N = 1;
- fclose(F);
+ }
return N;
}
@@ -135,9 +164,11 @@ bool ToASCII(uint8_t *Data, size_t Size) {
return Changed;
}
-bool IsASCII(const Unit &U) {
- for (auto X : U)
- if (!(isprint(X) || isspace(X))) return false;
+bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); }
+
+bool IsASCII(const uint8_t *Data, size_t Size) {
+ for (size_t i = 0; i < Size; i++)
+ if (!(isprint(Data[i]) || isspace(Data[i]))) return false;
return true;
}
@@ -214,8 +245,11 @@ bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units) {
return true;
}
-int GetPid() { return getpid(); }
+void SleepSeconds(int Seconds) {
+ std::this_thread::sleep_for(std::chrono::seconds(Seconds));
+}
+int GetPid() { return getpid(); }
std::string Base64(const Unit &U) {
static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -249,7 +283,15 @@ size_t GetPeakRSSMb() {
struct rusage usage;
if (getrusage(RUSAGE_SELF, &usage))
return 0;
- return usage.ru_maxrss >> 10;
+ if (LIBFUZZER_LINUX) {
+ // ru_maxrss is in KiB
+ return usage.ru_maxrss >> 10;
+ } else if (LIBFUZZER_APPLE) {
+ // ru_maxrss is in bytes
+ return usage.ru_maxrss >> 20;
+ }
+ assert(0 && "GetPeakRSSMb() is not implemented for your platform");
+ return 0;
}
} // namespace fuzzer
diff --git a/chromium/third_party/libFuzzer/src/afl/afl_driver.cpp b/chromium/third_party/libFuzzer/src/afl/afl_driver.cpp
new file mode 100644
index 00000000000..228317ca9e3
--- /dev/null
+++ b/chromium/third_party/libFuzzer/src/afl/afl_driver.cpp
@@ -0,0 +1,111 @@
+//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===//
+
+/* This file allows to fuzz libFuzzer-style target functions
+ (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode.
+
+Usage:
+################################################################################
+cat << EOF > test_fuzzer.cc
+#include <stdint.h>
+#include <stddef.h>
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (size > 0 && data[0] == 'H')
+ if (size > 1 && data[1] == 'I')
+ if (size > 2 && data[2] == '!')
+ __builtin_trap();
+ return 0;
+}
+EOF
+# Build your target with -fsanitize-coverage=trace-pc using fresh clang.
+clang -g -fsanitize-coverage=trace-pc test_fuzzer.cc -c
+# Build afl-llvm-rt.o.c from the AFL distribution.
+clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c
+# Build this file, link it with afl-llvm-rt.o.o and the target code.
+clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
+# Run AFL:
+rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
+$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
+################################################################################
+*/
+#include <assert.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// libFuzzer interface is thin, so we don't include any libFuzzer headers.
+extern "C" {
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
+}
+
+// Notify AFL about persistent mode.
+static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
+extern "C" int __afl_persistent_loop(unsigned int);
+static volatile char suppress_warning2 = AFL_PERSISTENT[0];
+
+// Notify AFL about deferred forkserver.
+static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
+extern "C" void __afl_manual_init();
+static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
+
+// Input buffer.
+static const size_t kMaxAflInputSize = 1 << 20;
+static uint8_t AflInputBuf[kMaxAflInputSize];
+
+// If the user asks us to duplicate stderr, then do it.
+static void maybe_duplicate_stderr() {
+ char* stderr_duplicate_filename =
+ getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
+
+ if (!stderr_duplicate_filename)
+ return;
+
+ FILE* stderr_duplicate_stream =
+ freopen(stderr_duplicate_filename, "a+", stderr);
+
+ if (!stderr_duplicate_stream) {
+ fprintf(stderr,
+ "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME"
+ );
+ abort();
+ }
+}
+
+int main(int argc, char **argv) {
+ fprintf(stderr, "Running in AFl-fuzz mode\nUsage:\n"
+ "afl-fuzz [afl-flags] %s [N] "
+ "-- run N fuzzing iterations before "
+ "re-spawning the process (default: 1000)\n",
+ argv[0]);
+ if (LLVMFuzzerInitialize)
+ LLVMFuzzerInitialize(&argc, &argv);
+ // Do any other expensive one-time initialization here.
+
+ maybe_duplicate_stderr();
+
+ __afl_manual_init();
+
+ int N = 1000;
+ if (argc >= 2)
+ N = atoi(argv[1]);
+ assert(N > 0);
+ while (__afl_persistent_loop(N)) {
+ ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
+ if (n_read > 0) {
+ // Copy AflInputBuf into a separate buffer to let asan find buffer
+ // overflows. Don't use unique_ptr/etc to avoid extra dependencies.
+ uint8_t *copy = new uint8_t[n_read];
+ memcpy(copy, AflInputBuf, n_read);
+ LLVMFuzzerTestOneInput(copy, n_read);
+ delete[] copy;
+ }
+ }
+}