Import libfuzzer-sys Rust Crate

Bug: 147140513
Test: N/A
Change-Id: I3be474604ebb26642b8f7f536ee3e77bd8ce2469
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..b4b4ba8
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,5 @@
+{
+  "git": {
+    "sha1": "104fca0a97b7172a0f2b88c4629f5473f7c84fe1"
+  }
+}
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
new file mode 100644
index 0000000..47e2bf2
--- /dev/null
+++ b/.github/workflows/rust.yml
@@ -0,0 +1,24 @@
+name: Rust
+
+on: [push, pull_request]
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v1
+
+    - name: Install nightly Rust
+      run: |
+        rustup toolchain install nightly
+        rustup default nightly
+
+    - name: Check rustfmt
+      run: |
+        rustup component add rustfmt --toolchain stable
+        cargo +stable fmt --all -- --check
+
+    - name: Run tests
+      run: ./ci/script.sh
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a9d37c5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+target
+Cargo.lock
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..e8a8486
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,120 @@
+## Unreleased
+
+Released YYYY-MM-DD.
+
+### Added
+
+* TODO (or remove section if none)
+
+### Changed
+
+* TODO (or remove section if none)
+
+### Deprecated
+
+* TODO (or remove section if none)
+
+### Removed
+
+* TODO (or remove section if none)
+
+### Fixed
+
+* TODO (or remove section if none)
+
+### Security
+
+* TODO (or remove section if none)
+
+--------------------------------------------------------------------------------
+
+## 0.3.4
+
+Released 2020-08-22.
+
+### Changed
+
+* Updated `arbitrary` dependency to 0.4.6
+
+--------------------------------------------------------------------------------
+
+## 0.3.3
+
+Released 2020-07-27.
+
+### Changed
+
+* Upgraded libfuzzer to commit
+  [4a4cafa](https://github.com/llvm/llvm-project/commit/4a4cafabc9067fced5890a245b03ef5897ad988b).
+
+  Notably, this pulls in [the new Entropic engine for
+  libFuzzer](https://mboehme.github.io/paper/FSE20.Entropy.pdf), which should
+  boost fuzzing efficiency when enabled. You can enable Entropic by passing
+  `-entropic=1` to your built fuzz targets (although, note that it is still
+  labeled "experimental").
+
+--------------------------------------------------------------------------------
+
+## 0.3.2
+
+Released 2020-03-18.
+
+### Changed
+
+* Upgraded the `arbitrary` dependency re-export to version 0.4.1.
+
+--------------------------------------------------------------------------------
+
+## 0.3.1
+
+Released 2020-02-27.
+
+### Changed
+
+* Fixed a fuzzing performance issue where libfuzzer could unnecessarily spend
+  time exploring all the ways that an `Arbitrary` implementation could fail to
+  construct an instance of itself because the fuzzer provided too few bytes. See
+  https://github.com/rust-fuzz/libfuzzer/issues/59 for details.
+
+--------------------------------------------------------------------------------
+
+## 0.3.0
+
+Released 2019-01-22.
+
+### Changed
+
+* Now works with and re-exports `arbitrary` versions 0.4.x.
+
+--------------------------------------------------------------------------------
+
+## 0.2.1
+
+Released 2019-01-16.
+
+### Added
+
+* Added support for the `CUSTOM_LIBFUZZER_STD_CXX=<lib>` environment variable
+  during builds that already use a custom libFuzzer checkout with
+  `CUSTOM_LIBFUZZER_PATH`. This allows you to explicitly choose to link LLVM or
+  GNU C++ standard libraries.
+
+--------------------------------------------------------------------------------
+
+## 0.2.0
+
+Released 2020-01-14.
+
+### Changed
+
+* Using `arbitrary` 0.3.x now. It is re-exported as `libfuzzer_sys::arbitrary`.
+
+### Added
+
+* You can enable support for `#[derive(Arbitrary)]` with the
+  `"arbitrary-derive"` cargo feature. This is a synonym for the `arbitrary`
+  crate's `"derive"` cargo feature.
+
+--------------------------------------------------------------------------------
+
+## 0.1.0
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..f057f0c
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,28 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+edition = "2018"
+name = "libfuzzer-sys"
+version = "0.3.4"
+authors = ["The rust-fuzz Project Developers"]
+description = "A wrapper around LLVM's libFuzzer runtime."
+readme = "./README.md"
+license = "MIT/Apache-2.0/NCSA"
+repository = "https://github.com/rust-fuzz/libfuzzer"
+[dependencies.arbitrary]
+version = "0.4.6"
+[build-dependencies.cc]
+version = "1.0"
+
+[features]
+arbitrary-derive = ["arbitrary/derive"]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..b2aeb4a
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,18 @@
+[package]
+authors = ["The rust-fuzz Project Developers"]
+description = "A wrapper around LLVM's libFuzzer runtime."
+edition = "2018"
+license = "MIT/Apache-2.0/NCSA"
+name = "libfuzzer-sys"
+readme = "./README.md"
+repository = "https://github.com/rust-fuzz/libfuzzer"
+version = "0.3.4"
+
+[dependencies]
+arbitrary = "0.4.6"
+
+[build-dependencies]
+cc = "1.0"
+
+[features]
+arbitrary-derive = ["arbitrary/derive"]
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..da469dc
--- /dev/null
+++ b/README.md
@@ -0,0 +1,73 @@
+# The `libfuzzer-sys` Crate
+
+Barebones wrapper around LLVM's libFuzzer runtime library.
+
+The CPP parts are extracted from compiler-rt git repository with `git filter-branch`.
+
+libFuzzer relies on LLVM sanitizer support. The Rust compiler has built-in support for LLVM sanitizer support, for now, it's limited to Linux. As a result, `libfuzzer-sys` only works on Linux.
+
+## Usage
+
+### Use `cargo fuzz`!
+
+[The recommended way to use this crate with `cargo fuzz`!][cargo-fuzz].
+
+[cargo-fuzz]: https://github.com/rust-fuzz/cargo-fuzz
+
+### Manual Usage
+
+This crate can also be used manually as following:
+
+First create a new cargo project:
+
+```
+$ cargo new --bin fuzzed
+$ cd fuzzed
+```
+
+Then add a dependency on the `fuzzer-sys` crate and your own crate:
+
+```toml
+[dependencies]
+libfuzzer-sys = "0.3.0"
+your_crate = { path = "../path/to/your/crate" }
+```
+
+Change the `fuzzed/src/main.rs` to fuzz your code:
+
+```rust
+#![no_main]
+
+use libfuzzer_sys::fuzz_target;
+
+fuzz_target!(|data: &[u8]| {
+    // code to fuzz goes here
+});
+```
+
+Build by running the following command:
+
+```sh
+$ cargo rustc -- \
+    -C passes='sancov' \
+    -C llvm-args='-sanitizer-coverage-level=3' \
+    -Z sanitizer=address
+```
+
+And finally, run the fuzzer:
+
+```sh
+$ ./target/debug/fuzzed
+```
+
+## Updating libfuzzer from upstream
+
+```
+./update-libfuzzer.sh <github.com/llvm-mirror/llvm-project SHA1>
+```
+
+## License
+
+All files in `libfuzzer` directory are licensed NCSA.
+
+Everything else is dual-licensed Apache 2.0 and MIT.
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..21c57c1
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,35 @@
+fn main() {
+    if let Ok(custom) = ::std::env::var("CUSTOM_LIBFUZZER_PATH") {
+        let custom_lib_path = ::std::path::PathBuf::from(&custom);
+        let custom_lib_dir = custom_lib_path.parent().unwrap().to_string_lossy();
+
+        let custom_lib_name = custom_lib_path.file_stem().unwrap().to_string_lossy();
+        let custom_lib_name = custom_lib_name.trim_start_matches("lib");
+
+        println!("cargo:rustc-link-search=native={}", custom_lib_dir);
+        println!("cargo:rustc-link-lib=static={}", custom_lib_name);
+
+        match std::env::var("CUSTOM_LIBFUZZER_STD_CXX") {
+            // Default behavior for backwards compat.
+            Err(_) => println!("cargo:rustc-link-lib=stdc++"),
+            Ok(s) if s == "none" => (),
+            Ok(s) => println!("cargo:rustc-link-lib={}", s),
+        }
+    } else {
+        let mut build = cc::Build::new();
+        let sources = ::std::fs::read_dir("libfuzzer")
+            .expect("listable source directory")
+            .map(|de| de.expect("file in directory").path())
+            .filter(|p| p.extension().map(|ext| ext == "cpp") == Some(true))
+            .collect::<Vec<_>>();
+        for source in sources.iter() {
+            println!("cargo:rerun-if-changed={}", source.display());
+            build.file(source.to_str().unwrap());
+        }
+        build.flag("-std=c++11");
+        build.flag("-fno-omit-frame-pointer");
+        build.flag("-w");
+        build.cpp(true);
+        build.compile("libfuzzer.a");
+    }
+}
diff --git a/ci/script.sh b/ci/script.sh
new file mode 100755
index 0000000..7a9981f
--- /dev/null
+++ b/ci/script.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+
+set -eux
+cd $(dirname $0)/..
+
+export CARGO_TARGET_DIR=$(pwd)/target
+
+pushd ./example
+cargo rustc \
+      --release \
+      -- \
+      -Cpasses='sancov' \
+      -Cllvm-args=-sanitizer-coverage-level=4 \
+      -Cllvm-args=-sanitizer-coverage-trace-compares \
+      -Cllvm-args=-sanitizer-coverage-inline-8bit-counters \
+      -Cllvm-args=-sanitizer-coverage-stack-depth \
+      -Cllvm-args=-sanitizer-coverage-trace-geps \
+      -Cllvm-args=-sanitizer-coverage-prune-blocks=0 \
+      -Zsanitizer=address
+(! $CARGO_TARGET_DIR/release/example -runs=100000)
+popd
+
+pushd ./example_arbitrary
+cargo rustc \
+      --release \
+      -- \
+      -Cpasses='sancov' \
+      -Cllvm-args=-sanitizer-coverage-level=4 \
+      -Cllvm-args=-sanitizer-coverage-trace-compares \
+      -Cllvm-args=-sanitizer-coverage-inline-8bit-counters \
+      -Cllvm-args=-sanitizer-coverage-stack-depth \
+      -Cllvm-args=-sanitizer-coverage-trace-geps \
+      -Cllvm-args=-sanitizer-coverage-prune-blocks=0 \
+      -Zsanitizer=address
+(! $CARGO_TARGET_DIR/release/example_arbitrary -runs=10000000)
+RUST_LIBFUZZER_DEBUG_PATH=$(pwd)/debug_output \
+    $CARGO_TARGET_DIR/release/example_arbitrary \
+    $(ls ./crash-* | head -n 1)
+cat $(pwd)/debug_output
+grep -q Rgb $(pwd)/debug_output
+popd
diff --git a/libfuzzer/CMakeLists.txt b/libfuzzer/CMakeLists.txt
new file mode 100644
index 0000000..b98c271
--- /dev/null
+++ b/libfuzzer/CMakeLists.txt
@@ -0,0 +1,178 @@
+set(LIBFUZZER_SOURCES
+  FuzzerCrossOver.cpp
+  FuzzerDataFlowTrace.cpp
+  FuzzerDriver.cpp
+  FuzzerExtFunctionsDlsym.cpp
+  FuzzerExtFunctionsWeak.cpp
+  FuzzerExtFunctionsWindows.cpp
+  FuzzerExtraCounters.cpp
+  FuzzerFork.cpp
+  FuzzerIO.cpp
+  FuzzerIOPosix.cpp
+  FuzzerIOWindows.cpp
+  FuzzerLoop.cpp
+  FuzzerMerge.cpp
+  FuzzerMutate.cpp
+  FuzzerSHA1.cpp
+  FuzzerTracePC.cpp
+  FuzzerUtil.cpp
+  FuzzerUtilDarwin.cpp
+  FuzzerUtilFuchsia.cpp
+  FuzzerUtilLinux.cpp
+  FuzzerUtilPosix.cpp
+  FuzzerUtilWindows.cpp)
+
+set(LIBFUZZER_HEADERS
+  FuzzerBuiltins.h
+  FuzzerBuiltinsMsvc.h
+  FuzzerCommand.h
+  FuzzerCorpus.h
+  FuzzerDataFlowTrace.h
+  FuzzerDefs.h
+  FuzzerDictionary.h
+  FuzzerExtFunctions.def
+  FuzzerExtFunctions.h
+  FuzzerFlags.def
+  FuzzerFork.h
+  FuzzerIO.h
+  FuzzerInterface.h
+  FuzzerInternal.h
+  FuzzerMerge.h
+  FuzzerMutate.h
+  FuzzerOptions.h
+  FuzzerRandom.h
+  FuzzerSHA1.h
+  FuzzerTracePC.h
+  FuzzerUtil.h
+  FuzzerValueBitMap.h)
+
+include_directories(../../include)
+
+CHECK_CXX_SOURCE_COMPILES("
+  static thread_local int blah;
+  int main() {
+  return 0;
+  }
+  " HAS_THREAD_LOCAL)
+
+set(LIBFUZZER_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+
+if(OS_NAME MATCHES "Linux|Fuchsia" AND
+   COMPILER_RT_LIBCXX_PATH AND
+   COMPILER_RT_LIBCXXABI_PATH)
+  list(APPEND LIBFUZZER_CFLAGS -nostdinc++ -D_LIBCPP_ABI_VERSION=Fuzzer)
+  # Remove -stdlib= which is unused when passing -nostdinc++.
+  string(REGEX REPLACE "-stdlib=[a-zA-Z+]*" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
+elseif(TARGET cxx-headers OR HAVE_LIBCXX)
+  set(LIBFUZZER_DEPS cxx-headers)
+endif()
+
+append_list_if(COMPILER_RT_HAS_OMIT_FRAME_POINTER_FLAG -fno-omit-frame-pointer LIBFUZZER_CFLAGS)
+
+if (CMAKE_CXX_FLAGS MATCHES "fsanitize-coverage")
+  list(APPEND LIBFUZZER_CFLAGS -fno-sanitize-coverage=trace-pc-guard,edge,trace-cmp,indirect-calls,8bit-counters)
+endif()
+
+if(MSVC)
+  # Silence warnings by turning off exceptions in MSVC headers and avoid an
+  # error by unecessarily defining thread_local when it isn't even used on
+  # Windows.
+  list(APPEND LIBFUZZER_CFLAGS -D_HAS_EXCEPTIONS=0)
+else()
+  if(NOT HAS_THREAD_LOCAL)
+    list(APPEND LIBFUZZER_CFLAGS -Dthread_local=__thread)
+  endif()
+endif()
+
+add_compiler_rt_component(fuzzer)
+
+add_compiler_rt_object_libraries(RTfuzzer
+  OS ${FUZZER_SUPPORTED_OS}
+  ARCHS ${FUZZER_SUPPORTED_ARCH}
+  SOURCES ${LIBFUZZER_SOURCES}
+  ADDITIONAL_HEADERS ${LIBFUZZER_HEADERS}
+  CFLAGS ${LIBFUZZER_CFLAGS}
+  DEPS ${LIBFUZZER_DEPS})
+
+add_compiler_rt_object_libraries(RTfuzzer_main
+  OS ${FUZZER_SUPPORTED_OS}
+  ARCHS ${FUZZER_SUPPORTED_ARCH}
+  SOURCES FuzzerMain.cpp
+  CFLAGS ${LIBFUZZER_CFLAGS}
+  DEPS ${LIBFUZZER_DEPS})
+
+add_compiler_rt_object_libraries(RTfuzzer_interceptors
+  OS ${FUZZER_SUPPORTED_OS}
+  ARCHS ${FUZZER_SUPPORTED_ARCH}
+  SOURCES FuzzerInterceptors.cpp
+  CFLAGS ${LIBFUZZER_CFLAGS}
+  DEPS ${LIBFUZZER_DEPS})
+
+add_compiler_rt_runtime(clang_rt.fuzzer
+  STATIC
+  OS ${FUZZER_SUPPORTED_OS}
+  ARCHS ${FUZZER_SUPPORTED_ARCH}
+  OBJECT_LIBS RTfuzzer RTfuzzer_main
+  CFLAGS ${LIBFUZZER_CFLAGS}
+  PARENT_TARGET fuzzer)
+
+add_compiler_rt_runtime(clang_rt.fuzzer_no_main
+  STATIC
+  OS ${FUZZER_SUPPORTED_OS}
+  ARCHS ${FUZZER_SUPPORTED_ARCH}
+  OBJECT_LIBS RTfuzzer
+  CFLAGS ${LIBFUZZER_CFLAGS}
+  PARENT_TARGET fuzzer)
+
+add_compiler_rt_runtime(clang_rt.fuzzer_interceptors
+  STATIC
+  OS ${FUZZER_SUPPORTED_OS}
+  ARCHS ${FUZZER_SUPPORTED_ARCH}
+  OBJECT_LIBS RTfuzzer_interceptors
+  CFLAGS ${LIBFUZZER_CFLAGS}
+  PARENT_TARGET fuzzer)
+
+if(OS_NAME MATCHES "Linux|Fuchsia" AND
+   COMPILER_RT_LIBCXX_PATH AND
+   COMPILER_RT_LIBCXXABI_PATH)
+  macro(partially_link_libcxx name dir arch)
+    if(${arch} MATCHES "i386")
+      set(EMULATION_ARGUMENT "-m" "elf_i386")
+    else()
+      set(EMULATION_ARGUMENT "")
+    endif()
+    set(cxx_${arch}_merge_dir "${CMAKE_CURRENT_BINARY_DIR}/cxx_${arch}_merge.dir")
+    file(MAKE_DIRECTORY ${cxx_${arch}_merge_dir})
+    add_custom_command(TARGET clang_rt.${name}-${arch} POST_BUILD
+      COMMAND ${CMAKE_LINKER} ${EMULATION_ARGUMENT} --whole-archive "$<TARGET_LINKER_FILE:clang_rt.${name}-${arch}>" --no-whole-archive ${dir}/lib/libc++.a -r -o ${name}.o
+      COMMAND ${CMAKE_OBJCOPY} --localize-hidden ${name}.o
+      COMMAND ${CMAKE_COMMAND} -E remove "$<TARGET_LINKER_FILE:clang_rt.${name}-${arch}>"
+      COMMAND ${CMAKE_AR} qcs "$<TARGET_LINKER_FILE:clang_rt.${name}-${arch}>" ${name}.o
+      WORKING_DIRECTORY ${cxx_${arch}_merge_dir}
+    )
+  endmacro()
+
+  foreach(arch ${FUZZER_SUPPORTED_ARCH})
+    get_target_flags_for_arch(${arch} TARGET_CFLAGS)
+    set(LIBCXX_${arch}_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libcxx_fuzzer_${arch})
+    add_custom_libcxx(libcxx_fuzzer_${arch} ${LIBCXX_${arch}_PREFIX}
+      CFLAGS ${TARGET_CFLAGS}
+      CMAKE_ARGS -DCMAKE_CXX_COMPILER_WORKS=ON
+                 -DCMAKE_POSITION_INDEPENDENT_CODE=ON
+                 -DLIBCXXABI_ENABLE_EXCEPTIONS=OFF
+                 -DLIBCXX_ABI_NAMESPACE=__Fuzzer)
+    target_compile_options(RTfuzzer.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
+    add_dependencies(RTfuzzer.${arch} libcxx_fuzzer_${arch}-build)
+    target_compile_options(RTfuzzer_main.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
+    add_dependencies(RTfuzzer_main.${arch} libcxx_fuzzer_${arch}-build)
+    target_compile_options(RTfuzzer_interceptors.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
+    add_dependencies(RTfuzzer_interceptors.${arch} libcxx_fuzzer_${arch}-build)
+    partially_link_libcxx(fuzzer_no_main ${LIBCXX_${arch}_PREFIX} ${arch})
+    partially_link_libcxx(fuzzer_interceptors ${LIBCXX_${arch}_PREFIX} ${arch})
+    partially_link_libcxx(fuzzer ${LIBCXX_${arch}_PREFIX} ${arch})
+  endforeach()
+endif()
+
+if(COMPILER_RT_INCLUDE_TESTS)
+  add_subdirectory(tests)
+endif()
diff --git a/libfuzzer/FuzzerBuiltins.h b/libfuzzer/FuzzerBuiltins.h
new file mode 100644
index 0000000..4c0ada8
--- /dev/null
+++ b/libfuzzer/FuzzerBuiltins.h
@@ -0,0 +1,35 @@
+//===- FuzzerBuiltins.h - Internal header for builtins ----------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Wrapper functions and marcos around builtin functions.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_BUILTINS_H
+#define LLVM_FUZZER_BUILTINS_H
+
+#include "FuzzerPlatform.h"
+
+#if !LIBFUZZER_MSVC
+#include <cstdint>
+
+#define GET_CALLER_PC() __builtin_return_address(0)
+
+namespace fuzzer {
+
+inline uint8_t  Bswap(uint8_t x)  { return x; }
+inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); }
+inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); }
+inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); }
+
+inline uint32_t Clzll(unsigned long long X) { return __builtin_clzll(X); }
+inline uint32_t Clz(unsigned long long X) { return __builtin_clz(X); }
+inline int Popcountll(unsigned long long X) { return __builtin_popcountll(X); }
+
+}  // namespace fuzzer
+
+#endif  // !LIBFUZZER_MSVC
+#endif  // LLVM_FUZZER_BUILTINS_H
diff --git a/libfuzzer/FuzzerBuiltinsMsvc.h b/libfuzzer/FuzzerBuiltinsMsvc.h
new file mode 100644
index 0000000..c5bec97
--- /dev/null
+++ b/libfuzzer/FuzzerBuiltinsMsvc.h
@@ -0,0 +1,72 @@
+//===- FuzzerBuiltinsMSVC.h - Internal header for builtins ------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Wrapper functions and marcos that use intrinsics instead of builtin functions
+// which cannot be compiled by MSVC.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_BUILTINS_MSVC_H
+#define LLVM_FUZZER_BUILTINS_MSVC_H
+
+#include "FuzzerPlatform.h"
+
+#if LIBFUZZER_MSVC
+#include <intrin.h>
+#include <cstdint>
+#include <cstdlib>
+
+// __builtin_return_address() cannot be compiled with MSVC. Use the equivalent
+// from <intrin.h>
+#define GET_CALLER_PC() _ReturnAddress()
+
+namespace fuzzer {
+
+inline uint8_t  Bswap(uint8_t x)  { return x; }
+// Use alternatives to __builtin functions from <stdlib.h> and <intrin.h> on
+// Windows since the builtins are not supported by MSVC.
+inline uint16_t Bswap(uint16_t x) { return _byteswap_ushort(x); }
+inline uint32_t Bswap(uint32_t x) { return _byteswap_ulong(x); }
+inline uint64_t Bswap(uint64_t x) { return _byteswap_uint64(x); }
+
+// The functions below were mostly copied from
+// compiler-rt/lib/builtins/int_lib.h which defines the __builtin functions used
+// outside of Windows.
+inline uint32_t Clzll(uint64_t X) {
+  unsigned long LeadZeroIdx = 0;
+
+#if !defined(_M_ARM) && !defined(_M_X64)
+  // Scan the high 32 bits.
+  if (_BitScanReverse(&LeadZeroIdx, static_cast<unsigned long>(X >> 32)))
+    return static_cast<int>(63 - (LeadZeroIdx + 32)); // Create a bit offset from the MSB.
+  // Scan the low 32 bits.
+  if (_BitScanReverse(&LeadZeroIdx, static_cast<unsigned long>(X)))
+    return static_cast<int>(63 - LeadZeroIdx);
+
+#else
+  if (_BitScanReverse64(&LeadZeroIdx, X)) return 63 - LeadZeroIdx;
+#endif
+  return 64;
+}
+
+inline uint32_t Clz(uint32_t X) {
+  unsigned long LeadZeroIdx = 0;
+  if (_BitScanReverse(&LeadZeroIdx, X)) return 31 - LeadZeroIdx;
+  return 32;
+}
+
+inline int Popcountll(unsigned long long X) {
+#if !defined(_M_ARM) && !defined(_M_X64)
+  return __popcnt(X) + __popcnt(X >> 32);
+#else
+  return __popcnt64(X);
+#endif
+}
+
+}  // namespace fuzzer
+
+#endif  // LIBFUZER_MSVC
+#endif  // LLVM_FUZZER_BUILTINS_MSVC_H
diff --git a/libfuzzer/FuzzerCommand.h b/libfuzzer/FuzzerCommand.h
new file mode 100644
index 0000000..8730886
--- /dev/null
+++ b/libfuzzer/FuzzerCommand.h
@@ -0,0 +1,178 @@
+//===- FuzzerCommand.h - Interface representing a process -------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// FuzzerCommand represents a command to run in a subprocess.  It allows callers
+// to manage command line arguments and output and error streams.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_COMMAND_H
+#define LLVM_FUZZER_COMMAND_H
+
+#include "FuzzerDefs.h"
+#include "FuzzerIO.h"
+
+#include <algorithm>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace fuzzer {
+
+class Command final {
+public:
+  // This command line flag is used to indicate that the remaining command line
+  // is immutable, meaning this flag effectively marks the end of the mutable
+  // argument list.
+  static inline const char *ignoreRemainingArgs() {
+    return "-ignore_remaining_args=1";
+  }
+
+  Command() : CombinedOutAndErr(false) {}
+
+  explicit Command(const Vector<std::string> &ArgsToAdd)
+      : Args(ArgsToAdd), CombinedOutAndErr(false) {}
+
+  explicit Command(const Command &Other)
+      : Args(Other.Args), CombinedOutAndErr(Other.CombinedOutAndErr),
+        OutputFile(Other.OutputFile) {}
+
+  Command &operator=(const Command &Other) {
+    Args = Other.Args;
+    CombinedOutAndErr = Other.CombinedOutAndErr;
+    OutputFile = Other.OutputFile;
+    return *this;
+  }
+
+  ~Command() {}
+
+  // Returns true if the given Arg is present in Args.  Only checks up to
+  // "-ignore_remaining_args=1".
+  bool hasArgument(const std::string &Arg) const {
+    auto i = endMutableArgs();
+    return std::find(Args.begin(), i, Arg) != i;
+  }
+
+  // Gets all of the current command line arguments, **including** those after
+  // "-ignore-remaining-args=1".
+  const Vector<std::string> &getArguments() const { return Args; }
+
+  // Adds the given argument before "-ignore_remaining_args=1", or at the end
+  // if that flag isn't present.
+  void addArgument(const std::string &Arg) {
+    Args.insert(endMutableArgs(), Arg);
+  }
+
+  // Adds all given arguments before "-ignore_remaining_args=1", or at the end
+  // if that flag isn't present.
+  void addArguments(const Vector<std::string> &ArgsToAdd) {
+    Args.insert(endMutableArgs(), ArgsToAdd.begin(), ArgsToAdd.end());
+  }
+
+  // Removes the given argument from the command argument list.  Ignores any
+  // occurrences after "-ignore_remaining_args=1", if present.
+  void removeArgument(const std::string &Arg) {
+    auto i = endMutableArgs();
+    Args.erase(std::remove(Args.begin(), i, Arg), i);
+  }
+
+  // Like hasArgument, but checks for "-[Flag]=...".
+  bool hasFlag(const std::string &Flag) const {
+    std::string Arg("-" + Flag + "=");
+    auto IsMatch = [&](const std::string &Other) {
+      return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
+    };
+    return std::any_of(Args.begin(), endMutableArgs(), IsMatch);
+  }
+
+  // Returns the value of the first instance of a given flag, or an empty string
+  // if the flag isn't present.  Ignores any occurrences after
+  // "-ignore_remaining_args=1", if present.
+  std::string getFlagValue(const std::string &Flag) const {
+    std::string Arg("-" + Flag + "=");
+    auto IsMatch = [&](const std::string &Other) {
+      return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
+    };
+    auto i = endMutableArgs();
+    auto j = std::find_if(Args.begin(), i, IsMatch);
+    std::string result;
+    if (j != i) {
+      result = j->substr(Arg.length());
+    }
+    return result;
+  }
+
+  // Like AddArgument, but adds "-[Flag]=[Value]".
+  void addFlag(const std::string &Flag, const std::string &Value) {
+    addArgument("-" + Flag + "=" + Value);
+  }
+
+  // Like RemoveArgument, but removes "-[Flag]=...".
+  void removeFlag(const std::string &Flag) {
+    std::string Arg("-" + Flag + "=");
+    auto IsMatch = [&](const std::string &Other) {
+      return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
+    };
+    auto i = endMutableArgs();
+    Args.erase(std::remove_if(Args.begin(), i, IsMatch), i);
+  }
+
+  // Returns whether the command's stdout is being written to an output file.
+  bool hasOutputFile() const { return !OutputFile.empty(); }
+
+  // Returns the currently set output file.
+  const std::string &getOutputFile() const { return OutputFile; }
+
+  // Configures the command to redirect its output to the name file.
+  void setOutputFile(const std::string &FileName) { OutputFile = FileName; }
+
+  // Returns whether the command's stderr is redirected to stdout.
+  bool isOutAndErrCombined() const { return CombinedOutAndErr; }
+
+  // Sets whether to redirect the command's stderr to its stdout.
+  void combineOutAndErr(bool combine = true) { CombinedOutAndErr = combine; }
+
+  // Returns a string representation of the command.  On many systems this will
+  // be the equivalent command line.
+  std::string toString() const {
+    std::stringstream SS;
+    for (auto arg : getArguments())
+      SS << arg << " ";
+    if (hasOutputFile())
+      SS << ">" << getOutputFile() << " ";
+    if (isOutAndErrCombined())
+      SS << "2>&1 ";
+    std::string result = SS.str();
+    if (!result.empty())
+      result = result.substr(0, result.length() - 1);
+    return result;
+  }
+
+private:
+  Command(Command &&Other) = delete;
+  Command &operator=(Command &&Other) = delete;
+
+  Vector<std::string>::iterator endMutableArgs() {
+    return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
+  }
+
+  Vector<std::string>::const_iterator endMutableArgs() const {
+    return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
+  }
+
+  // The command arguments.  Args[0] is the command name.
+  Vector<std::string> Args;
+
+  // True indicates stderr is redirected to stdout.
+  bool CombinedOutAndErr;
+
+  // If not empty, stdout is redirected to the named file.
+  std::string OutputFile;
+};
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_COMMAND_H
diff --git a/libfuzzer/FuzzerCorpus.h b/libfuzzer/FuzzerCorpus.h
new file mode 100644
index 0000000..54d1e09
--- /dev/null
+++ b/libfuzzer/FuzzerCorpus.h
@@ -0,0 +1,533 @@
+//===- FuzzerCorpus.h - Internal header for the Fuzzer ----------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// fuzzer::InputCorpus
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_CORPUS
+#define LLVM_FUZZER_CORPUS
+
+#include "FuzzerDataFlowTrace.h"
+#include "FuzzerDefs.h"
+#include "FuzzerIO.h"
+#include "FuzzerRandom.h"
+#include "FuzzerSHA1.h"
+#include "FuzzerTracePC.h"
+#include <algorithm>
+#include <numeric>
+#include <random>
+#include <unordered_set>
+
+namespace fuzzer {
+
+struct InputInfo {
+  Unit U;  // The actual input data.
+  uint8_t Sha1[kSHA1NumBytes];  // Checksum.
+  // Number of features that this input has and no smaller input has.
+  size_t NumFeatures = 0;
+  size_t Tmp = 0; // Used by ValidateFeatureSet.
+  // Stats.
+  size_t NumExecutedMutations = 0;
+  size_t NumSuccessfullMutations = 0;
+  bool MayDeleteFile = false;
+  bool Reduced = false;
+  bool HasFocusFunction = false;
+  Vector<uint32_t> UniqFeatureSet;
+  Vector<uint8_t> DataFlowTraceForFocusFunction;
+  // Power schedule.
+  bool NeedsEnergyUpdate = false;
+  double Energy = 0.0;
+  size_t SumIncidence = 0;
+  Vector<std::pair<uint32_t, uint16_t>> FeatureFreqs;
+
+  // Delete feature Idx and its frequency from FeatureFreqs.
+  bool DeleteFeatureFreq(uint32_t Idx) {
+    if (FeatureFreqs.empty())
+      return false;
+
+    // Binary search over local feature frequencies sorted by index.
+    auto Lower = std::lower_bound(FeatureFreqs.begin(), FeatureFreqs.end(),
+                                  std::pair<uint32_t, uint16_t>(Idx, 0));
+
+    if (Lower != FeatureFreqs.end() && Lower->first == Idx) {
+      FeatureFreqs.erase(Lower);
+      return true;
+    }
+    return false;
+  }
+
+  // Assign more energy to a high-entropy seed, i.e., that reveals more
+  // information about the globally rare features in the neighborhood
+  // of the seed. Since we do not know the entropy of a seed that has
+  // never been executed we assign fresh seeds maximum entropy and
+  // let II->Energy approach the true entropy from above.
+  void UpdateEnergy(size_t GlobalNumberOfFeatures) {
+    Energy = 0.0;
+    SumIncidence = 0;
+
+    // Apply add-one smoothing to locally discovered features.
+    for (auto F : FeatureFreqs) {
+      size_t LocalIncidence = F.second + 1;
+      Energy -= LocalIncidence * logl(LocalIncidence);
+      SumIncidence += LocalIncidence;
+    }
+
+    // Apply add-one smoothing to locally undiscovered features.
+    //   PreciseEnergy -= 0; // since logl(1.0) == 0)
+    SumIncidence += (GlobalNumberOfFeatures - FeatureFreqs.size());
+
+    // Add a single locally abundant feature apply add-one smoothing.
+    size_t AbdIncidence = NumExecutedMutations + 1;
+    Energy -= AbdIncidence * logl(AbdIncidence);
+    SumIncidence += AbdIncidence;
+
+    // Normalize.
+    if (SumIncidence != 0)
+      Energy = (Energy / SumIncidence) + logl(SumIncidence);
+  }
+
+  // Increment the frequency of the feature Idx.
+  void UpdateFeatureFrequency(uint32_t Idx) {
+    NeedsEnergyUpdate = true;
+
+    // The local feature frequencies is an ordered vector of pairs.
+    // If there are no local feature frequencies, push_back preserves order.
+    // Set the feature frequency for feature Idx32 to 1.
+    if (FeatureFreqs.empty()) {
+      FeatureFreqs.push_back(std::pair<uint32_t, uint16_t>(Idx, 1));
+      return;
+    }
+
+    // Binary search over local feature frequencies sorted by index.
+    auto Lower = std::lower_bound(FeatureFreqs.begin(), FeatureFreqs.end(),
+                                  std::pair<uint32_t, uint16_t>(Idx, 0));
+
+    // If feature Idx32 already exists, increment its frequency.
+    // Otherwise, insert a new pair right after the next lower index.
+    if (Lower != FeatureFreqs.end() && Lower->first == Idx) {
+      Lower->second++;
+    } else {
+      FeatureFreqs.insert(Lower, std::pair<uint32_t, uint16_t>(Idx, 1));
+    }
+  }
+};
+
+struct EntropicOptions {
+  bool Enabled;
+  size_t NumberOfRarestFeatures;
+  size_t FeatureFrequencyThreshold;
+};
+
+class InputCorpus {
+  static const uint32_t kFeatureSetSize = 1 << 21;
+  static const uint8_t kMaxMutationFactor = 20;
+  static const size_t kSparseEnergyUpdates = 100;
+
+  size_t NumExecutedMutations = 0;
+
+  EntropicOptions Entropic;
+
+public:
+  InputCorpus(const std::string &OutputCorpus, EntropicOptions Entropic)
+      : Entropic(Entropic), OutputCorpus(OutputCorpus) {
+    memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature));
+    memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature));
+  }
+  ~InputCorpus() {
+    for (auto II : Inputs)
+      delete II;
+  }
+  size_t size() const { return Inputs.size(); }
+  size_t SizeInBytes() const {
+    size_t Res = 0;
+    for (auto II : Inputs)
+      Res += II->U.size();
+    return Res;
+  }
+  size_t NumActiveUnits() const {
+    size_t Res = 0;
+    for (auto II : Inputs)
+      Res += !II->U.empty();
+    return Res;
+  }
+  size_t MaxInputSize() const {
+    size_t Res = 0;
+    for (auto II : Inputs)
+        Res = std::max(Res, II->U.size());
+    return Res;
+  }
+  void IncrementNumExecutedMutations() { NumExecutedMutations++; }
+
+  size_t NumInputsThatTouchFocusFunction() {
+    return std::count_if(Inputs.begin(), Inputs.end(), [](const InputInfo *II) {
+      return II->HasFocusFunction;
+    });
+  }
+
+  size_t NumInputsWithDataFlowTrace() {
+    return std::count_if(Inputs.begin(), Inputs.end(), [](const InputInfo *II) {
+      return !II->DataFlowTraceForFocusFunction.empty();
+    });
+  }
+
+  bool empty() const { return Inputs.empty(); }
+  const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; }
+  InputInfo *AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile,
+                         bool HasFocusFunction,
+                         const Vector<uint32_t> &FeatureSet,
+                         const DataFlowTrace &DFT, const InputInfo *BaseII) {
+    assert(!U.empty());
+    if (FeatureDebug)
+      Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures);
+    Inputs.push_back(new InputInfo());
+    InputInfo &II = *Inputs.back();
+    II.U = U;
+    II.NumFeatures = NumFeatures;
+    II.MayDeleteFile = MayDeleteFile;
+    II.UniqFeatureSet = FeatureSet;
+    II.HasFocusFunction = HasFocusFunction;
+    // Assign maximal energy to the new seed.
+    II.Energy = RareFeatures.empty() ? 1.0 : log(RareFeatures.size());
+    II.SumIncidence = RareFeatures.size();
+    II.NeedsEnergyUpdate = false;
+    std::sort(II.UniqFeatureSet.begin(), II.UniqFeatureSet.end());
+    ComputeSHA1(U.data(), U.size(), II.Sha1);
+    auto Sha1Str = Sha1ToString(II.Sha1);
+    Hashes.insert(Sha1Str);
+    if (HasFocusFunction)
+      if (auto V = DFT.Get(Sha1Str))
+        II.DataFlowTraceForFocusFunction = *V;
+    // This is a gross heuristic.
+    // Ideally, when we add an element to a corpus we need to know its DFT.
+    // But if we don't, we'll use the DFT of its base input.
+    if (II.DataFlowTraceForFocusFunction.empty() && BaseII)
+      II.DataFlowTraceForFocusFunction = BaseII->DataFlowTraceForFocusFunction;
+    DistributionNeedsUpdate = true;
+    PrintCorpus();
+    // ValidateFeatureSet();
+    return &II;
+  }
+
+  // Debug-only
+  void PrintUnit(const Unit &U) {
+    if (!FeatureDebug) return;
+    for (uint8_t C : U) {
+      if (C != 'F' && C != 'U' && C != 'Z')
+        C = '.';
+      Printf("%c", C);
+    }
+  }
+
+  // Debug-only
+  void PrintFeatureSet(const Vector<uint32_t> &FeatureSet) {
+    if (!FeatureDebug) return;
+    Printf("{");
+    for (uint32_t Feature: FeatureSet)
+      Printf("%u,", Feature);
+    Printf("}");
+  }
+
+  // Debug-only
+  void PrintCorpus() {
+    if (!FeatureDebug) return;
+    Printf("======= CORPUS:\n");
+    int i = 0;
+    for (auto II : Inputs) {
+      if (std::find(II->U.begin(), II->U.end(), 'F') != II->U.end()) {
+        Printf("[%2d] ", i);
+        Printf("%s sz=%zd ", Sha1ToString(II->Sha1).c_str(), II->U.size());
+        PrintUnit(II->U);
+        Printf(" ");
+        PrintFeatureSet(II->UniqFeatureSet);
+        Printf("\n");
+      }
+      i++;
+    }
+  }
+
+  void Replace(InputInfo *II, const Unit &U) {
+    assert(II->U.size() > U.size());
+    Hashes.erase(Sha1ToString(II->Sha1));
+    DeleteFile(*II);
+    ComputeSHA1(U.data(), U.size(), II->Sha1);
+    Hashes.insert(Sha1ToString(II->Sha1));
+    II->U = U;
+    II->Reduced = true;
+    DistributionNeedsUpdate = true;
+  }
+
+  bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); }
+  bool HasUnit(const std::string &H) { return Hashes.count(H); }
+  InputInfo &ChooseUnitToMutate(Random &Rand) {
+    InputInfo &II = *Inputs[ChooseUnitIdxToMutate(Rand)];
+    assert(!II.U.empty());
+    return II;
+  }
+
+  // Returns an index of random unit from the corpus to mutate.
+  size_t ChooseUnitIdxToMutate(Random &Rand) {
+    UpdateCorpusDistribution(Rand);
+    size_t Idx = static_cast<size_t>(CorpusDistribution(Rand));
+    assert(Idx < Inputs.size());
+    return Idx;
+  }
+
+  void PrintStats() {
+    for (size_t i = 0; i < Inputs.size(); i++) {
+      const auto &II = *Inputs[i];
+      Printf("  [% 3zd %s] sz: % 5zd runs: % 5zd succ: % 5zd focus: %d\n", i,
+             Sha1ToString(II.Sha1).c_str(), II.U.size(),
+             II.NumExecutedMutations, II.NumSuccessfullMutations, II.HasFocusFunction);
+    }
+  }
+
+  void PrintFeatureSet() {
+    for (size_t i = 0; i < kFeatureSetSize; i++) {
+      if(size_t Sz = GetFeature(i))
+        Printf("[%zd: id %zd sz%zd] ", i, SmallestElementPerFeature[i], Sz);
+    }
+    Printf("\n\t");
+    for (size_t i = 0; i < Inputs.size(); i++)
+      if (size_t N = Inputs[i]->NumFeatures)
+        Printf(" %zd=>%zd ", i, N);
+    Printf("\n");
+  }
+
+  void DeleteFile(const InputInfo &II) {
+    if (!OutputCorpus.empty() && II.MayDeleteFile)
+      RemoveFile(DirPlusFile(OutputCorpus, Sha1ToString(II.Sha1)));
+  }
+
+  void DeleteInput(size_t Idx) {
+    InputInfo &II = *Inputs[Idx];
+    DeleteFile(II);
+    Unit().swap(II.U);
+    II.Energy = 0.0;
+    II.NeedsEnergyUpdate = false;
+    DistributionNeedsUpdate = true;
+    if (FeatureDebug)
+      Printf("EVICTED %zd\n", Idx);
+  }
+
+  void AddRareFeature(uint32_t Idx) {
+    // Maintain *at least* TopXRarestFeatures many rare features
+    // and all features with a frequency below ConsideredRare.
+    // Remove all other features.
+    while (RareFeatures.size() > Entropic.NumberOfRarestFeatures &&
+           FreqOfMostAbundantRareFeature > Entropic.FeatureFrequencyThreshold) {
+
+      // Find most and second most abbundant feature.
+      uint32_t MostAbundantRareFeatureIndices[2] = {RareFeatures[0],
+                                                    RareFeatures[0]};
+      size_t Delete = 0;
+      for (size_t i = 0; i < RareFeatures.size(); i++) {
+        uint32_t Idx2 = RareFeatures[i];
+        if (GlobalFeatureFreqs[Idx2] >=
+            GlobalFeatureFreqs[MostAbundantRareFeatureIndices[0]]) {
+          MostAbundantRareFeatureIndices[1] = MostAbundantRareFeatureIndices[0];
+          MostAbundantRareFeatureIndices[0] = Idx2;
+          Delete = i;
+        }
+      }
+
+      // Remove most abundant rare feature.
+      RareFeatures[Delete] = RareFeatures.back();
+      RareFeatures.pop_back();
+
+      for (auto II : Inputs) {
+        if (II->DeleteFeatureFreq(MostAbundantRareFeatureIndices[0]))
+          II->NeedsEnergyUpdate = true;
+      }
+
+      // Set 2nd most abundant as the new most abundant feature count.
+      FreqOfMostAbundantRareFeature =
+          GlobalFeatureFreqs[MostAbundantRareFeatureIndices[1]];
+    }
+
+    // Add rare feature, handle collisions, and update energy.
+    RareFeatures.push_back(Idx);
+    GlobalFeatureFreqs[Idx] = 0;
+    for (auto II : Inputs) {
+      II->DeleteFeatureFreq(Idx);
+
+      // Apply add-one smoothing to this locally undiscovered feature.
+      // Zero energy seeds will never be fuzzed and remain zero energy.
+      if (II->Energy > 0.0) {
+        II->SumIncidence += 1;
+        II->Energy += logl(II->SumIncidence) / II->SumIncidence;
+      }
+    }
+
+    DistributionNeedsUpdate = true;
+  }
+
+  bool AddFeature(size_t Idx, uint32_t NewSize, bool Shrink) {
+    assert(NewSize);
+    Idx = Idx % kFeatureSetSize;
+    uint32_t OldSize = GetFeature(Idx);
+    if (OldSize == 0 || (Shrink && OldSize > NewSize)) {
+      if (OldSize > 0) {
+        size_t OldIdx = SmallestElementPerFeature[Idx];
+        InputInfo &II = *Inputs[OldIdx];
+        assert(II.NumFeatures > 0);
+        II.NumFeatures--;
+        if (II.NumFeatures == 0)
+          DeleteInput(OldIdx);
+      } else {
+        NumAddedFeatures++;
+        if (Entropic.Enabled)
+          AddRareFeature((uint32_t)Idx);
+      }
+      NumUpdatedFeatures++;
+      if (FeatureDebug)
+        Printf("ADD FEATURE %zd sz %d\n", Idx, NewSize);
+      SmallestElementPerFeature[Idx] = Inputs.size();
+      InputSizesPerFeature[Idx] = NewSize;
+      return true;
+    }
+    return false;
+  }
+
+  // Increment frequency of feature Idx globally and locally.
+  void UpdateFeatureFrequency(InputInfo *II, size_t Idx) {
+    uint32_t Idx32 = Idx % kFeatureSetSize;
+
+    // Saturated increment.
+    if (GlobalFeatureFreqs[Idx32] == 0xFFFF)
+      return;
+    uint16_t Freq = GlobalFeatureFreqs[Idx32]++;
+
+    // Skip if abundant.
+    if (Freq > FreqOfMostAbundantRareFeature ||
+        std::find(RareFeatures.begin(), RareFeatures.end(), Idx32) ==
+            RareFeatures.end())
+      return;
+
+    // Update global frequencies.
+    if (Freq == FreqOfMostAbundantRareFeature)
+      FreqOfMostAbundantRareFeature++;
+
+    // Update local frequencies.
+    if (II)
+      II->UpdateFeatureFrequency(Idx32);
+  }
+
+  size_t NumFeatures() const { return NumAddedFeatures; }
+  size_t NumFeatureUpdates() const { return NumUpdatedFeatures; }
+
+private:
+
+  static const bool FeatureDebug = false;
+
+  size_t GetFeature(size_t Idx) const { return InputSizesPerFeature[Idx]; }
+
+  void ValidateFeatureSet() {
+    if (FeatureDebug)
+      PrintFeatureSet();
+    for (size_t Idx = 0; Idx < kFeatureSetSize; Idx++)
+      if (GetFeature(Idx))
+        Inputs[SmallestElementPerFeature[Idx]]->Tmp++;
+    for (auto II: Inputs) {
+      if (II->Tmp != II->NumFeatures)
+        Printf("ZZZ %zd %zd\n", II->Tmp, II->NumFeatures);
+      assert(II->Tmp == II->NumFeatures);
+      II->Tmp = 0;
+    }
+  }
+
+  // Updates the probability distribution for the units in the corpus.
+  // Must be called whenever the corpus or unit weights are changed.
+  //
+  // Hypothesis: inputs that maximize information about globally rare features
+  // are interesting.
+  void UpdateCorpusDistribution(Random &Rand) {
+    // Skip update if no seeds or rare features were added/deleted.
+    // Sparse updates for local change of feature frequencies,
+    // i.e., randomly do not skip.
+    if (!DistributionNeedsUpdate &&
+        (!Entropic.Enabled || Rand(kSparseEnergyUpdates)))
+      return;
+
+    DistributionNeedsUpdate = false;
+
+    size_t N = Inputs.size();
+    assert(N);
+    Intervals.resize(N + 1);
+    Weights.resize(N);
+    std::iota(Intervals.begin(), Intervals.end(), 0);
+
+    bool VanillaSchedule = true;
+    if (Entropic.Enabled) {
+      for (auto II : Inputs) {
+        if (II->NeedsEnergyUpdate && II->Energy != 0.0) {
+          II->NeedsEnergyUpdate = false;
+          II->UpdateEnergy(RareFeatures.size());
+        }
+      }
+
+      for (size_t i = 0; i < N; i++) {
+
+        if (Inputs[i]->NumFeatures == 0) {
+          // If the seed doesn't represent any features, assign zero energy.
+          Weights[i] = 0.;
+        } else if (Inputs[i]->NumExecutedMutations / kMaxMutationFactor >
+                   NumExecutedMutations / Inputs.size()) {
+          // If the seed was fuzzed a lot more than average, assign zero energy.
+          Weights[i] = 0.;
+        } else {
+          // Otherwise, simply assign the computed energy.
+          Weights[i] = Inputs[i]->Energy;
+        }
+
+        // If energy for all seeds is zero, fall back to vanilla schedule.
+        if (Weights[i] > 0.0)
+          VanillaSchedule = false;
+      }
+    }
+
+    if (VanillaSchedule) {
+      for (size_t i = 0; i < N; i++)
+        Weights[i] = Inputs[i]->NumFeatures
+                         ? (i + 1) * (Inputs[i]->HasFocusFunction ? 1000 : 1)
+                         : 0.;
+    }
+
+    if (FeatureDebug) {
+      for (size_t i = 0; i < N; i++)
+        Printf("%zd ", Inputs[i]->NumFeatures);
+      Printf("SCORE\n");
+      for (size_t i = 0; i < N; i++)
+        Printf("%f ", Weights[i]);
+      Printf("Weights\n");
+    }
+    CorpusDistribution = std::piecewise_constant_distribution<double>(
+        Intervals.begin(), Intervals.end(), Weights.begin());
+  }
+  std::piecewise_constant_distribution<double> CorpusDistribution;
+
+  Vector<double> Intervals;
+  Vector<double> Weights;
+
+  std::unordered_set<std::string> Hashes;
+  Vector<InputInfo*> Inputs;
+
+  size_t NumAddedFeatures = 0;
+  size_t NumUpdatedFeatures = 0;
+  uint32_t InputSizesPerFeature[kFeatureSetSize];
+  uint32_t SmallestElementPerFeature[kFeatureSetSize];
+
+  bool DistributionNeedsUpdate = true;
+  uint16_t FreqOfMostAbundantRareFeature = 0;
+  uint16_t GlobalFeatureFreqs[kFeatureSetSize] = {};
+  Vector<uint32_t> RareFeatures;
+
+  std::string OutputCorpus;
+};
+
+}  // namespace fuzzer
+
+#endif  // LLVM_FUZZER_CORPUS
diff --git a/libfuzzer/FuzzerCrossOver.cpp b/libfuzzer/FuzzerCrossOver.cpp
new file mode 100644
index 0000000..83d9f8d
--- /dev/null
+++ b/libfuzzer/FuzzerCrossOver.cpp
@@ -0,0 +1,51 @@
+//===- FuzzerCrossOver.cpp - Cross over two test inputs -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Cross over test inputs.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerDefs.h"
+#include "FuzzerMutate.h"
+#include "FuzzerRandom.h"
+#include <cstring>
+
+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/libfuzzer/FuzzerDataFlowTrace.cpp b/libfuzzer/FuzzerDataFlowTrace.cpp
new file mode 100644
index 0000000..48df8e6
--- /dev/null
+++ b/libfuzzer/FuzzerDataFlowTrace.cpp
@@ -0,0 +1,286 @@
+//===- FuzzerDataFlowTrace.cpp - DataFlowTrace                ---*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// fuzzer::DataFlowTrace
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerDataFlowTrace.h"
+
+#include "FuzzerCommand.h"
+#include "FuzzerIO.h"
+#include "FuzzerRandom.h"
+#include "FuzzerSHA1.h"
+#include "FuzzerUtil.h"
+
+#include <cstdlib>
+#include <fstream>
+#include <numeric>
+#include <queue>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+namespace fuzzer {
+static const char *kFunctionsTxt = "functions.txt";
+
+bool BlockCoverage::AppendCoverage(const std::string &S) {
+  std::stringstream SS(S);
+  return AppendCoverage(SS);
+}
+
+// Coverage lines have this form:
+// CN X Y Z T
+// where N is the number of the function, T is the total number of instrumented
+// BBs, and X,Y,Z, if present, are the indecies of covered BB.
+// BB #0, which is the entry block, is not explicitly listed.
+bool BlockCoverage::AppendCoverage(std::istream &IN) {
+  std::string L;
+  while (std::getline(IN, L, '\n')) {
+    if (L.empty())
+      continue;
+    std::stringstream SS(L.c_str() + 1);
+    size_t FunctionId  = 0;
+    SS >> FunctionId;
+    if (L[0] == 'F') {
+      FunctionsWithDFT.insert(FunctionId);
+      continue;
+    }
+    if (L[0] != 'C') continue;
+    Vector<uint32_t> CoveredBlocks;
+    while (true) {
+      uint32_t BB = 0;
+      SS >> BB;
+      if (!SS) break;
+      CoveredBlocks.push_back(BB);
+    }
+    if (CoveredBlocks.empty()) return false;
+    uint32_t NumBlocks = CoveredBlocks.back();
+    CoveredBlocks.pop_back();
+    for (auto BB : CoveredBlocks)
+      if (BB >= NumBlocks) return false;
+    auto It = Functions.find(FunctionId);
+    auto &Counters =
+        It == Functions.end()
+            ? Functions.insert({FunctionId, Vector<uint32_t>(NumBlocks)})
+                  .first->second
+            : It->second;
+
+    if (Counters.size() != NumBlocks) return false;  // wrong number of blocks.
+
+    Counters[0]++;
+    for (auto BB : CoveredBlocks)
+      Counters[BB]++;
+  }
+  return true;
+}
+
+// Assign weights to each function.
+// General principles:
+//   * any uncovered function gets weight 0.
+//   * a function with lots of uncovered blocks gets bigger weight.
+//   * a function with a less frequently executed code gets bigger weight.
+Vector<double> BlockCoverage::FunctionWeights(size_t NumFunctions) const {
+  Vector<double> Res(NumFunctions);
+  for (auto It : Functions) {
+    auto FunctionID = It.first;
+    auto Counters = It.second;
+    assert(FunctionID < NumFunctions);
+    auto &Weight = Res[FunctionID];
+    // Give higher weight if the function has a DFT.
+    Weight = FunctionsWithDFT.count(FunctionID) ? 1000. : 1;
+    // Give higher weight to functions with less frequently seen basic blocks.
+    Weight /= SmallestNonZeroCounter(Counters);
+    // Give higher weight to functions with the most uncovered basic blocks.
+    Weight *= NumberOfUncoveredBlocks(Counters) + 1;
+  }
+  return Res;
+}
+
+void DataFlowTrace::ReadCoverage(const std::string &DirPath) {
+  Vector<SizedFile> Files;
+  GetSizedFilesFromDir(DirPath, &Files);
+  for (auto &SF : Files) {
+    auto Name = Basename(SF.File);
+    if (Name == kFunctionsTxt) continue;
+    if (!CorporaHashes.count(Name)) continue;
+    std::ifstream IF(SF.File);
+    Coverage.AppendCoverage(IF);
+  }
+}
+
+static void DFTStringAppendToVector(Vector<uint8_t> *DFT,
+                                    const std::string &DFTString) {
+  assert(DFT->size() == DFTString.size());
+  for (size_t I = 0, Len = DFT->size(); I < Len; I++)
+    (*DFT)[I] = DFTString[I] == '1';
+}
+
+// converts a string of '0' and '1' into a Vector<uint8_t>
+static Vector<uint8_t> DFTStringToVector(const std::string &DFTString) {
+  Vector<uint8_t> DFT(DFTString.size());
+  DFTStringAppendToVector(&DFT, DFTString);
+  return DFT;
+}
+
+static bool ParseError(const char *Err, const std::string &Line) {
+  Printf("DataFlowTrace: parse error: %s: Line: %s\n", Err, Line.c_str());
+  return false;
+}
+
+// TODO(metzman): replace std::string with std::string_view for
+// better performance. Need to figure our how to use string_view on Windows.
+static bool ParseDFTLine(const std::string &Line, size_t *FunctionNum,
+                         std::string *DFTString) {
+  if (!Line.empty() && Line[0] != 'F')
+    return false; // Ignore coverage.
+  size_t SpacePos = Line.find(' ');
+  if (SpacePos == std::string::npos)
+    return ParseError("no space in the trace line", Line);
+  if (Line.empty() || Line[0] != 'F')
+    return ParseError("the trace line doesn't start with 'F'", Line);
+  *FunctionNum = std::atol(Line.c_str() + 1);
+  const char *Beg = Line.c_str() + SpacePos + 1;
+  const char *End = Line.c_str() + Line.size();
+  assert(Beg < End);
+  size_t Len = End - Beg;
+  for (size_t I = 0; I < Len; I++) {
+    if (Beg[I] != '0' && Beg[I] != '1')
+      return ParseError("the trace should contain only 0 or 1", Line);
+  }
+  *DFTString = Beg;
+  return true;
+}
+
+bool DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction,
+                         Vector<SizedFile> &CorporaFiles, Random &Rand) {
+  if (DirPath.empty()) return false;
+  Printf("INFO: DataFlowTrace: reading from '%s'\n", DirPath.c_str());
+  Vector<SizedFile> Files;
+  GetSizedFilesFromDir(DirPath, &Files);
+  std::string L;
+  size_t FocusFuncIdx = SIZE_MAX;
+  Vector<std::string> FunctionNames;
+
+  // Collect the hashes of the corpus files.
+  for (auto &SF : CorporaFiles)
+    CorporaHashes.insert(Hash(FileToVector(SF.File)));
+
+  // Read functions.txt
+  std::ifstream IF(DirPlusFile(DirPath, kFunctionsTxt));
+  size_t NumFunctions = 0;
+  while (std::getline(IF, L, '\n')) {
+    FunctionNames.push_back(L);
+    NumFunctions++;
+    if (*FocusFunction == L)
+      FocusFuncIdx = NumFunctions - 1;
+  }
+  if (!NumFunctions)
+    return false;
+
+  if (*FocusFunction == "auto") {
+    // AUTOFOCUS works like this:
+    // * reads the coverage data from the DFT files.
+    // * assigns weights to functions based on coverage.
+    // * chooses a random function according to the weights.
+    ReadCoverage(DirPath);
+    auto Weights = Coverage.FunctionWeights(NumFunctions);
+    Vector<double> Intervals(NumFunctions + 1);
+    std::iota(Intervals.begin(), Intervals.end(), 0);
+    auto Distribution = std::piecewise_constant_distribution<double>(
+        Intervals.begin(), Intervals.end(), Weights.begin());
+    FocusFuncIdx = static_cast<size_t>(Distribution(Rand));
+    *FocusFunction = FunctionNames[FocusFuncIdx];
+    assert(FocusFuncIdx < NumFunctions);
+    Printf("INFO: AUTOFOCUS: %zd %s\n", FocusFuncIdx,
+           FunctionNames[FocusFuncIdx].c_str());
+    for (size_t i = 0; i < NumFunctions; i++) {
+      if (!Weights[i]) continue;
+      Printf("  [%zd] W %g\tBB-tot %u\tBB-cov %u\tEntryFreq %u:\t%s\n", i,
+             Weights[i], Coverage.GetNumberOfBlocks(i),
+             Coverage.GetNumberOfCoveredBlocks(i), Coverage.GetCounter(i, 0),
+             FunctionNames[i].c_str());
+    }
+  }
+
+  if (!NumFunctions || FocusFuncIdx == SIZE_MAX || Files.size() <= 1)
+    return false;
+
+  // Read traces.
+  size_t NumTraceFiles = 0;
+  size_t NumTracesWithFocusFunction = 0;
+  for (auto &SF : Files) {
+    auto Name = Basename(SF.File);
+    if (Name == kFunctionsTxt) continue;
+    if (!CorporaHashes.count(Name)) continue;  // not in the corpus.
+    NumTraceFiles++;
+    // Printf("=== %s\n", Name.c_str());
+    std::ifstream IF(SF.File);
+    while (std::getline(IF, L, '\n')) {
+      size_t FunctionNum = 0;
+      std::string DFTString;
+      if (ParseDFTLine(L, &FunctionNum, &DFTString) &&
+          FunctionNum == FocusFuncIdx) {
+        NumTracesWithFocusFunction++;
+
+        if (FunctionNum >= NumFunctions)
+          return ParseError("N is greater than the number of functions", L);
+        Traces[Name] = DFTStringToVector(DFTString);
+        // Print just a few small traces.
+        if (NumTracesWithFocusFunction <= 3 && DFTString.size() <= 16)
+          Printf("%s => |%s|\n", Name.c_str(), std::string(DFTString).c_str());
+        break; // No need to parse the following lines.
+      }
+    }
+  }
+  Printf("INFO: DataFlowTrace: %zd trace files, %zd functions, "
+         "%zd traces with focus function\n",
+         NumTraceFiles, NumFunctions, NumTracesWithFocusFunction);
+  return NumTraceFiles > 0;
+}
+
+int CollectDataFlow(const std::string &DFTBinary, const std::string &DirPath,
+                    const Vector<SizedFile> &CorporaFiles) {
+  Printf("INFO: collecting data flow: bin: %s dir: %s files: %zd\n",
+         DFTBinary.c_str(), DirPath.c_str(), CorporaFiles.size());
+  if (CorporaFiles.empty()) {
+    Printf("ERROR: can't collect data flow without corpus provided.");
+    return 1;
+  }
+
+  static char DFSanEnv[] = "DFSAN_OPTIONS=fast16labels=1:warn_unimplemented=0";
+  putenv(DFSanEnv);
+  MkDir(DirPath);
+  for (auto &F : CorporaFiles) {
+    // For every input F we need to collect the data flow and the coverage.
+    // Data flow collection may fail if we request too many DFSan tags at once.
+    // So, we start from requesting all tags in range [0,Size) and if that fails
+    // we then request tags in [0,Size/2) and [Size/2, Size), and so on.
+    // Function number => DFT.
+    auto OutPath = DirPlusFile(DirPath, Hash(FileToVector(F.File)));
+    std::unordered_map<size_t, Vector<uint8_t>> DFTMap;
+    std::unordered_set<std::string> Cov;
+    Command Cmd;
+    Cmd.addArgument(DFTBinary);
+    Cmd.addArgument(F.File);
+    Cmd.addArgument(OutPath);
+    Printf("CMD: %s\n", Cmd.toString().c_str());
+    ExecuteCommand(Cmd);
+  }
+  // Write functions.txt if it's currently empty or doesn't exist.
+  auto FunctionsTxtPath = DirPlusFile(DirPath, kFunctionsTxt);
+  if (FileToString(FunctionsTxtPath).empty()) {
+    Command Cmd;
+    Cmd.addArgument(DFTBinary);
+    Cmd.setOutputFile(FunctionsTxtPath);
+    ExecuteCommand(Cmd);
+  }
+  return 0;
+}
+
+}  // namespace fuzzer
diff --git a/libfuzzer/FuzzerDataFlowTrace.h b/libfuzzer/FuzzerDataFlowTrace.h
new file mode 100644
index 0000000..d6e3de3
--- /dev/null
+++ b/libfuzzer/FuzzerDataFlowTrace.h
@@ -0,0 +1,135 @@
+//===- FuzzerDataFlowTrace.h - Internal header for the Fuzzer ---*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// fuzzer::DataFlowTrace; reads and handles a data-flow trace.
+//
+// A data flow trace is generated by e.g. dataflow/DataFlow.cpp
+// and is stored on disk in a separate directory.
+//
+// The trace dir contains a file 'functions.txt' which lists function names,
+// oner per line, e.g.
+// ==> functions.txt <==
+// Func2
+// LLVMFuzzerTestOneInput
+// Func1
+//
+// All other files in the dir are the traces, see dataflow/DataFlow.cpp.
+// The name of the file is sha1 of the input used to generate the trace.
+//
+// Current status:
+//   the data is parsed and the summary is printed, but the data is not yet
+//   used in any other way.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_DATA_FLOW_TRACE
+#define LLVM_FUZZER_DATA_FLOW_TRACE
+
+#include "FuzzerDefs.h"
+#include "FuzzerIO.h"
+
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+#include <string>
+
+namespace fuzzer {
+
+int CollectDataFlow(const std::string &DFTBinary, const std::string &DirPath,
+                    const Vector<SizedFile> &CorporaFiles);
+
+class BlockCoverage {
+ public:
+  bool AppendCoverage(std::istream &IN);
+  bool AppendCoverage(const std::string &S);
+
+  size_t NumCoveredFunctions() const { return Functions.size(); }
+
+  uint32_t GetCounter(size_t FunctionId, size_t BasicBlockId) {
+    auto It = Functions.find(FunctionId);
+    if (It == Functions.end()) return 0;
+    const auto &Counters = It->second;
+    if (BasicBlockId < Counters.size())
+      return Counters[BasicBlockId];
+    return 0;
+  }
+
+  uint32_t GetNumberOfBlocks(size_t FunctionId) {
+    auto It = Functions.find(FunctionId);
+    if (It == Functions.end()) return 0;
+    const auto &Counters = It->second;
+    return Counters.size();
+  }
+
+  uint32_t GetNumberOfCoveredBlocks(size_t FunctionId) {
+    auto It = Functions.find(FunctionId);
+    if (It == Functions.end()) return 0;
+    const auto &Counters = It->second;
+    uint32_t Result = 0;
+    for (auto Cnt: Counters)
+      if (Cnt)
+        Result++;
+    return Result;
+  }
+
+  Vector<double> FunctionWeights(size_t NumFunctions) const;
+  void clear() { Functions.clear(); }
+
+ private:
+
+  typedef Vector<uint32_t> CoverageVector;
+
+  uint32_t NumberOfCoveredBlocks(const CoverageVector &Counters) const {
+    uint32_t Res = 0;
+    for (auto Cnt : Counters)
+      if (Cnt)
+        Res++;
+    return Res;
+  }
+
+  uint32_t NumberOfUncoveredBlocks(const CoverageVector &Counters) const {
+    return Counters.size() - NumberOfCoveredBlocks(Counters);
+  }
+
+  uint32_t SmallestNonZeroCounter(const CoverageVector &Counters) const {
+    assert(!Counters.empty());
+    uint32_t Res = Counters[0];
+    for (auto Cnt : Counters)
+      if (Cnt)
+        Res = Min(Res, Cnt);
+    assert(Res);
+    return Res;
+  }
+
+  // Function ID => vector of counters.
+  // Each counter represents how many input files trigger the given basic block.
+  std::unordered_map<size_t, CoverageVector> Functions;
+  // Functions that have DFT entry.
+  std::unordered_set<size_t> FunctionsWithDFT;
+};
+
+class DataFlowTrace {
+ public:
+  void ReadCoverage(const std::string &DirPath);
+  bool Init(const std::string &DirPath, std::string *FocusFunction,
+            Vector<SizedFile> &CorporaFiles, Random &Rand);
+  void Clear() { Traces.clear(); }
+  const Vector<uint8_t> *Get(const std::string &InputSha1) const {
+    auto It = Traces.find(InputSha1);
+    if (It != Traces.end())
+      return &It->second;
+    return nullptr;
+  }
+
+ private:
+  // Input's sha1 => DFT for the FocusFunction.
+  std::unordered_map<std::string, Vector<uint8_t> > Traces;
+  BlockCoverage Coverage;
+  std::unordered_set<std::string> CorporaHashes;
+};
+}  // namespace fuzzer
+
+#endif // LLVM_FUZZER_DATA_FLOW_TRACE
diff --git a/libfuzzer/FuzzerDefs.h b/libfuzzer/FuzzerDefs.h
new file mode 100644
index 0000000..1a2752a
--- /dev/null
+++ b/libfuzzer/FuzzerDefs.h
@@ -0,0 +1,75 @@
+//===- FuzzerDefs.h - Internal header for the Fuzzer ------------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Basic definitions.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_DEFS_H
+#define LLVM_FUZZER_DEFS_H
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+
+namespace fuzzer {
+
+template <class T> T Min(T a, T b) { return a < b ? a : b; }
+template <class T> T Max(T a, T b) { return a > b ? a : b; }
+
+class Random;
+class Dictionary;
+class DictionaryEntry;
+class MutationDispatcher;
+struct FuzzingOptions;
+class InputCorpus;
+struct InputInfo;
+struct ExternalFunctions;
+
+// Global interface to functions that may or may not be available.
+extern ExternalFunctions *EF;
+
+// We are using a custom allocator to give a different symbol name to STL
+// containers in order to avoid ODR violations.
+template<typename T>
+  class fuzzer_allocator: public std::allocator<T> {
+    public:
+      fuzzer_allocator() = default;
+
+      template<class U>
+      fuzzer_allocator(const fuzzer_allocator<U>&) {}
+
+      template<class Other>
+      struct rebind { typedef fuzzer_allocator<Other> other;  };
+  };
+
+template<typename T>
+using Vector = std::vector<T, fuzzer_allocator<T>>;
+
+template<typename T>
+using Set = std::set<T, std::less<T>, fuzzer_allocator<T>>;
+
+typedef Vector<uint8_t> Unit;
+typedef Vector<Unit> UnitVector;
+typedef int (*UserCallback)(const uint8_t *Data, size_t Size);
+
+int FuzzerDriver(int *argc, char ***argv, UserCallback Callback);
+
+uint8_t *ExtraCountersBegin();
+uint8_t *ExtraCountersEnd();
+void ClearExtraCounters();
+
+extern bool RunningUserCallback;
+
+}  // namespace fuzzer
+
+#endif  // LLVM_FUZZER_DEFS_H
diff --git a/libfuzzer/FuzzerDictionary.h b/libfuzzer/FuzzerDictionary.h
new file mode 100644
index 0000000..301c5d9
--- /dev/null
+++ b/libfuzzer/FuzzerDictionary.h
@@ -0,0 +1,118 @@
+//===- FuzzerDictionary.h - Internal header for the Fuzzer ------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// fuzzer::Dictionary
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_DICTIONARY_H
+#define LLVM_FUZZER_DICTIONARY_H
+
+#include "FuzzerDefs.h"
+#include "FuzzerIO.h"
+#include "FuzzerUtil.h"
+#include <algorithm>
+#include <limits>
+
+namespace fuzzer {
+// A simple POD sized array of bytes.
+template <size_t kMaxSizeT> class FixedWord {
+public:
+  static const size_t kMaxSize = kMaxSizeT;
+  FixedWord() {}
+  FixedWord(const uint8_t *B, uint8_t S) { Set(B, S); }
+
+  void Set(const uint8_t *B, uint8_t S) {
+    assert(S <= kMaxSize);
+    memcpy(Data, B, S);
+    Size = S;
+  }
+
+  bool operator==(const FixedWord<kMaxSize> &w) const {
+    return Size == w.Size && 0 == memcmp(Data, w.Data, Size);
+  }
+
+  static size_t GetMaxSize() { return kMaxSize; }
+  const uint8_t *data() const { return Data; }
+  uint8_t size() const { return Size; }
+
+private:
+  uint8_t Size = 0;
+  uint8_t Data[kMaxSize];
+};
+
+typedef FixedWord<64> Word;
+
+class DictionaryEntry {
+ public:
+  DictionaryEntry() {}
+  DictionaryEntry(Word W) : W(W) {}
+  DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {}
+  const Word &GetW() const { return W; }
+
+  bool HasPositionHint() const { return PositionHint != std::numeric_limits<size_t>::max(); }
+  size_t GetPositionHint() const {
+    assert(HasPositionHint());
+    return PositionHint;
+  }
+  void IncUseCount() { UseCount++; }
+  void IncSuccessCount() { SuccessCount++; }
+  size_t GetUseCount() const { return UseCount; }
+  size_t GetSuccessCount() const {return SuccessCount; }
+
+  void Print(const char *PrintAfter = "\n") {
+    PrintASCII(W.data(), W.size());
+    if (HasPositionHint())
+      Printf("@%zd", GetPositionHint());
+    Printf("%s", PrintAfter);
+  }
+
+private:
+  Word W;
+  size_t PositionHint = std::numeric_limits<size_t>::max();
+  size_t UseCount = 0;
+  size_t SuccessCount = 0;
+};
+
+class Dictionary {
+ public:
+  static const size_t kMaxDictSize = 1 << 14;
+
+  bool ContainsWord(const Word &W) const {
+    return std::any_of(begin(), end(), [&](const DictionaryEntry &DE) {
+      return DE.GetW() == W;
+    });
+  }
+  const DictionaryEntry *begin() const { return &DE[0]; }
+  const DictionaryEntry *end() const { return begin() + Size; }
+  DictionaryEntry & operator[] (size_t Idx) {
+    assert(Idx < Size);
+    return DE[Idx];
+  }
+  void push_back(DictionaryEntry DE) {
+    if (Size < kMaxDictSize)
+      this->DE[Size++] = DE;
+  }
+  void clear() { Size = 0; }
+  bool empty() const { return Size == 0; }
+  size_t size() const { return Size; }
+
+private:
+  DictionaryEntry DE[kMaxDictSize];
+  size_t Size = 0;
+};
+
+// Parses one dictionary entry.
+// If successful, 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 successfully.
+bool ParseDictionaryFile(const std::string &Text, Vector<Unit> *Units);
+
+}  // namespace fuzzer
+
+#endif  // LLVM_FUZZER_DICTIONARY_H
diff --git a/libfuzzer/FuzzerDriver.cpp b/libfuzzer/FuzzerDriver.cpp
new file mode 100644
index 0000000..00a33a4
--- /dev/null
+++ b/libfuzzer/FuzzerDriver.cpp
@@ -0,0 +1,864 @@
+//===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// FuzzerDriver and flag parsing.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerCommand.h"
+#include "FuzzerCorpus.h"
+#include "FuzzerFork.h"
+#include "FuzzerIO.h"
+#include "FuzzerInterface.h"
+#include "FuzzerInternal.h"
+#include "FuzzerMerge.h"
+#include "FuzzerMutate.h"
+#include "FuzzerPlatform.h"
+#include "FuzzerRandom.h"
+#include "FuzzerTracePC.h"
+#include <algorithm>
+#include <atomic>
+#include <chrono>
+#include <cstdlib>
+#include <cstring>
+#include <mutex>
+#include <string>
+#include <thread>
+#include <fstream>
+
+// This function should be present in the libFuzzer so that the client
+// binary can test for its existence.
+#if LIBFUZZER_MSVC
+extern "C" void __libfuzzer_is_present() {}
+#if defined(_M_IX86) || defined(__i386__)
+#pragma comment(linker, "/include:___libfuzzer_is_present")
+#else
+#pragma comment(linker, "/include:__libfuzzer_is_present")
+#endif
+#else
+extern "C" __attribute__((used)) void __libfuzzer_is_present() {}
+#endif  // LIBFUZZER_MSVC
+
+namespace fuzzer {
+
+// Program arguments.
+struct FlagDescription {
+  const char *Name;
+  const char *Description;
+  int   Default;
+  int   *IntFlag;
+  const char **StrFlag;
+  unsigned int *UIntFlag;
+};
+
+struct {
+#define FUZZER_DEPRECATED_FLAG(Name)
+#define FUZZER_FLAG_INT(Name, Default, Description) int Name;
+#define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name;
+#define FUZZER_FLAG_STRING(Name, Description) const char *Name;
+#include "FuzzerFlags.def"
+#undef FUZZER_DEPRECATED_FLAG
+#undef FUZZER_FLAG_INT
+#undef FUZZER_FLAG_UNSIGNED
+#undef FUZZER_FLAG_STRING
+} Flags;
+
+static const FlagDescription FlagDescriptions [] {
+#define FUZZER_DEPRECATED_FLAG(Name)                                           \
+  {#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr},
+#define FUZZER_FLAG_INT(Name, Default, Description)                            \
+  {#Name, Description, Default, &Flags.Name, nullptr, nullptr},
+#define FUZZER_FLAG_UNSIGNED(Name, Default, Description)                       \
+  {#Name,   Description, static_cast<int>(Default),                            \
+   nullptr, nullptr, &Flags.Name},
+#define FUZZER_FLAG_STRING(Name, Description)                                  \
+  {#Name, Description, 0, nullptr, &Flags.Name, nullptr},
+#include "FuzzerFlags.def"
+#undef FUZZER_DEPRECATED_FLAG
+#undef FUZZER_FLAG_INT
+#undef FUZZER_FLAG_UNSIGNED
+#undef FUZZER_FLAG_STRING
+};
+
+static const size_t kNumFlags =
+    sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]);
+
+static Vector<std::string> *Inputs;
+static std::string *ProgName;
+
+static void PrintHelp() {
+  Printf("Usage:\n");
+  auto Prog = ProgName->c_str();
+  Printf("\nTo run fuzzing pass 0 or more directories.\n");
+  Printf("%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog);
+
+  Printf("\nTo run individual tests without fuzzing pass 1 or more files:\n");
+  Printf("%s [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n", Prog);
+
+  Printf("\nFlags: (strictly in form -flag=value)\n");
+  size_t MaxFlagLen = 0;
+  for (size_t F = 0; F < kNumFlags; F++)
+    MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen);
+
+  for (size_t F = 0; F < kNumFlags; F++) {
+    const auto &D = FlagDescriptions[F];
+    if (strstr(D.Description, "internal flag") == D.Description) continue;
+    Printf(" %s", D.Name);
+    for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++)
+      Printf(" ");
+    Printf("\t");
+    Printf("%d\t%s\n", D.Default, D.Description);
+  }
+  Printf("\nFlags starting with '--' will be ignored and "
+            "will be passed verbatim to subprocesses.\n");
+}
+
+static const char *FlagValue(const char *Param, const char *Name) {
+  size_t Len = strlen(Name);
+  if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 &&
+      Param[Len + 1] == '=')
+      return &Param[Len + 2];
+  return nullptr;
+}
+
+// Avoid calling stol as it triggers a bug in clang/glibc build.
+static long MyStol(const char *Str) {
+  long Res = 0;
+  long Sign = 1;
+  if (*Str == '-') {
+    Str++;
+    Sign = -1;
+  }
+  for (size_t i = 0; Str[i]; i++) {
+    char Ch = Str[i];
+    if (Ch < '0' || Ch > '9')
+      return Res;
+    Res = Res * 10 + (Ch - '0');
+  }
+  return Res * Sign;
+}
+
+static bool ParseOneFlag(const char *Param) {
+  if (Param[0] != '-') return false;
+  if (Param[1] == '-') {
+    static bool PrintedWarning = false;
+    if (!PrintedWarning) {
+      PrintedWarning = true;
+      Printf("INFO: libFuzzer ignores flags that start with '--'\n");
+    }
+    for (size_t F = 0; F < kNumFlags; F++)
+      if (FlagValue(Param + 1, FlagDescriptions[F].Name))
+        Printf("WARNING: did you mean '%s' (single dash)?\n", Param + 1);
+    return true;
+  }
+  for (size_t F = 0; F < kNumFlags; F++) {
+    const char *Name = FlagDescriptions[F].Name;
+    const char *Str = FlagValue(Param, Name);
+    if (Str)  {
+      if (FlagDescriptions[F].IntFlag) {
+        int Val = MyStol(Str);
+        *FlagDescriptions[F].IntFlag = Val;
+        if (Flags.verbosity >= 2)
+          Printf("Flag: %s %d\n", Name, Val);
+        return true;
+      } else if (FlagDescriptions[F].UIntFlag) {
+        unsigned int Val = std::stoul(Str);
+        *FlagDescriptions[F].UIntFlag = Val;
+        if (Flags.verbosity >= 2)
+          Printf("Flag: %s %u\n", Name, Val);
+        return true;
+      } else if (FlagDescriptions[F].StrFlag) {
+        *FlagDescriptions[F].StrFlag = Str;
+        if (Flags.verbosity >= 2)
+          Printf("Flag: %s %s\n", Name, Str);
+        return true;
+      } else {  // Deprecated flag.
+        Printf("Flag: %s: deprecated, don't use\n", Name);
+        return true;
+      }
+    }
+  }
+  Printf("\n\nWARNING: unrecognized flag '%s'; "
+         "use -help=1 to list all flags\n\n", Param);
+  return true;
+}
+
+// We don't use any library to minimize dependencies.
+static void ParseFlags(const Vector<std::string> &Args,
+                       const ExternalFunctions *EF) {
+  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;
+  }
+
+  // Disable len_control by default, if LLVMFuzzerCustomMutator is used.
+  if (EF->LLVMFuzzerCustomMutator) {
+    Flags.len_control = 0;
+    Printf("INFO: found LLVMFuzzerCustomMutator (%p). "
+           "Disabling -len_control by default.\n", EF->LLVMFuzzerCustomMutator);
+  }
+
+  Inputs = new Vector<std::string>;
+  for (size_t A = 1; A < Args.size(); A++) {
+    if (ParseOneFlag(Args[A].c_str())) {
+      if (Flags.ignore_remaining_args)
+        break;
+      continue;
+    }
+    Inputs->push_back(Args[A]);
+  }
+}
+
+static std::mutex Mu;
+
+static void PulseThread() {
+  while (true) {
+    SleepSeconds(600);
+    std::lock_guard<std::mutex> Lock(Mu);
+    Printf("pulse...\n");
+  }
+}
+
+static void WorkerThread(const Command &BaseCmd, std::atomic<unsigned> *Counter,
+                         unsigned NumJobs, std::atomic<bool> *HasErrors) {
+  while (true) {
+    unsigned C = (*Counter)++;
+    if (C >= NumJobs) break;
+    std::string Log = "fuzz-" + std::to_string(C) + ".log";
+    Command Cmd(BaseCmd);
+    Cmd.setOutputFile(Log);
+    Cmd.combineOutAndErr();
+    if (Flags.verbosity) {
+      std::string CommandLine = Cmd.toString();
+      Printf("%s\n", CommandLine.c_str());
+    }
+    int ExitCode = ExecuteCommand(Cmd);
+    if (ExitCode != 0)
+      *HasErrors = true;
+    std::lock_guard<std::mutex> Lock(Mu);
+    Printf("================== Job %u exited with exit code %d ============\n",
+           C, ExitCode);
+    fuzzer::CopyFileToErr(Log);
+  }
+}
+
+std::string CloneArgsWithoutX(const Vector<std::string> &Args,
+                              const char *X1, const char *X2) {
+  std::string Cmd;
+  for (auto &S : Args) {
+    if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2))
+      continue;
+    Cmd += S + " ";
+  }
+  return Cmd;
+}
+
+static int RunInMultipleProcesses(const Vector<std::string> &Args,
+                                  unsigned NumWorkers, unsigned NumJobs) {
+  std::atomic<unsigned> Counter(0);
+  std::atomic<bool> HasErrors(false);
+  Command Cmd(Args);
+  Cmd.removeFlag("jobs");
+  Cmd.removeFlag("workers");
+  Vector<std::thread> V;
+  std::thread Pulse(PulseThread);
+  Pulse.detach();
+  for (unsigned i = 0; i < NumWorkers; i++)
+    V.push_back(std::thread(WorkerThread, std::ref(Cmd), &Counter, NumJobs, &HasErrors));
+  for (auto &T : V)
+    T.join();
+  return HasErrors ? 1 : 0;
+}
+
+static void RssThread(Fuzzer *F, size_t RssLimitMb) {
+  while (true) {
+    SleepSeconds(1);
+    size_t Peak = GetPeakRSSMb();
+    if (Peak > RssLimitMb)
+      F->RssLimitCallback();
+  }
+}
+
+static void StartRssThread(Fuzzer *F, size_t RssLimitMb) {
+  if (!RssLimitMb)
+    return;
+  std::thread T(RssThread, F, RssLimitMb);
+  T.detach();
+}
+
+int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) {
+  Unit U = FileToVector(InputFilePath);
+  if (MaxLen && MaxLen < U.size())
+    U.resize(MaxLen);
+  F->ExecuteCallback(U.data(), U.size());
+  F->TryDetectingAMemoryLeak(U.data(), U.size(), true);
+  return 0;
+}
+
+static bool AllInputsAreFiles() {
+  if (Inputs->empty()) return false;
+  for (auto &Path : *Inputs)
+    if (!IsFile(Path))
+      return false;
+  return true;
+}
+
+static std::string GetDedupTokenFromCmdOutput(const std::string &S) {
+  auto Beg = S.find("DEDUP_TOKEN:");
+  if (Beg == std::string::npos)
+    return "";
+  auto End = S.find('\n', Beg);
+  if (End == std::string::npos)
+    return "";
+  return S.substr(Beg, End - Beg);
+}
+
+int CleanseCrashInput(const Vector<std::string> &Args,
+                       const FuzzingOptions &Options) {
+  if (Inputs->size() != 1 || !Flags.exact_artifact_path) {
+    Printf("ERROR: -cleanse_crash should be given one input file and"
+          " -exact_artifact_path\n");
+    exit(1);
+  }
+  std::string InputFilePath = Inputs->at(0);
+  std::string OutputFilePath = Flags.exact_artifact_path;
+  Command Cmd(Args);
+  Cmd.removeFlag("cleanse_crash");
+
+  assert(Cmd.hasArgument(InputFilePath));
+  Cmd.removeArgument(InputFilePath);
+
+  auto TmpFilePath = TempPath("CleanseCrashInput", ".repro");
+  Cmd.addArgument(TmpFilePath);
+  Cmd.setOutputFile(getDevNull());
+  Cmd.combineOutAndErr();
+
+  std::string CurrentFilePath = InputFilePath;
+  auto U = FileToVector(CurrentFilePath);
+  size_t Size = U.size();
+
+  const Vector<uint8_t> ReplacementBytes = {' ', 0xff};
+  for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) {
+    bool Changed = false;
+    for (size_t Idx = 0; Idx < Size; Idx++) {
+      Printf("CLEANSE[%d]: Trying to replace byte %zd of %zd\n", NumAttempts,
+             Idx, Size);
+      uint8_t OriginalByte = U[Idx];
+      if (ReplacementBytes.end() != std::find(ReplacementBytes.begin(),
+                                              ReplacementBytes.end(),
+                                              OriginalByte))
+        continue;
+      for (auto NewByte : ReplacementBytes) {
+        U[Idx] = NewByte;
+        WriteToFile(U, TmpFilePath);
+        auto ExitCode = ExecuteCommand(Cmd);
+        RemoveFile(TmpFilePath);
+        if (!ExitCode) {
+          U[Idx] = OriginalByte;
+        } else {
+          Changed = true;
+          Printf("CLEANSE: Replaced byte %zd with 0x%x\n", Idx, NewByte);
+          WriteToFile(U, OutputFilePath);
+          break;
+        }
+      }
+    }
+    if (!Changed) break;
+  }
+  return 0;
+}
+
+int MinimizeCrashInput(const Vector<std::string> &Args,
+                       const FuzzingOptions &Options) {
+  if (Inputs->size() != 1) {
+    Printf("ERROR: -minimize_crash should be given one input file\n");
+    exit(1);
+  }
+  std::string InputFilePath = Inputs->at(0);
+  Command BaseCmd(Args);
+  BaseCmd.removeFlag("minimize_crash");
+  BaseCmd.removeFlag("exact_artifact_path");
+  assert(BaseCmd.hasArgument(InputFilePath));
+  BaseCmd.removeArgument(InputFilePath);
+  if (Flags.runs <= 0 && Flags.max_total_time == 0) {
+    Printf("INFO: you need to specify -runs=N or "
+           "-max_total_time=N with -minimize_crash=1\n"
+           "INFO: defaulting to -max_total_time=600\n");
+    BaseCmd.addFlag("max_total_time", "600");
+  }
+
+  BaseCmd.combineOutAndErr();
+
+  std::string CurrentFilePath = InputFilePath;
+  while (true) {
+    Unit U = FileToVector(CurrentFilePath);
+    Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n",
+           CurrentFilePath.c_str(), U.size());
+
+    Command Cmd(BaseCmd);
+    Cmd.addArgument(CurrentFilePath);
+
+    Printf("CRASH_MIN: executing: %s\n", Cmd.toString().c_str());
+    std::string CmdOutput;
+    bool Success = ExecuteCommand(Cmd, &CmdOutput);
+    if (Success) {
+      Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str());
+      exit(1);
+    }
+    Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize "
+           "it further\n",
+           CurrentFilePath.c_str(), U.size());
+    auto DedupToken1 = GetDedupTokenFromCmdOutput(CmdOutput);
+    if (!DedupToken1.empty())
+      Printf("CRASH_MIN: DedupToken1: %s\n", DedupToken1.c_str());
+
+    std::string ArtifactPath =
+        Flags.exact_artifact_path
+            ? Flags.exact_artifact_path
+            : Options.ArtifactPrefix + "minimized-from-" + Hash(U);
+    Cmd.addFlag("minimize_crash_internal_step", "1");
+    Cmd.addFlag("exact_artifact_path", ArtifactPath);
+    Printf("CRASH_MIN: executing: %s\n", Cmd.toString().c_str());
+    CmdOutput.clear();
+    Success = ExecuteCommand(Cmd, &CmdOutput);
+    Printf("%s", CmdOutput.c_str());
+    if (Success) {
+      if (Flags.exact_artifact_path) {
+        CurrentFilePath = Flags.exact_artifact_path;
+        WriteToFile(U, CurrentFilePath);
+      }
+      Printf("CRASH_MIN: failed to minimize beyond %s (%d bytes), exiting\n",
+             CurrentFilePath.c_str(), U.size());
+      break;
+    }
+    auto DedupToken2 = GetDedupTokenFromCmdOutput(CmdOutput);
+    if (!DedupToken2.empty())
+      Printf("CRASH_MIN: DedupToken2: %s\n", DedupToken2.c_str());
+
+    if (DedupToken1 != DedupToken2) {
+      if (Flags.exact_artifact_path) {
+        CurrentFilePath = Flags.exact_artifact_path;
+        WriteToFile(U, CurrentFilePath);
+      }
+      Printf("CRASH_MIN: mismatch in dedup tokens"
+             " (looks like a different bug). Won't minimize further\n");
+      break;
+    }
+
+    CurrentFilePath = ArtifactPath;
+    Printf("*********************************\n");
+  }
+  return 0;
+}
+
+int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) {
+  assert(Inputs->size() == 1);
+  std::string InputFilePath = Inputs->at(0);
+  Unit U = FileToVector(InputFilePath);
+  Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size());
+  if (U.size() < 2) {
+    Printf("INFO: The input is small enough, exiting\n");
+    exit(0);
+  }
+  F->SetMaxInputLen(U.size());
+  F->SetMaxMutationLen(U.size() - 1);
+  F->MinimizeCrashLoop(U);
+  Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n");
+  exit(0);
+  return 0;
+}
+
+void Merge(Fuzzer *F, FuzzingOptions &Options, const Vector<std::string> &Args,
+           const Vector<std::string> &Corpora, const char *CFPathOrNull) {
+  if (Corpora.size() < 2) {
+    Printf("INFO: Merge requires two or more corpus dirs\n");
+    exit(0);
+  }
+
+  Vector<SizedFile> OldCorpus, NewCorpus;
+  GetSizedFilesFromDir(Corpora[0], &OldCorpus);
+  for (size_t i = 1; i < Corpora.size(); i++)
+    GetSizedFilesFromDir(Corpora[i], &NewCorpus);
+  std::sort(OldCorpus.begin(), OldCorpus.end());
+  std::sort(NewCorpus.begin(), NewCorpus.end());
+
+  std::string CFPath = CFPathOrNull ? CFPathOrNull : TempPath("Merge", ".txt");
+  Vector<std::string> NewFiles;
+  Set<uint32_t> NewFeatures, NewCov;
+  CrashResistantMerge(Args, OldCorpus, NewCorpus, &NewFiles, {}, &NewFeatures,
+                      {}, &NewCov, CFPath, true);
+  for (auto &Path : NewFiles)
+    F->WriteToOutputCorpus(FileToVector(Path, Options.MaxLen));
+  // We are done, delete the control file if it was a temporary one.
+  if (!Flags.merge_control_file)
+    RemoveFile(CFPath);
+
+  exit(0);
+}
+
+int AnalyzeDictionary(Fuzzer *F, const Vector<Unit>& Dict,
+                      UnitVector& Corpus) {
+  Printf("Started dictionary minimization (up to %d tests)\n",
+         Dict.size() * Corpus.size() * 2);
+
+  // Scores and usage count for each dictionary unit.
+  Vector<int> Scores(Dict.size());
+  Vector<int> Usages(Dict.size());
+
+  Vector<size_t> InitialFeatures;
+  Vector<size_t> ModifiedFeatures;
+  for (auto &C : Corpus) {
+    // Get coverage for the testcase without modifications.
+    F->ExecuteCallback(C.data(), C.size());
+    InitialFeatures.clear();
+    TPC.CollectFeatures([&](size_t Feature) {
+      InitialFeatures.push_back(Feature);
+    });
+
+    for (size_t i = 0; i < Dict.size(); ++i) {
+      Vector<uint8_t> Data = C;
+      auto StartPos = std::search(Data.begin(), Data.end(),
+                                  Dict[i].begin(), Dict[i].end());
+      // Skip dictionary unit, if the testcase does not contain it.
+      if (StartPos == Data.end())
+        continue;
+
+      ++Usages[i];
+      while (StartPos != Data.end()) {
+        // Replace all occurrences of dictionary unit in the testcase.
+        auto EndPos = StartPos + Dict[i].size();
+        for (auto It = StartPos; It != EndPos; ++It)
+          *It ^= 0xFF;
+
+        StartPos = std::search(EndPos, Data.end(),
+                               Dict[i].begin(), Dict[i].end());
+      }
+
+      // Get coverage for testcase with masked occurrences of dictionary unit.
+      F->ExecuteCallback(Data.data(), Data.size());
+      ModifiedFeatures.clear();
+      TPC.CollectFeatures([&](size_t Feature) {
+        ModifiedFeatures.push_back(Feature);
+      });
+
+      if (InitialFeatures == ModifiedFeatures)
+        --Scores[i];
+      else
+        Scores[i] += 2;
+    }
+  }
+
+  Printf("###### Useless dictionary elements. ######\n");
+  for (size_t i = 0; i < Dict.size(); ++i) {
+    // Dictionary units with positive score are treated as useful ones.
+    if (Scores[i] > 0)
+       continue;
+
+    Printf("\"");
+    PrintASCII(Dict[i].data(), Dict[i].size(), "\"");
+    Printf(" # Score: %d, Used: %d\n", Scores[i], Usages[i]);
+  }
+  Printf("###### End of useless dictionary elements. ######\n");
+  return 0;
+}
+
+Vector<std::string> ParseSeedInuts(const char *seed_inputs) {
+  // Parse -seed_inputs=file1,file2,... or -seed_inputs=@seed_inputs_file
+  Vector<std::string> Files;
+  if (!seed_inputs) return Files;
+  std::string SeedInputs;
+  if (Flags.seed_inputs[0] == '@')
+    SeedInputs = FileToString(Flags.seed_inputs + 1); // File contains list.
+  else
+    SeedInputs = Flags.seed_inputs; // seed_inputs contains the list.
+  if (SeedInputs.empty()) {
+    Printf("seed_inputs is empty or @file does not exist.\n");
+    exit(1);
+  }
+  // Parse SeedInputs.
+  size_t comma_pos = 0;
+  while ((comma_pos = SeedInputs.find_last_of(',')) != std::string::npos) {
+    Files.push_back(SeedInputs.substr(comma_pos + 1));
+    SeedInputs = SeedInputs.substr(0, comma_pos);
+  }
+  Files.push_back(SeedInputs);
+  return Files;
+}
+
+static Vector<SizedFile> ReadCorpora(const Vector<std::string> &CorpusDirs,
+    const Vector<std::string> &ExtraSeedFiles) {
+  Vector<SizedFile> SizedFiles;
+  size_t LastNumFiles = 0;
+  for (auto &Dir : CorpusDirs) {
+    GetSizedFilesFromDir(Dir, &SizedFiles);
+    Printf("INFO: % 8zd files found in %s\n", SizedFiles.size() - LastNumFiles,
+           Dir.c_str());
+    LastNumFiles = SizedFiles.size();
+  }
+  for (auto &File : ExtraSeedFiles)
+    if (auto Size = FileSize(File))
+      SizedFiles.push_back({File, Size});
+  return SizedFiles;
+}
+
+int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
+  using namespace fuzzer;
+  assert(argc && argv && "Argument pointers cannot be nullptr");
+  std::string Argv0((*argv)[0]);
+  EF = new ExternalFunctions();
+  if (EF->LLVMFuzzerInitialize)
+    EF->LLVMFuzzerInitialize(argc, argv);
+  if (EF->__msan_scoped_disable_interceptor_checks)
+    EF->__msan_scoped_disable_interceptor_checks();
+  const Vector<std::string> Args(*argv, *argv + *argc);
+  assert(!Args.empty());
+  ProgName = new std::string(Args[0]);
+  if (Argv0 != *ProgName) {
+    Printf("ERROR: argv[0] has been modified in LLVMFuzzerInitialize\n");
+    exit(1);
+  }
+  ParseFlags(Args, EF);
+  if (Flags.help) {
+    PrintHelp();
+    return 0;
+  }
+
+  if (Flags.close_fd_mask & 2)
+    DupAndCloseStderr();
+  if (Flags.close_fd_mask & 1)
+    CloseStdout();
+
+  if (Flags.jobs > 0 && Flags.workers == 0) {
+    Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs);
+    if (Flags.workers > 1)
+      Printf("Running %u workers\n", Flags.workers);
+  }
+
+  if (Flags.workers > 0 && Flags.jobs > 0)
+    return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs);
+
+  FuzzingOptions Options;
+  Options.Verbosity = Flags.verbosity;
+  Options.MaxLen = Flags.max_len;
+  Options.LenControl = Flags.len_control;
+  Options.UnitTimeoutSec = Flags.timeout;
+  Options.ErrorExitCode = Flags.error_exitcode;
+  Options.TimeoutExitCode = Flags.timeout_exitcode;
+  Options.IgnoreTimeouts = Flags.ignore_timeouts;
+  Options.IgnoreOOMs = Flags.ignore_ooms;
+  Options.IgnoreCrashes = Flags.ignore_crashes;
+  Options.MaxTotalTimeSec = Flags.max_total_time;
+  Options.DoCrossOver = Flags.cross_over;
+  Options.MutateDepth = Flags.mutate_depth;
+  Options.ReduceDepth = Flags.reduce_depth;
+  Options.UseCounters = Flags.use_counters;
+  Options.UseMemmem = Flags.use_memmem;
+  Options.UseCmp = Flags.use_cmp;
+  Options.UseValueProfile = Flags.use_value_profile;
+  Options.Shrink = Flags.shrink;
+  Options.ReduceInputs = Flags.reduce_inputs;
+  Options.ShuffleAtStartUp = Flags.shuffle;
+  Options.PreferSmall = Flags.prefer_small;
+  Options.ReloadIntervalSec = Flags.reload;
+  Options.OnlyASCII = Flags.only_ascii;
+  Options.DetectLeaks = Flags.detect_leaks;
+  Options.PurgeAllocatorIntervalSec = Flags.purge_allocator_interval;
+  Options.TraceMalloc = Flags.trace_malloc;
+  Options.RssLimitMb = Flags.rss_limit_mb;
+  Options.MallocLimitMb = Flags.malloc_limit_mb;
+  if (!Options.MallocLimitMb)
+    Options.MallocLimitMb = Options.RssLimitMb;
+  if (Flags.runs >= 0)
+    Options.MaxNumberOfRuns = Flags.runs;
+  if (!Inputs->empty() && !Flags.minimize_crash_internal_step)
+    Options.OutputCorpus = (*Inputs)[0];
+  Options.ReportSlowUnits = Flags.report_slow_units;
+  if (Flags.artifact_prefix)
+    Options.ArtifactPrefix = Flags.artifact_prefix;
+  if (Flags.exact_artifact_path)
+    Options.ExactArtifactPath = Flags.exact_artifact_path;
+  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());
+  bool RunIndividualFiles = AllInputsAreFiles();
+  Options.SaveArtifacts =
+      !RunIndividualFiles || Flags.minimize_crash_internal_step;
+  Options.PrintNewCovPcs = Flags.print_pcs;
+  Options.PrintNewCovFuncs = Flags.print_funcs;
+  Options.PrintFinalStats = Flags.print_final_stats;
+  Options.PrintCorpusStats = Flags.print_corpus_stats;
+  Options.PrintCoverage = Flags.print_coverage;
+  if (Flags.exit_on_src_pos)
+    Options.ExitOnSrcPos = Flags.exit_on_src_pos;
+  if (Flags.exit_on_item)
+    Options.ExitOnItem = Flags.exit_on_item;
+  if (Flags.focus_function)
+    Options.FocusFunction = Flags.focus_function;
+  if (Flags.data_flow_trace)
+    Options.DataFlowTrace = Flags.data_flow_trace;
+  if (Flags.features_dir)
+    Options.FeaturesDir = Flags.features_dir;
+  if (Flags.collect_data_flow)
+    Options.CollectDataFlow = Flags.collect_data_flow;
+  if (Flags.stop_file)
+    Options.StopFile = Flags.stop_file;
+  Options.Entropic = Flags.entropic;
+  Options.EntropicFeatureFrequencyThreshold =
+      (size_t)Flags.entropic_feature_frequency_threshold;
+  Options.EntropicNumberOfRarestFeatures =
+      (size_t)Flags.entropic_number_of_rarest_features;
+  if (Options.Entropic) {
+    if (!Options.FocusFunction.empty()) {
+      Printf("ERROR: The parameters `--entropic` and `--focus_function` cannot "
+             "be used together.\n");
+      exit(1);
+    }
+    Printf("INFO: Running with entropic power schedule (0x%X, %d).\n",
+           Options.EntropicFeatureFrequencyThreshold,
+           Options.EntropicNumberOfRarestFeatures);
+  }
+  struct EntropicOptions Entropic;
+  Entropic.Enabled = Options.Entropic;
+  Entropic.FeatureFrequencyThreshold =
+      Options.EntropicFeatureFrequencyThreshold;
+  Entropic.NumberOfRarestFeatures = Options.EntropicNumberOfRarestFeatures;
+
+  unsigned Seed = Flags.seed;
+  // Initialize Seed.
+  if (Seed == 0)
+    Seed =
+        std::chrono::system_clock::now().time_since_epoch().count() + GetPid();
+  if (Flags.verbosity)
+    Printf("INFO: Seed: %u\n", Seed);
+
+  if (Flags.collect_data_flow && !Flags.fork && !Flags.merge) {
+    if (RunIndividualFiles)
+      return CollectDataFlow(Flags.collect_data_flow, Flags.data_flow_trace,
+                        ReadCorpora({}, *Inputs));
+    else
+      return CollectDataFlow(Flags.collect_data_flow, Flags.data_flow_trace,
+                        ReadCorpora(*Inputs, {}));
+  }
+
+  Random Rand(Seed);
+  auto *MD = new MutationDispatcher(Rand, Options);
+  auto *Corpus = new InputCorpus(Options.OutputCorpus, Entropic);
+  auto *F = new Fuzzer(Callback, *Corpus, *MD, Options);
+
+  for (auto &U: Dictionary)
+    if (U.size() <= Word::GetMaxSize())
+      MD->AddWordToManualDictionary(Word(U.data(), U.size()));
+
+      // Threads are only supported by Chrome. Don't use them with emscripten
+      // for now.
+#if !LIBFUZZER_EMSCRIPTEN
+  StartRssThread(F, Flags.rss_limit_mb);
+#endif // LIBFUZZER_EMSCRIPTEN
+
+  Options.HandleAbrt = Flags.handle_abrt;
+  Options.HandleBus = Flags.handle_bus;
+  Options.HandleFpe = Flags.handle_fpe;
+  Options.HandleIll = Flags.handle_ill;
+  Options.HandleInt = Flags.handle_int;
+  Options.HandleSegv = Flags.handle_segv;
+  Options.HandleTerm = Flags.handle_term;
+  Options.HandleXfsz = Flags.handle_xfsz;
+  Options.HandleUsr1 = Flags.handle_usr1;
+  Options.HandleUsr2 = Flags.handle_usr2;
+  SetSignalHandler(Options);
+
+  std::atexit(Fuzzer::StaticExitCallback);
+
+  if (Flags.minimize_crash)
+    return MinimizeCrashInput(Args, Options);
+
+  if (Flags.minimize_crash_internal_step)
+    return MinimizeCrashInputInternalStep(F, Corpus);
+
+  if (Flags.cleanse_crash)
+    return CleanseCrashInput(Args, Options);
+
+  if (RunIndividualFiles) {
+    Options.SaveArtifacts = false;
+    int Runs = std::max(1, Flags.runs);
+    Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName->c_str(),
+           Inputs->size(), Runs);
+    for (auto &Path : *Inputs) {
+      auto StartTime = system_clock::now();
+      Printf("Running: %s\n", Path.c_str());
+      for (int Iter = 0; Iter < Runs; Iter++)
+        RunOneTest(F, Path.c_str(), Options.MaxLen);
+      auto StopTime = system_clock::now();
+      auto MS = duration_cast<milliseconds>(StopTime - StartTime).count();
+      Printf("Executed %s in %zd ms\n", Path.c_str(), (long)MS);
+    }
+    Printf("***\n"
+           "*** NOTE: fuzzing was not performed, you have only\n"
+           "***       executed the target code on a fixed set of inputs.\n"
+           "***\n");
+    F->PrintFinalStats();
+    exit(0);
+  }
+
+  if (Flags.fork)
+    FuzzWithFork(F->GetMD().GetRand(), Options, Args, *Inputs, Flags.fork);
+
+  if (Flags.merge)
+    Merge(F, Options, Args, *Inputs, Flags.merge_control_file);
+
+  if (Flags.merge_inner) {
+    const size_t kDefaultMaxMergeLen = 1 << 20;
+    if (Options.MaxLen == 0)
+      F->SetMaxInputLen(kDefaultMaxMergeLen);
+    assert(Flags.merge_control_file);
+    F->CrashResistantMergeInternalStep(Flags.merge_control_file);
+    exit(0);
+  }
+
+  if (Flags.analyze_dict) {
+    size_t MaxLen = INT_MAX;  // Large max length.
+    UnitVector InitialCorpus;
+    for (auto &Inp : *Inputs) {
+      Printf("Loading corpus dir: %s\n", Inp.c_str());
+      ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr,
+                             MaxLen, /*ExitOnError=*/false);
+    }
+
+    if (Dictionary.empty() || Inputs->empty()) {
+      Printf("ERROR: can't analyze dict without dict and corpus provided\n");
+      return 1;
+    }
+    if (AnalyzeDictionary(F, Dictionary, InitialCorpus)) {
+      Printf("Dictionary analysis failed\n");
+      exit(1);
+    }
+    Printf("Dictionary analysis succeeded\n");
+    exit(0);
+  }
+
+  auto CorporaFiles = ReadCorpora(*Inputs, ParseSeedInuts(Flags.seed_inputs));
+  F->Loop(CorporaFiles);
+
+  if (Flags.verbosity)
+    Printf("Done %zd runs in %zd second(s)\n", F->getTotalNumberOfRuns(),
+           F->secondsSinceProcessStartUp());
+  F->PrintFinalStats();
+
+  exit(0);  // Don't let F destroy itself.
+}
+
+// Storage for global ExternalFunctions object.
+ExternalFunctions *EF = nullptr;
+
+}  // namespace fuzzer
diff --git a/libfuzzer/FuzzerExtFunctions.def b/libfuzzer/FuzzerExtFunctions.def
new file mode 100644
index 0000000..51edf84
--- /dev/null
+++ b/libfuzzer/FuzzerExtFunctions.def
@@ -0,0 +1,50 @@
+//===- FuzzerExtFunctions.def - External functions --------------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// 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_acquire_crash_state, int, (), true);
+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_log_write, void, (const char *buf, size_t len), false);
+EXT_FUNC(__sanitizer_purge_allocator, void, (), false);
+EXT_FUNC(__sanitizer_print_memory_profile, void, (size_t, size_t), false);
+EXT_FUNC(__sanitizer_print_stack_trace, void, (), true);
+EXT_FUNC(__sanitizer_symbolize_pc, void,
+         (void *, const char *fmt, char *out_buf, size_t out_buf_size), false);
+EXT_FUNC(__sanitizer_get_module_and_offset_for_pc, int,
+         (void *pc, char *module_path,
+         size_t module_path_len,void **pc_offset), false);
+EXT_FUNC(__sanitizer_set_death_callback, void, (void (*)(void)), true);
+EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false);
+EXT_FUNC(__msan_scoped_disable_interceptor_checks, void, (), false);
+EXT_FUNC(__msan_scoped_enable_interceptor_checks, void, (), false);
+EXT_FUNC(__msan_unpoison, void, (const volatile void *, size_t size), false);
+EXT_FUNC(__msan_unpoison_param, void, (size_t n), false);
diff --git a/libfuzzer/FuzzerExtFunctions.h b/libfuzzer/FuzzerExtFunctions.h
new file mode 100644
index 0000000..c88aac4
--- /dev/null
+++ b/libfuzzer/FuzzerExtFunctions.h
@@ -0,0 +1,34 @@
+//===- FuzzerExtFunctions.h - Interface to external functions ---*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// 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/libfuzzer/FuzzerExtFunctionsDlsym.cpp b/libfuzzer/FuzzerExtFunctionsDlsym.cpp
new file mode 100644
index 0000000..95233d2
--- /dev/null
+++ b/libfuzzer/FuzzerExtFunctionsDlsym.cpp
@@ -0,0 +1,51 @@
+//===- FuzzerExtFunctionsDlsym.cpp - Interface to external functions ------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// 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 "FuzzerPlatform.h"
+#if LIBFUZZER_APPLE
+
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.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/libfuzzer/FuzzerExtFunctionsWeak.cpp b/libfuzzer/FuzzerExtFunctionsWeak.cpp
new file mode 100644
index 0000000..24ddc57
--- /dev/null
+++ b/libfuzzer/FuzzerExtFunctionsWeak.cpp
@@ -0,0 +1,54 @@
+//===- FuzzerExtFunctionsWeak.cpp - Interface to external functions -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// 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 "FuzzerPlatform.h"
+#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FUCHSIA ||                \
+    LIBFUZZER_FREEBSD || LIBFUZZER_OPENBSD || LIBFUZZER_EMSCRIPTEN
+
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+
+extern "C" {
+// Declare these symbols as weak to allow them to be optionally defined.
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN)                            \
+  __attribute__((weak, visibility("default"))) RETURN_TYPE NAME FUNC_SIG
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+}
+
+using namespace fuzzer;
+
+static void CheckFnPtr(void *FnPtr, const char *FnName, bool WarnIfMissing) {
+  if (FnPtr == nullptr && WarnIfMissing) {
+    Printf("WARNING: Failed to find function \"%s\".\n", FnName);
+  }
+}
+
+namespace fuzzer {
+
+ExternalFunctions::ExternalFunctions() {
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN)                            \
+  this->NAME = ::NAME;                                                         \
+  CheckFnPtr(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(::NAME)),    \
+             #NAME, WARN);
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+}
+
+} // namespace fuzzer
+
+#endif
diff --git a/libfuzzer/FuzzerExtFunctionsWindows.cpp b/libfuzzer/FuzzerExtFunctionsWindows.cpp
new file mode 100644
index 0000000..688bad1
--- /dev/null
+++ b/libfuzzer/FuzzerExtFunctionsWindows.cpp
@@ -0,0 +1,82 @@
+//=== FuzzerExtWindows.cpp - Interface to external functions --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Implementation of FuzzerExtFunctions for Windows. Uses alternatename when
+// compiled with MSVC. Uses weak aliases when compiled with clang. Unfortunately
+// the method each compiler supports is not supported by the other.
+//===----------------------------------------------------------------------===//
+#include "FuzzerPlatform.h"
+#if LIBFUZZER_WINDOWS
+
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+
+using namespace fuzzer;
+
+// Intermediate macro to ensure the parameter is expanded before stringified.
+#define STRINGIFY_(A) #A
+#define STRINGIFY(A) STRINGIFY_(A)
+
+#if LIBFUZZER_MSVC
+// Copied from compiler-rt/lib/sanitizer_common/sanitizer_win_defs.h
+#if defined(_M_IX86) || defined(__i386__)
+#define WIN_SYM_PREFIX "_"
+#else
+#define WIN_SYM_PREFIX
+#endif
+
+// Declare external functions as having alternativenames, so that we can
+// determine if they are not defined.
+#define EXTERNAL_FUNC(Name, Default)                                   \
+  __pragma(comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY( \
+                               Name) "=" WIN_SYM_PREFIX STRINGIFY(Default)))
+#else
+// Declare external functions as weak to allow them to default to a specified
+// function if not defined explicitly. We must use weak symbols because clang's
+// support for alternatename is not 100%, see
+// https://bugs.llvm.org/show_bug.cgi?id=40218 for more details.
+#define EXTERNAL_FUNC(Name, Default) \
+  __attribute__((weak, alias(STRINGIFY(Default))))
+#endif  // LIBFUZZER_MSVC
+
+extern "C" {
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN)         \
+  RETURN_TYPE NAME##Def FUNC_SIG {                          \
+    Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \
+    exit(1);                                                \
+  }                                                         \
+  EXTERNAL_FUNC(NAME, NAME##Def) RETURN_TYPE NAME FUNC_SIG
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+}
+
+template <typename T>
+static T *GetFnPtr(T *Fun, T *FunDef, const char *FnName, bool WarnIfMissing) {
+  if (Fun == FunDef) {
+    if (WarnIfMissing)
+      Printf("WARNING: Failed to find function \"%s\".\n", FnName);
+    return nullptr;
+  }
+  return Fun;
+}
+
+namespace fuzzer {
+
+ExternalFunctions::ExternalFunctions() {
+#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
+  this->NAME = GetFnPtr<decltype(::NAME)>(::NAME, ::NAME##Def, #NAME, WARN);
+
+#include "FuzzerExtFunctions.def"
+
+#undef EXT_FUNC
+}
+
+}  // namespace fuzzer
+
+#endif // LIBFUZZER_WINDOWS
diff --git a/libfuzzer/FuzzerExtraCounters.cpp b/libfuzzer/FuzzerExtraCounters.cpp
new file mode 100644
index 0000000..d36beba
--- /dev/null
+++ b/libfuzzer/FuzzerExtraCounters.cpp
@@ -0,0 +1,42 @@
+//===- FuzzerExtraCounters.cpp - Extra coverage counters ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Extra coverage counters defined by user code.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerPlatform.h"
+#include <cstdint>
+
+#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD ||                \
+    LIBFUZZER_OPENBSD || LIBFUZZER_FUCHSIA || LIBFUZZER_EMSCRIPTEN
+__attribute__((weak)) extern uint8_t __start___libfuzzer_extra_counters;
+__attribute__((weak)) extern uint8_t __stop___libfuzzer_extra_counters;
+
+namespace fuzzer {
+uint8_t *ExtraCountersBegin() { return &__start___libfuzzer_extra_counters; }
+uint8_t *ExtraCountersEnd() { return &__stop___libfuzzer_extra_counters; }
+ATTRIBUTE_NO_SANITIZE_ALL
+void ClearExtraCounters() {  // hand-written memset, don't asan-ify.
+  uintptr_t *Beg = reinterpret_cast<uintptr_t*>(ExtraCountersBegin());
+  uintptr_t *End = reinterpret_cast<uintptr_t*>(ExtraCountersEnd());
+  for (; Beg < End; Beg++) {
+    *Beg = 0;
+    __asm__ __volatile__("" : : : "memory");
+  }
+}
+
+}  // namespace fuzzer
+
+#else
+// TODO: implement for other platforms.
+namespace fuzzer {
+uint8_t *ExtraCountersBegin() { return nullptr; }
+uint8_t *ExtraCountersEnd() { return nullptr; }
+void ClearExtraCounters() {}
+}  // namespace fuzzer
+
+#endif
diff --git a/libfuzzer/FuzzerFlags.def b/libfuzzer/FuzzerFlags.def
new file mode 100644
index 0000000..832224a
--- /dev/null
+++ b/libfuzzer/FuzzerFlags.def
@@ -0,0 +1,169 @@
+//===- FuzzerFlags.def - Run-time flags -------------------------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Flags. FUZZER_FLAG_INT/FUZZER_FLAG_STRING macros should be defined at the
+// point of inclusion. We are not using any flag parsing library for better
+// portability and independence.
+//===----------------------------------------------------------------------===//
+FUZZER_FLAG_INT(verbosity, 1, "Verbosity level.")
+FUZZER_FLAG_UNSIGNED(seed, 0, "Random seed. If 0, seed is generated.")
+FUZZER_FLAG_INT(runs, -1,
+            "Number of individual test runs (-1 for infinite runs).")
+FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. "
+    "If 0, libFuzzer tries to guess a good value based on the corpus "
+    "and reports it. ")
+FUZZER_FLAG_INT(len_control, 100, "Try generating small inputs first, "
+  "then try larger inputs over time.  Specifies the rate at which the length "
+  "limit is increased (smaller == faster).  If 0, immediately try inputs with "
+  "size up to max_len. Default value is 0, if LLVMFuzzerCustomMutator is used.")
+FUZZER_FLAG_STRING(seed_inputs, "A comma-separated list of input files "
+  "to use as an additional seed corpus. Alternatively, an \"@\" followed by "
+  "the name of a file containing the comma-separated list.")
+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(reduce_depth, 0, "Experimental/internal. "
+                "Reduce depth if mutations lose unique features")
+FUZZER_FLAG_INT(shuffle, 1, "Shuffle inputs at startup")
+FUZZER_FLAG_INT(prefer_small, 1,
+    "If 1, always prefer smaller inputs during the corpus shuffle.")
+FUZZER_FLAG_INT(
+    timeout, 1200,
+    "Timeout in seconds (if positive). "
+    "If one unit runs more than this number of seconds the process will abort.")
+FUZZER_FLAG_INT(error_exitcode, 77, "When libFuzzer itself reports a bug "
+  "this exit code will be used.")
+FUZZER_FLAG_INT(timeout_exitcode, 70, "When libFuzzer reports a timeout "
+  "this exit code will be used.")
+FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total "
+                                   "time in seconds to run the fuzzer.")
+FUZZER_FLAG_INT(help, 0, "Print help.")
+FUZZER_FLAG_INT(fork, 0, "Experimental mode where fuzzing happens "
+                "in a subprocess")
+FUZZER_FLAG_INT(ignore_timeouts, 1, "Ignore timeouts in fork mode")
+FUZZER_FLAG_INT(ignore_ooms, 1, "Ignore OOMs in fork mode")
+FUZZER_FLAG_INT(ignore_crashes, 0, "Ignore crashes in fork mode")
+FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be "
+  "merged into the 1-st corpus. Only interesting units will be taken. "
+  "This flag can be used to minimize a corpus.")
+FUZZER_FLAG_STRING(stop_file, "Stop fuzzing ASAP if this file exists")
+FUZZER_FLAG_STRING(merge_inner, "internal flag")
+FUZZER_FLAG_STRING(merge_control_file,
+                   "Specify a control file used for the merge process. "
+                   "If a merge process gets killed it tries to leave this file "
+                   "in a state suitable for resuming the merge. "
+                   "By default a temporary file will be used."
+                   "The same file can be used for multistep merge process.")
+FUZZER_FLAG_INT(minimize_crash, 0, "If 1, minimizes the provided"
+  " crash input. Use with -runs=N or -max_total_time=N to limit "
+  "the number attempts."
+  " Use with -exact_artifact_path to specify the output."
+  " Combine with ASAN_OPTIONS=dedup_token_length=3 (or similar) to ensure that"
+  " the minimized input triggers the same crash."
+  )
+FUZZER_FLAG_INT(cleanse_crash, 0, "If 1, tries to cleanse the provided"
+  " crash input to make it contain fewer original bytes."
+  " Use with -exact_artifact_path to specify the output."
+  )
+FUZZER_FLAG_INT(minimize_crash_internal_step, 0, "internal flag")
+FUZZER_FLAG_STRING(features_dir, "internal flag. Used to dump feature sets on disk."
+  "Every time a new input is added to the corpus, a corresponding file in the features_dir"
+  " is created containing the unique features of that input."
+  " Features are stored in binary format.")
+FUZZER_FLAG_INT(use_counters, 1, "Use coverage counters")
+FUZZER_FLAG_INT(use_memmem, 1,
+                "Use hints from intercepting memmem, strstr, etc")
+FUZZER_FLAG_INT(use_value_profile, 0,
+                "Experimental. Use value profile to guide fuzzing.")
+FUZZER_FLAG_INT(use_cmp, 1, "Use CMP traces to guide mutations")
+FUZZER_FLAG_INT(shrink, 0, "Experimental. Try to shrink corpus inputs.")
+FUZZER_FLAG_INT(reduce_inputs, 1,
+  "Try to reduce the size of inputs while preserving their full feature sets")
+FUZZER_FLAG_UNSIGNED(jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn"
+                          " this number of jobs in separate worker processes"
+                          " with stdout/stderr redirected to fuzz-JOB.log.")
+FUZZER_FLAG_UNSIGNED(workers, 0,
+            "Number of simultaneous worker processes to run the jobs."
+            " If zero, \"min(jobs,NumberOfCpuCores()/2)\" is used.")
+FUZZER_FLAG_INT(reload, 1,
+                "Reload the main corpus every <N> seconds to get new units"
+                " discovered by other processes. If 0, disabled")
+FUZZER_FLAG_INT(report_slow_units, 10,
+    "Report slowest units if they run for more than this number of seconds.")
+FUZZER_FLAG_INT(only_ascii, 0,
+                "If 1, generate only ASCII (isprint+isspace) inputs.")
+FUZZER_FLAG_STRING(dict, "Experimental. Use the dictionary file.")
+FUZZER_FLAG_STRING(artifact_prefix, "Write fuzzing artifacts (crash, "
+                                    "timeout, or slow inputs) as "
+                                    "$(artifact_prefix)file")
+FUZZER_FLAG_STRING(exact_artifact_path,
+                   "Write the single artifact on failure (crash, timeout) "
+                   "as $(exact_artifact_path). This overrides -artifact_prefix "
+                   "and will not use checksum in the file name. Do not "
+                   "use the same path for several parallel processes.")
+FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.")
+FUZZER_FLAG_INT(print_funcs, 2, "If >=1, print out at most this number of "
+                                "newly covered functions.")
+FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.")
+FUZZER_FLAG_INT(print_corpus_stats, 0,
+  "If 1, print statistics on corpus elements at exit.")
+FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text"
+                                   " at exit.")
+FUZZER_FLAG_INT(dump_coverage, 0, "Deprecated.")
+FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.")
+FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGBUS.")
+FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.")
+FUZZER_FLAG_INT(handle_ill, 1, "If 1, try to intercept SIGILL.")
+FUZZER_FLAG_INT(handle_fpe, 1, "If 1, try to intercept SIGFPE.")
+FUZZER_FLAG_INT(handle_int, 1, "If 1, try to intercept SIGINT.")
+FUZZER_FLAG_INT(handle_term, 1, "If 1, try to intercept SIGTERM.")
+FUZZER_FLAG_INT(handle_xfsz, 1, "If 1, try to intercept SIGXFSZ.")
+FUZZER_FLAG_INT(handle_usr1, 1, "If 1, try to intercept SIGUSR1.")
+FUZZER_FLAG_INT(handle_usr2, 1, "If 1, try to intercept SIGUSR2.")
+FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; "
+    "if 2, close stderr; if 3, close both. "
+    "Be careful, this will also close e.g. stderr of asan.")
+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(purge_allocator_interval, 1, "Purge allocator caches and "
+    "quarantines every <N> seconds. When rss_limit_mb is specified (>0), "
+    "purging starts when RSS exceeds 50% of rss_limit_mb. Pass "
+    "purge_allocator_interval=-1 to disable this functionality.")
+FUZZER_FLAG_INT(trace_malloc, 0, "If >= 1 will print all mallocs/frees. "
+    "If >= 2 will also print stack traces.")
+FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon"
+    "reaching this limit of RSS memory usage.")
+FUZZER_FLAG_INT(malloc_limit_mb, 0, "If non-zero, the fuzzer will exit "
+    "if the target tries to allocate this number of Mb with one malloc call. "
+    "If zero (default) same limit as rss_limit_mb is applied.")
+FUZZER_FLAG_STRING(exit_on_src_pos, "Exit if a newly found PC originates"
+    " from the given source location. Example: -exit_on_src_pos=foo.cc:123. "
+    "Used primarily for testing libFuzzer itself.")
+FUZZER_FLAG_STRING(exit_on_item, "Exit if an item with a given sha1 sum"
+    " was added to the corpus. "
+    "Used primarily for testing libFuzzer itself.")
+FUZZER_FLAG_INT(ignore_remaining_args, 0, "If 1, ignore all arguments passed "
+                "after this one. Useful for fuzzers that need to do their own "
+                "argument parsing.")
+FUZZER_FLAG_STRING(focus_function, "Experimental. "
+     "Fuzzing will focus on inputs that trigger calls to this function. "
+     "If -focus_function=auto and -data_flow_trace is used, libFuzzer "
+     "will choose the focus functions automatically.")
+FUZZER_FLAG_INT(entropic, 0, "Experimental. Enables entropic power schedule.")
+FUZZER_FLAG_INT(entropic_feature_frequency_threshold, 0xFF, "Experimental. If "
+     "entropic is enabled, all features which are observed less often than "
+     "the specified value are considered as rare.")
+FUZZER_FLAG_INT(entropic_number_of_rarest_features, 100, "Experimental. If "
+     "entropic is enabled, we keep track of the frequencies only for the "
+     "Top-X least abundant features (union features that are considered as "
+     "rare).")
+
+FUZZER_FLAG_INT(analyze_dict, 0, "Experimental")
+FUZZER_DEPRECATED_FLAG(use_clang_coverage)
+FUZZER_FLAG_STRING(data_flow_trace, "Experimental: use the data flow trace")
+FUZZER_FLAG_STRING(collect_data_flow,
+                   "Experimental: collect the data flow trace")
diff --git a/libfuzzer/FuzzerFork.cpp b/libfuzzer/FuzzerFork.cpp
new file mode 100644
index 0000000..d9e6b79
--- /dev/null
+++ b/libfuzzer/FuzzerFork.cpp
@@ -0,0 +1,409 @@
+//===- FuzzerFork.cpp - run fuzzing in separate subprocesses --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Spawn and orchestrate separate fuzzing processes.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerCommand.h"
+#include "FuzzerFork.h"
+#include "FuzzerIO.h"
+#include "FuzzerInternal.h"
+#include "FuzzerMerge.h"
+#include "FuzzerSHA1.h"
+#include "FuzzerTracePC.h"
+#include "FuzzerUtil.h"
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <fstream>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <sstream>
+#include <thread>
+
+namespace fuzzer {
+
+struct Stats {
+  size_t number_of_executed_units = 0;
+  size_t peak_rss_mb = 0;
+  size_t average_exec_per_sec = 0;
+};
+
+static Stats ParseFinalStatsFromLog(const std::string &LogPath) {
+  std::ifstream In(LogPath);
+  std::string Line;
+  Stats Res;
+  struct {
+    const char *Name;
+    size_t *Var;
+  } NameVarPairs[] = {
+      {"stat::number_of_executed_units:", &Res.number_of_executed_units},
+      {"stat::peak_rss_mb:", &Res.peak_rss_mb},
+      {"stat::average_exec_per_sec:", &Res.average_exec_per_sec},
+      {nullptr, nullptr},
+  };
+  while (std::getline(In, Line, '\n')) {
+    if (Line.find("stat::") != 0) continue;
+    std::istringstream ISS(Line);
+    std::string Name;
+    size_t Val;
+    ISS >> Name >> Val;
+    for (size_t i = 0; NameVarPairs[i].Name; i++)
+      if (Name == NameVarPairs[i].Name)
+        *NameVarPairs[i].Var = Val;
+  }
+  return Res;
+}
+
+struct FuzzJob {
+  // Inputs.
+  Command Cmd;
+  std::string CorpusDir;
+  std::string FeaturesDir;
+  std::string LogPath;
+  std::string SeedListPath;
+  std::string CFPath;
+  size_t      JobId;
+
+  int         DftTimeInSeconds = 0;
+
+  // Fuzzing Outputs.
+  int ExitCode;
+
+  ~FuzzJob() {
+    RemoveFile(CFPath);
+    RemoveFile(LogPath);
+    RemoveFile(SeedListPath);
+    RmDirRecursive(CorpusDir);
+    RmDirRecursive(FeaturesDir);
+  }
+};
+
+struct GlobalEnv {
+  Vector<std::string> Args;
+  Vector<std::string> CorpusDirs;
+  std::string MainCorpusDir;
+  std::string TempDir;
+  std::string DFTDir;
+  std::string DataFlowBinary;
+  Set<uint32_t> Features, Cov;
+  Set<std::string> FilesWithDFT;
+  Vector<std::string> Files;
+  Random *Rand;
+  std::chrono::system_clock::time_point ProcessStartTime;
+  int Verbosity = 0;
+
+  size_t NumTimeouts = 0;
+  size_t NumOOMs = 0;
+  size_t NumCrashes = 0;
+
+
+  size_t NumRuns = 0;
+
+  std::string StopFile() { return DirPlusFile(TempDir, "STOP"); }
+
+  size_t secondsSinceProcessStartUp() const {
+    return std::chrono::duration_cast<std::chrono::seconds>(
+               std::chrono::system_clock::now() - ProcessStartTime)
+        .count();
+  }
+
+  FuzzJob *CreateNewJob(size_t JobId) {
+    Command Cmd(Args);
+    Cmd.removeFlag("fork");
+    Cmd.removeFlag("runs");
+    Cmd.removeFlag("collect_data_flow");
+    for (auto &C : CorpusDirs) // Remove all corpora from the args.
+      Cmd.removeArgument(C);
+    Cmd.addFlag("reload", "0");  // working in an isolated dir, no reload.
+    Cmd.addFlag("print_final_stats", "1");
+    Cmd.addFlag("print_funcs", "0");  // no need to spend time symbolizing.
+    Cmd.addFlag("max_total_time", std::to_string(std::min((size_t)300, JobId)));
+    Cmd.addFlag("stop_file", StopFile());
+    if (!DataFlowBinary.empty()) {
+      Cmd.addFlag("data_flow_trace", DFTDir);
+      if (!Cmd.hasFlag("focus_function"))
+        Cmd.addFlag("focus_function", "auto");
+    }
+    auto Job = new FuzzJob;
+    std::string Seeds;
+    if (size_t CorpusSubsetSize =
+            std::min(Files.size(), (size_t)sqrt(Files.size() + 2))) {
+      auto Time1 = std::chrono::system_clock::now();
+      for (size_t i = 0; i < CorpusSubsetSize; i++) {
+        auto &SF = Files[Rand->SkewTowardsLast(Files.size())];
+        Seeds += (Seeds.empty() ? "" : ",") + SF;
+        CollectDFT(SF);
+      }
+      auto Time2 = std::chrono::system_clock::now();
+      Job->DftTimeInSeconds = duration_cast<seconds>(Time2 - Time1).count();
+    }
+    if (!Seeds.empty()) {
+      Job->SeedListPath =
+          DirPlusFile(TempDir, std::to_string(JobId) + ".seeds");
+      WriteToFile(Seeds, Job->SeedListPath);
+      Cmd.addFlag("seed_inputs", "@" + Job->SeedListPath);
+    }
+    Job->LogPath = DirPlusFile(TempDir, std::to_string(JobId) + ".log");
+    Job->CorpusDir = DirPlusFile(TempDir, "C" + std::to_string(JobId));
+    Job->FeaturesDir = DirPlusFile(TempDir, "F" + std::to_string(JobId));
+    Job->CFPath = DirPlusFile(TempDir, std::to_string(JobId) + ".merge");
+    Job->JobId = JobId;
+
+
+    Cmd.addArgument(Job->CorpusDir);
+    Cmd.addFlag("features_dir", Job->FeaturesDir);
+
+    for (auto &D : {Job->CorpusDir, Job->FeaturesDir}) {
+      RmDirRecursive(D);
+      MkDir(D);
+    }
+
+    Cmd.setOutputFile(Job->LogPath);
+    Cmd.combineOutAndErr();
+
+    Job->Cmd = Cmd;
+
+    if (Verbosity >= 2)
+      Printf("Job %zd/%p Created: %s\n", JobId, Job,
+             Job->Cmd.toString().c_str());
+    // Start from very short runs and gradually increase them.
+    return Job;
+  }
+
+  void RunOneMergeJob(FuzzJob *Job) {
+    auto Stats = ParseFinalStatsFromLog(Job->LogPath);
+    NumRuns += Stats.number_of_executed_units;
+
+    Vector<SizedFile> TempFiles, MergeCandidates;
+    // Read all newly created inputs and their feature sets.
+    // Choose only those inputs that have new features.
+    GetSizedFilesFromDir(Job->CorpusDir, &TempFiles);
+    std::sort(TempFiles.begin(), TempFiles.end());
+    for (auto &F : TempFiles) {
+      auto FeatureFile = F.File;
+      FeatureFile.replace(0, Job->CorpusDir.size(), Job->FeaturesDir);
+      auto FeatureBytes = FileToVector(FeatureFile, 0, false);
+      assert((FeatureBytes.size() % sizeof(uint32_t)) == 0);
+      Vector<uint32_t> NewFeatures(FeatureBytes.size() / sizeof(uint32_t));
+      memcpy(NewFeatures.data(), FeatureBytes.data(), FeatureBytes.size());
+      for (auto Ft : NewFeatures) {
+        if (!Features.count(Ft)) {
+          MergeCandidates.push_back(F);
+          break;
+        }
+      }
+    }
+    // if (!FilesToAdd.empty() || Job->ExitCode != 0)
+    Printf("#%zd: cov: %zd ft: %zd corp: %zd exec/s %zd "
+           "oom/timeout/crash: %zd/%zd/%zd time: %zds job: %zd dft_time: %d\n",
+           NumRuns, Cov.size(), Features.size(), Files.size(),
+           Stats.average_exec_per_sec, NumOOMs, NumTimeouts, NumCrashes,
+           secondsSinceProcessStartUp(), Job->JobId, Job->DftTimeInSeconds);
+
+    if (MergeCandidates.empty()) return;
+
+    Vector<std::string> FilesToAdd;
+    Set<uint32_t> NewFeatures, NewCov;
+    CrashResistantMerge(Args, {}, MergeCandidates, &FilesToAdd, Features,
+                        &NewFeatures, Cov, &NewCov, Job->CFPath, false);
+    for (auto &Path : FilesToAdd) {
+      auto U = FileToVector(Path);
+      auto NewPath = DirPlusFile(MainCorpusDir, Hash(U));
+      WriteToFile(U, NewPath);
+      Files.push_back(NewPath);
+    }
+    Features.insert(NewFeatures.begin(), NewFeatures.end());
+    Cov.insert(NewCov.begin(), NewCov.end());
+    for (auto Idx : NewCov)
+      if (auto *TE = TPC.PCTableEntryByIdx(Idx))
+        if (TPC.PcIsFuncEntry(TE))
+          PrintPC("  NEW_FUNC: %p %F %L\n", "",
+                  TPC.GetNextInstructionPc(TE->PC));
+
+  }
+
+
+  void CollectDFT(const std::string &InputPath) {
+    if (DataFlowBinary.empty()) return;
+    if (!FilesWithDFT.insert(InputPath).second) return;
+    Command Cmd(Args);
+    Cmd.removeFlag("fork");
+    Cmd.removeFlag("runs");
+    Cmd.addFlag("data_flow_trace", DFTDir);
+    Cmd.addArgument(InputPath);
+    for (auto &C : CorpusDirs) // Remove all corpora from the args.
+      Cmd.removeArgument(C);
+    Cmd.setOutputFile(DirPlusFile(TempDir, "dft.log"));
+    Cmd.combineOutAndErr();
+    // Printf("CollectDFT: %s\n", Cmd.toString().c_str());
+    ExecuteCommand(Cmd);
+  }
+
+};
+
+struct JobQueue {
+  std::queue<FuzzJob *> Qu;
+  std::mutex Mu;
+  std::condition_variable Cv;
+
+  void Push(FuzzJob *Job) {
+    {
+      std::lock_guard<std::mutex> Lock(Mu);
+      Qu.push(Job);
+    }
+    Cv.notify_one();
+  }
+  FuzzJob *Pop() {
+    std::unique_lock<std::mutex> Lk(Mu);
+    // std::lock_guard<std::mutex> Lock(Mu);
+    Cv.wait(Lk, [&]{return !Qu.empty();});
+    assert(!Qu.empty());
+    auto Job = Qu.front();
+    Qu.pop();
+    return Job;
+  }
+};
+
+void WorkerThread(JobQueue *FuzzQ, JobQueue *MergeQ) {
+  while (auto Job = FuzzQ->Pop()) {
+    // Printf("WorkerThread: job %p\n", Job);
+    Job->ExitCode = ExecuteCommand(Job->Cmd);
+    MergeQ->Push(Job);
+  }
+}
+
+// This is just a skeleton of an experimental -fork=1 feature.
+void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
+                  const Vector<std::string> &Args,
+                  const Vector<std::string> &CorpusDirs, int NumJobs) {
+  Printf("INFO: -fork=%d: fuzzing in separate process(s)\n", NumJobs);
+
+  GlobalEnv Env;
+  Env.Args = Args;
+  Env.CorpusDirs = CorpusDirs;
+  Env.Rand = &Rand;
+  Env.Verbosity = Options.Verbosity;
+  Env.ProcessStartTime = std::chrono::system_clock::now();
+  Env.DataFlowBinary = Options.CollectDataFlow;
+
+  Vector<SizedFile> SeedFiles;
+  for (auto &Dir : CorpusDirs)
+    GetSizedFilesFromDir(Dir, &SeedFiles);
+  std::sort(SeedFiles.begin(), SeedFiles.end());
+  Env.TempDir = TempPath("FuzzWithFork", ".dir");
+  Env.DFTDir = DirPlusFile(Env.TempDir, "DFT");
+  RmDirRecursive(Env.TempDir);  // in case there is a leftover from old runs.
+  MkDir(Env.TempDir);
+  MkDir(Env.DFTDir);
+
+
+  if (CorpusDirs.empty())
+    MkDir(Env.MainCorpusDir = DirPlusFile(Env.TempDir, "C"));
+  else
+    Env.MainCorpusDir = CorpusDirs[0];
+
+  auto CFPath = DirPlusFile(Env.TempDir, "merge.txt");
+  CrashResistantMerge(Env.Args, {}, SeedFiles, &Env.Files, {}, &Env.Features,
+                      {}, &Env.Cov,
+                      CFPath, false);
+  RemoveFile(CFPath);
+  Printf("INFO: -fork=%d: %zd seed inputs, starting to fuzz in %s\n", NumJobs,
+         Env.Files.size(), Env.TempDir.c_str());
+
+  int ExitCode = 0;
+
+  JobQueue FuzzQ, MergeQ;
+
+  auto StopJobs = [&]() {
+    for (int i = 0; i < NumJobs; i++)
+      FuzzQ.Push(nullptr);
+    MergeQ.Push(nullptr);
+    WriteToFile(Unit({1}), Env.StopFile());
+  };
+
+  size_t JobId = 1;
+  Vector<std::thread> Threads;
+  for (int t = 0; t < NumJobs; t++) {
+    Threads.push_back(std::thread(WorkerThread, &FuzzQ, &MergeQ));
+    FuzzQ.Push(Env.CreateNewJob(JobId++));
+  }
+
+  while (true) {
+    std::unique_ptr<FuzzJob> Job(MergeQ.Pop());
+    if (!Job)
+      break;
+    ExitCode = Job->ExitCode;
+    if (ExitCode == Options.InterruptExitCode) {
+      Printf("==%lu== libFuzzer: a child was interrupted; exiting\n", GetPid());
+      StopJobs();
+      break;
+    }
+    Fuzzer::MaybeExitGracefully();
+
+    Env.RunOneMergeJob(Job.get());
+
+    // Continue if our crash is one of the ignorred ones.
+    if (Options.IgnoreTimeouts && ExitCode == Options.TimeoutExitCode)
+      Env.NumTimeouts++;
+    else if (Options.IgnoreOOMs && ExitCode == Options.OOMExitCode)
+      Env.NumOOMs++;
+    else if (ExitCode != 0) {
+      Env.NumCrashes++;
+      if (Options.IgnoreCrashes) {
+        std::ifstream In(Job->LogPath);
+        std::string Line;
+        while (std::getline(In, Line, '\n'))
+          if (Line.find("ERROR:") != Line.npos ||
+              Line.find("runtime error:") != Line.npos)
+            Printf("%s\n", Line.c_str());
+      } else {
+        // And exit if we don't ignore this crash.
+        Printf("INFO: log from the inner process:\n%s",
+               FileToString(Job->LogPath).c_str());
+        StopJobs();
+        break;
+      }
+    }
+
+    // Stop if we are over the time budget.
+    // This is not precise, since other threads are still running
+    // and we will wait while joining them.
+    // We also don't stop instantly: other jobs need to finish.
+    if (Options.MaxTotalTimeSec > 0 &&
+        Env.secondsSinceProcessStartUp() >= (size_t)Options.MaxTotalTimeSec) {
+      Printf("INFO: fuzzed for %zd seconds, wrapping up soon\n",
+             Env.secondsSinceProcessStartUp());
+      StopJobs();
+      break;
+    }
+    if (Env.NumRuns >= Options.MaxNumberOfRuns) {
+      Printf("INFO: fuzzed for %zd iterations, wrapping up soon\n",
+             Env.NumRuns);
+      StopJobs();
+      break;
+    }
+
+    FuzzQ.Push(Env.CreateNewJob(JobId++));
+  }
+
+  for (auto &T : Threads)
+    T.join();
+
+  // The workers have terminated. Don't try to remove the directory before they
+  // terminate to avoid a race condition preventing cleanup on Windows.
+  RmDirRecursive(Env.TempDir);
+
+  // Use the exit code from the last child process.
+  Printf("INFO: exiting: %d time: %zds\n", ExitCode,
+         Env.secondsSinceProcessStartUp());
+  exit(ExitCode);
+}
+
+} // namespace fuzzer
diff --git a/libfuzzer/FuzzerFork.h b/libfuzzer/FuzzerFork.h
new file mode 100644
index 0000000..b29a43e
--- /dev/null
+++ b/libfuzzer/FuzzerFork.h
@@ -0,0 +1,24 @@
+//===- FuzzerFork.h - run fuzzing in sub-processes --------------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_FORK_H
+#define LLVM_FUZZER_FORK_H
+
+#include "FuzzerDefs.h"
+#include "FuzzerOptions.h"
+#include "FuzzerRandom.h"
+
+#include <string>
+
+namespace fuzzer {
+void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
+                  const Vector<std::string> &Args,
+                  const Vector<std::string> &CorpusDirs, int NumJobs);
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_FORK_H
diff --git a/libfuzzer/FuzzerIO.cpp b/libfuzzer/FuzzerIO.cpp
new file mode 100644
index 0000000..cbb1dbe
--- /dev/null
+++ b/libfuzzer/FuzzerIO.cpp
@@ -0,0 +1,159 @@
+//===- FuzzerIO.cpp - IO utils. -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// IO functions.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerDefs.h"
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+#include "FuzzerUtil.h"
+#include <algorithm>
+#include <cstdarg>
+#include <fstream>
+#include <iterator>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+namespace fuzzer {
+
+static FILE *OutputFile = stderr;
+
+long GetEpoch(const std::string &Path) {
+  struct stat St;
+  if (stat(Path.c_str(), &St))
+    return 0;  // Can't stat, be conservative.
+  return St.st_mtime;
+}
+
+Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
+  std::ifstream T(Path, std::ios::binary);
+  if (ExitOnError && !T) {
+    Printf("No such directory: %s; exiting\n", Path.c_str());
+    exit(1);
+  }
+
+  T.seekg(0, T.end);
+  auto EndPos = T.tellg();
+  if (EndPos < 0) return {};
+  size_t FileLen = EndPos;
+  if (MaxSize)
+    FileLen = std::min(FileLen, MaxSize);
+
+  T.seekg(0, T.beg);
+  Unit Res(FileLen);
+  T.read(reinterpret_cast<char *>(Res.data()), FileLen);
+  return Res;
+}
+
+std::string FileToString(const std::string &Path) {
+  std::ifstream T(Path, std::ios::binary);
+  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) {
+  WriteToFile(U.data(), U.size(), Path);
+}
+
+void WriteToFile(const std::string &Data, const std::string &Path) {
+  WriteToFile(reinterpret_cast<const uint8_t *>(Data.c_str()), Data.size(),
+              Path);
+}
+
+void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path) {
+  // Use raw C interface because this function may be called from a sig handler.
+  FILE *Out = fopen(Path.c_str(), "wb");
+  if (!Out) return;
+  fwrite(Data, sizeof(Data[0]), Size, Out);
+  fclose(Out);
+}
+
+void ReadDirToVectorOfUnits(const char *Path, Vector<Unit> *V,
+                            long *Epoch, size_t MaxSize, bool ExitOnError) {
+  long E = Epoch ? *Epoch : 0;
+  Vector<std::string> Files;
+  ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true);
+  size_t NumLoaded = 0;
+  for (size_t i = 0; i < Files.size(); i++) {
+    auto &X = Files[i];
+    if (Epoch && GetEpoch(X) < E) continue;
+    NumLoaded++;
+    if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024)
+      Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path);
+    auto S = FileToVector(X, MaxSize, ExitOnError);
+    if (!S.empty())
+      V->push_back(S);
+  }
+}
+
+
+void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V) {
+  Vector<std::string> Files;
+  ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/true);
+  for (auto &File : Files)
+    if (size_t Size = FileSize(File))
+      V->push_back({File, Size});
+}
+
+std::string DirPlusFile(const std::string &DirPath,
+                        const std::string &FileName) {
+  return DirPath + GetSeparator() + FileName;
+}
+
+void DupAndCloseStderr() {
+  int OutputFd = DuplicateFile(2);
+  if (OutputFd >= 0) {
+    FILE *NewOutputFile = OpenFile(OutputFd, "w");
+    if (NewOutputFile) {
+      OutputFile = NewOutputFile;
+      if (EF->__sanitizer_set_report_fd)
+        EF->__sanitizer_set_report_fd(
+            reinterpret_cast<void *>(GetHandleFromFd(OutputFd)));
+      DiscardOutput(2);
+    }
+  }
+}
+
+void CloseStdout() {
+  DiscardOutput(1);
+}
+
+void Printf(const char *Fmt, ...) {
+  va_list ap;
+  va_start(ap, Fmt);
+  vfprintf(OutputFile, Fmt, ap);
+  va_end(ap);
+  fflush(OutputFile);
+}
+
+void VPrintf(bool Verbose, const char *Fmt, ...) {
+  if (!Verbose) return;
+  va_list ap;
+  va_start(ap, Fmt);
+  vfprintf(OutputFile, Fmt, ap);
+  va_end(ap);
+  fflush(OutputFile);
+}
+
+void RmDirRecursive(const std::string &Dir) {
+  IterateDirRecursive(
+      Dir, [](const std::string &Path) {},
+      [](const std::string &Path) { RmDir(Path); },
+      [](const std::string &Path) { RemoveFile(Path); });
+}
+
+std::string TempPath(const char *Prefix, const char *Extension) {
+  return DirPlusFile(TmpDir(), std::string("libFuzzerTemp.") + Prefix +
+                                   std::to_string(GetPid()) + Extension);
+}
+
+}  // namespace fuzzer
diff --git a/libfuzzer/FuzzerIO.h b/libfuzzer/FuzzerIO.h
new file mode 100644
index 0000000..6e4368b
--- /dev/null
+++ b/libfuzzer/FuzzerIO.h
@@ -0,0 +1,106 @@
+//===- FuzzerIO.h - Internal header for IO utils ----------------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// IO interface.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_IO_H
+#define LLVM_FUZZER_IO_H
+
+#include "FuzzerDefs.h"
+
+namespace fuzzer {
+
+long GetEpoch(const std::string &Path);
+
+Unit FileToVector(const std::string &Path, size_t MaxSize = 0,
+                  bool ExitOnError = true);
+
+std::string FileToString(const std::string &Path);
+
+void CopyFileToErr(const std::string &Path);
+
+void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path);
+// Write Data.c_str() to the file without terminating null character.
+void WriteToFile(const std::string &Data, const std::string &Path);
+void WriteToFile(const Unit &U, const std::string &Path);
+
+void ReadDirToVectorOfUnits(const char *Path, Vector<Unit> *V,
+                            long *Epoch, size_t MaxSize, bool ExitOnError);
+
+// Returns "Dir/FileName" or equivalent for the current OS.
+std::string DirPlusFile(const std::string &DirPath,
+                        const std::string &FileName);
+
+// Returns the name of the dir, similar to the 'dirname' utility.
+std::string DirName(const std::string &FileName);
+
+// Returns path to a TmpDir.
+std::string TmpDir();
+
+std::string TempPath(const char *Prefix, const char *Extension);
+
+bool IsInterestingCoverageFile(const std::string &FileName);
+
+void DupAndCloseStderr();
+
+void CloseStdout();
+
+void Printf(const char *Fmt, ...);
+void VPrintf(bool Verbose, const char *Fmt, ...);
+
+// Print using raw syscalls, useful when printing at early init stages.
+void RawPrint(const char *Str);
+
+// Platform specific functions:
+bool IsFile(const std::string &Path);
+size_t FileSize(const std::string &Path);
+
+void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
+                             Vector<std::string> *V, bool TopDir);
+
+void RmDirRecursive(const std::string &Dir);
+
+// Iterate files and dirs inside Dir, recursively.
+// Call DirPreCallback/DirPostCallback on dirs before/after
+// calling FileCallback on files.
+void IterateDirRecursive(const std::string &Dir,
+                         void (*DirPreCallback)(const std::string &Dir),
+                         void (*DirPostCallback)(const std::string &Dir),
+                         void (*FileCallback)(const std::string &Dir));
+
+struct SizedFile {
+  std::string File;
+  size_t Size;
+  bool operator<(const SizedFile &B) const { return Size < B.Size; }
+};
+
+void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V);
+
+char GetSeparator();
+// Similar to the basename utility: returns the file name w/o the dir prefix.
+std::string Basename(const std::string &Path);
+
+FILE* OpenFile(int Fd, const char *Mode);
+
+int CloseFile(int Fd);
+
+int DuplicateFile(int Fd);
+
+void RemoveFile(const std::string &Path);
+void RenameFile(const std::string &OldPath, const std::string &NewPath);
+
+intptr_t GetHandleFromFd(int fd);
+
+void MkDir(const std::string &Path);
+void RmDir(const std::string &Path);
+
+const std::string &getDevNull();
+
+}  // namespace fuzzer
+
+#endif  // LLVM_FUZZER_IO_H
diff --git a/libfuzzer/FuzzerIOPosix.cpp b/libfuzzer/FuzzerIOPosix.cpp
new file mode 100644
index 0000000..aac85b0
--- /dev/null
+++ b/libfuzzer/FuzzerIOPosix.cpp
@@ -0,0 +1,176 @@
+//===- FuzzerIOPosix.cpp - IO utils for Posix. ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// IO functions implementation using Posix API.
+//===----------------------------------------------------------------------===//
+#include "FuzzerPlatform.h"
+#if LIBFUZZER_POSIX || LIBFUZZER_FUCHSIA
+
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+#include <cstdarg>
+#include <cstdio>
+#include <dirent.h>
+#include <fstream>
+#include <iterator>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace fuzzer {
+
+bool IsFile(const std::string &Path) {
+  struct stat St;
+  if (stat(Path.c_str(), &St))
+    return false;
+  return S_ISREG(St.st_mode);
+}
+
+static bool IsDirectory(const std::string &Path) {
+  struct stat St;
+  if (stat(Path.c_str(), &St))
+    return false;
+  return S_ISDIR(St.st_mode);
+}
+
+size_t FileSize(const std::string &Path) {
+  struct stat St;
+  if (stat(Path.c_str(), &St))
+    return 0;
+  return St.st_size;
+}
+
+std::string Basename(const std::string &Path) {
+  size_t Pos = Path.rfind(GetSeparator());
+  if (Pos == std::string::npos) return Path;
+  assert(Pos < Path.size());
+  return Path.substr(Pos + 1);
+}
+
+void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
+                             Vector<std::string> *V, bool TopDir) {
+  auto E = GetEpoch(Dir);
+  if (Epoch)
+    if (E && *Epoch >= E) return;
+
+  DIR *D = opendir(Dir.c_str());
+  if (!D) {
+    Printf("%s: %s; exiting\n", strerror(errno), Dir.c_str());
+    exit(1);
+  }
+  while (auto E = readdir(D)) {
+    std::string Path = DirPlusFile(Dir, E->d_name);
+    if (E->d_type == DT_REG || E->d_type == DT_LNK ||
+        (E->d_type == DT_UNKNOWN && IsFile(Path)))
+      V->push_back(Path);
+    else if ((E->d_type == DT_DIR ||
+             (E->d_type == DT_UNKNOWN && IsDirectory(Path))) &&
+             *E->d_name != '.')
+      ListFilesInDirRecursive(Path, Epoch, V, false);
+  }
+  closedir(D);
+  if (Epoch && TopDir)
+    *Epoch = E;
+}
+
+
+void IterateDirRecursive(const std::string &Dir,
+                         void (*DirPreCallback)(const std::string &Dir),
+                         void (*DirPostCallback)(const std::string &Dir),
+                         void (*FileCallback)(const std::string &Dir)) {
+  DirPreCallback(Dir);
+  DIR *D = opendir(Dir.c_str());
+  if (!D) return;
+  while (auto E = readdir(D)) {
+    std::string Path = DirPlusFile(Dir, E->d_name);
+    if (E->d_type == DT_REG || E->d_type == DT_LNK ||
+        (E->d_type == DT_UNKNOWN && IsFile(Path)))
+      FileCallback(Path);
+    else if ((E->d_type == DT_DIR ||
+             (E->d_type == DT_UNKNOWN && IsDirectory(Path))) &&
+             *E->d_name != '.')
+      IterateDirRecursive(Path, DirPreCallback, DirPostCallback, FileCallback);
+  }
+  closedir(D);
+  DirPostCallback(Dir);
+}
+
+char GetSeparator() {
+  return '/';
+}
+
+FILE* OpenFile(int Fd, const char* Mode) {
+  return fdopen(Fd, Mode);
+}
+
+int CloseFile(int fd) {
+  return close(fd);
+}
+
+int DuplicateFile(int Fd) {
+  return dup(Fd);
+}
+
+void RemoveFile(const std::string &Path) {
+  unlink(Path.c_str());
+}
+
+void RenameFile(const std::string &OldPath, const std::string &NewPath) {
+  rename(OldPath.c_str(), NewPath.c_str());
+}
+
+intptr_t GetHandleFromFd(int fd) {
+  return static_cast<intptr_t>(fd);
+}
+
+std::string DirName(const std::string &FileName) {
+  char *Tmp = new char[FileName.size() + 1];
+  memcpy(Tmp, FileName.c_str(), FileName.size() + 1);
+  std::string Res = dirname(Tmp);
+  delete [] Tmp;
+  return Res;
+}
+
+std::string TmpDir() {
+  if (auto Env = getenv("TMPDIR"))
+    return Env;
+  return "/tmp";
+}
+
+bool IsInterestingCoverageFile(const std::string &FileName) {
+  if (FileName.find("compiler-rt/lib/") != std::string::npos)
+    return false; // sanitizer internal.
+  if (FileName.find("/usr/lib/") != std::string::npos)
+    return false;
+  if (FileName.find("/usr/include/") != std::string::npos)
+    return false;
+  if (FileName == "<null>")
+    return false;
+  return true;
+}
+
+void RawPrint(const char *Str) {
+  write(2, Str, strlen(Str));
+}
+
+void MkDir(const std::string &Path) {
+  mkdir(Path.c_str(), 0700);
+}
+
+void RmDir(const std::string &Path) {
+  rmdir(Path.c_str());
+}
+
+const std::string &getDevNull() {
+  static const std::string devNull = "/dev/null";
+  return devNull;
+}
+
+}  // namespace fuzzer
+
+#endif // LIBFUZZER_POSIX
diff --git a/libfuzzer/FuzzerIOWindows.cpp b/libfuzzer/FuzzerIOWindows.cpp
new file mode 100644
index 0000000..651283a
--- /dev/null
+++ b/libfuzzer/FuzzerIOWindows.cpp
@@ -0,0 +1,413 @@
+//===- FuzzerIOWindows.cpp - IO utils for Windows. ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// IO functions implementation for Windows.
+//===----------------------------------------------------------------------===//
+#include "FuzzerPlatform.h"
+#if LIBFUZZER_WINDOWS
+
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+#include <cstdarg>
+#include <cstdio>
+#include <fstream>
+#include <io.h>
+#include <iterator>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <windows.h>
+
+namespace fuzzer {
+
+static bool IsFile(const std::string &Path, const DWORD &FileAttributes) {
+
+  if (FileAttributes & FILE_ATTRIBUTE_NORMAL)
+    return true;
+
+  if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+    return false;
+
+  HANDLE FileHandle(
+      CreateFileA(Path.c_str(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+                  FILE_FLAG_BACKUP_SEMANTICS, 0));
+
+  if (FileHandle == INVALID_HANDLE_VALUE) {
+    Printf("CreateFileA() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
+        GetLastError());
+    return false;
+  }
+
+  DWORD FileType = GetFileType(FileHandle);
+
+  if (FileType == FILE_TYPE_UNKNOWN) {
+    Printf("GetFileType() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
+        GetLastError());
+    CloseHandle(FileHandle);
+    return false;
+  }
+
+  if (FileType != FILE_TYPE_DISK) {
+    CloseHandle(FileHandle);
+    return false;
+  }
+
+  CloseHandle(FileHandle);
+  return true;
+}
+
+bool IsFile(const std::string &Path) {
+  DWORD Att = GetFileAttributesA(Path.c_str());
+
+  if (Att == INVALID_FILE_ATTRIBUTES) {
+    Printf("GetFileAttributesA() failed for \"%s\" (Error code: %lu).\n",
+        Path.c_str(), GetLastError());
+    return false;
+  }
+
+  return IsFile(Path, Att);
+}
+
+static bool IsDir(DWORD FileAttrs) {
+  if (FileAttrs == INVALID_FILE_ATTRIBUTES) return false;
+  return FileAttrs & FILE_ATTRIBUTE_DIRECTORY;
+}
+
+std::string Basename(const std::string &Path) {
+  size_t Pos = Path.find_last_of("/\\");
+  if (Pos == std::string::npos) return Path;
+  assert(Pos < Path.size());
+  return Path.substr(Pos + 1);
+}
+
+size_t FileSize(const std::string &Path) {
+  WIN32_FILE_ATTRIBUTE_DATA attr;
+  if (!GetFileAttributesExA(Path.c_str(), GetFileExInfoStandard, &attr)) {
+    DWORD LastError = GetLastError();
+    if (LastError != ERROR_FILE_NOT_FOUND)
+      Printf("GetFileAttributesExA() failed for \"%s\" (Error code: %lu).\n",
+             Path.c_str(), LastError);
+    return 0;
+  }
+  ULARGE_INTEGER size;
+  size.HighPart = attr.nFileSizeHigh;
+  size.LowPart = attr.nFileSizeLow;
+  return size.QuadPart;
+}
+
+void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
+                             Vector<std::string> *V, bool TopDir) {
+  auto E = GetEpoch(Dir);
+  if (Epoch)
+    if (E && *Epoch >= E) return;
+
+  std::string Path(Dir);
+  assert(!Path.empty());
+  if (Path.back() != '\\')
+      Path.push_back('\\');
+  Path.push_back('*');
+
+  // Get the first directory entry.
+  WIN32_FIND_DATAA FindInfo;
+  HANDLE FindHandle(FindFirstFileA(Path.c_str(), &FindInfo));
+  if (FindHandle == INVALID_HANDLE_VALUE)
+  {
+    if (GetLastError() == ERROR_FILE_NOT_FOUND)
+      return;
+    Printf("No such file or directory: %s; exiting\n", Dir.c_str());
+    exit(1);
+  }
+
+  do {
+    std::string FileName = DirPlusFile(Dir, FindInfo.cFileName);
+
+    if (FindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+      size_t FilenameLen = strlen(FindInfo.cFileName);
+      if ((FilenameLen == 1 && FindInfo.cFileName[0] == '.') ||
+          (FilenameLen == 2 && FindInfo.cFileName[0] == '.' &&
+                               FindInfo.cFileName[1] == '.'))
+        continue;
+
+      ListFilesInDirRecursive(FileName, Epoch, V, false);
+    }
+    else if (IsFile(FileName, FindInfo.dwFileAttributes))
+      V->push_back(FileName);
+  } while (FindNextFileA(FindHandle, &FindInfo));
+
+  DWORD LastError = GetLastError();
+  if (LastError != ERROR_NO_MORE_FILES)
+    Printf("FindNextFileA failed (Error code: %lu).\n", LastError);
+
+  FindClose(FindHandle);
+
+  if (Epoch && TopDir)
+    *Epoch = E;
+}
+
+
+void IterateDirRecursive(const std::string &Dir,
+                         void (*DirPreCallback)(const std::string &Dir),
+                         void (*DirPostCallback)(const std::string &Dir),
+                         void (*FileCallback)(const std::string &Dir)) {
+  // TODO(metzman): Implement ListFilesInDirRecursive via this function.
+  DirPreCallback(Dir);
+
+  DWORD DirAttrs = GetFileAttributesA(Dir.c_str());
+  if (!IsDir(DirAttrs)) return;
+
+  std::string TargetDir(Dir);
+  assert(!TargetDir.empty());
+  if (TargetDir.back() != '\\') TargetDir.push_back('\\');
+  TargetDir.push_back('*');
+
+  WIN32_FIND_DATAA FindInfo;
+  // Find the directory's first file.
+  HANDLE FindHandle = FindFirstFileA(TargetDir.c_str(), &FindInfo);
+  if (FindHandle == INVALID_HANDLE_VALUE) {
+    DWORD LastError = GetLastError();
+    if (LastError != ERROR_FILE_NOT_FOUND) {
+      // If the directory isn't empty, then something abnormal is going on.
+      Printf("FindFirstFileA failed for %s (Error code: %lu).\n", Dir.c_str(),
+             LastError);
+    }
+    return;
+  }
+
+  do {
+    std::string Path = DirPlusFile(Dir, FindInfo.cFileName);
+    DWORD PathAttrs = FindInfo.dwFileAttributes;
+    if (IsDir(PathAttrs)) {
+      // Is Path the current directory (".") or the parent ("..")?
+      if (strcmp(FindInfo.cFileName, ".") == 0 ||
+          strcmp(FindInfo.cFileName, "..") == 0)
+        continue;
+      IterateDirRecursive(Path, DirPreCallback, DirPostCallback, FileCallback);
+    } else if (PathAttrs != INVALID_FILE_ATTRIBUTES) {
+      FileCallback(Path);
+    }
+  } while (FindNextFileA(FindHandle, &FindInfo));
+
+  DWORD LastError = GetLastError();
+  if (LastError != ERROR_NO_MORE_FILES)
+    Printf("FindNextFileA failed for %s (Error code: %lu).\n", Dir.c_str(),
+           LastError);
+
+  FindClose(FindHandle);
+  DirPostCallback(Dir);
+}
+
+char GetSeparator() {
+  return '\\';
+}
+
+FILE* OpenFile(int Fd, const char* Mode) {
+  return _fdopen(Fd, Mode);
+}
+
+int CloseFile(int Fd) {
+  return _close(Fd);
+}
+
+int DuplicateFile(int Fd) {
+  return _dup(Fd);
+}
+
+void RemoveFile(const std::string &Path) {
+  _unlink(Path.c_str());
+}
+
+void RenameFile(const std::string &OldPath, const std::string &NewPath) {
+  rename(OldPath.c_str(), NewPath.c_str());
+}
+
+intptr_t GetHandleFromFd(int fd) {
+  return _get_osfhandle(fd);
+}
+
+static bool IsSeparator(char C) {
+  return C == '\\' || C == '/';
+}
+
+// Parse disk designators, like "C:\". If Relative == true, also accepts: "C:".
+// Returns number of characters considered if successful.
+static size_t ParseDrive(const std::string &FileName, const size_t Offset,
+                         bool Relative = true) {
+  if (Offset + 1 >= FileName.size() || FileName[Offset + 1] != ':')
+    return 0;
+  if (Offset + 2 >= FileName.size() || !IsSeparator(FileName[Offset + 2])) {
+    if (!Relative) // Accept relative path?
+      return 0;
+    else
+      return 2;
+  }
+  return 3;
+}
+
+// Parse a file name, like: SomeFile.txt
+// Returns number of characters considered if successful.
+static size_t ParseFileName(const std::string &FileName, const size_t Offset) {
+  size_t Pos = Offset;
+  const size_t End = FileName.size();
+  for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
+    ;
+  return Pos - Offset;
+}
+
+// Parse a directory ending in separator, like: `SomeDir\`
+// Returns number of characters considered if successful.
+static size_t ParseDir(const std::string &FileName, const size_t Offset) {
+  size_t Pos = Offset;
+  const size_t End = FileName.size();
+  if (Pos >= End || IsSeparator(FileName[Pos]))
+    return 0;
+  for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
+    ;
+  if (Pos >= End)
+    return 0;
+  ++Pos; // Include separator.
+  return Pos - Offset;
+}
+
+// Parse a servername and share, like: `SomeServer\SomeShare\`
+// Returns number of characters considered if successful.
+static size_t ParseServerAndShare(const std::string &FileName,
+                                  const size_t Offset) {
+  size_t Pos = Offset, Res;
+  if (!(Res = ParseDir(FileName, Pos)))
+    return 0;
+  Pos += Res;
+  if (!(Res = ParseDir(FileName, Pos)))
+    return 0;
+  Pos += Res;
+  return Pos - Offset;
+}
+
+// Parse the given Ref string from the position Offset, to exactly match the given
+// string Patt.
+// Returns number of characters considered if successful.
+static size_t ParseCustomString(const std::string &Ref, size_t Offset,
+                                const char *Patt) {
+  size_t Len = strlen(Patt);
+  if (Offset + Len > Ref.size())
+    return 0;
+  return Ref.compare(Offset, Len, Patt) == 0 ? Len : 0;
+}
+
+// Parse a location, like:
+// \\?\UNC\Server\Share\  \\?\C:\  \\Server\Share\  \  C:\  C:
+// Returns number of characters considered if successful.
+static size_t ParseLocation(const std::string &FileName) {
+  size_t Pos = 0, Res;
+
+  if ((Res = ParseCustomString(FileName, Pos, R"(\\?\)"))) {
+    Pos += Res;
+    if ((Res = ParseCustomString(FileName, Pos, R"(UNC\)"))) {
+      Pos += Res;
+      if ((Res = ParseServerAndShare(FileName, Pos)))
+        return Pos + Res;
+      return 0;
+    }
+    if ((Res = ParseDrive(FileName, Pos, false)))
+      return Pos + Res;
+    return 0;
+  }
+
+  if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
+    ++Pos;
+    if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
+      ++Pos;
+      if ((Res = ParseServerAndShare(FileName, Pos)))
+        return Pos + Res;
+      return 0;
+    }
+    return Pos;
+  }
+
+  if ((Res = ParseDrive(FileName, Pos)))
+    return Pos + Res;
+
+  return Pos;
+}
+
+std::string DirName(const std::string &FileName) {
+  size_t LocationLen = ParseLocation(FileName);
+  size_t DirLen = 0, Res;
+  while ((Res = ParseDir(FileName, LocationLen + DirLen)))
+    DirLen += Res;
+  size_t FileLen = ParseFileName(FileName, LocationLen + DirLen);
+
+  if (LocationLen + DirLen + FileLen != FileName.size()) {
+    Printf("DirName() failed for \"%s\", invalid path.\n", FileName.c_str());
+    exit(1);
+  }
+
+  if (DirLen) {
+    --DirLen; // Remove trailing separator.
+    if (!FileLen) { // Path ended in separator.
+      assert(DirLen);
+      // Remove file name from Dir.
+      while (DirLen && !IsSeparator(FileName[LocationLen + DirLen - 1]))
+        --DirLen;
+      if (DirLen) // Remove trailing separator.
+        --DirLen;
+    }
+  }
+
+  if (!LocationLen) { // Relative path.
+    if (!DirLen)
+      return ".";
+    return std::string(".\\").append(FileName, 0, DirLen);
+  }
+
+  return FileName.substr(0, LocationLen + DirLen);
+}
+
+std::string TmpDir() {
+  std::string Tmp;
+  Tmp.resize(MAX_PATH + 1);
+  DWORD Size = GetTempPathA(Tmp.size(), &Tmp[0]);
+  if (Size == 0) {
+    Printf("Couldn't get Tmp path.\n");
+    exit(1);
+  }
+  Tmp.resize(Size);
+  return Tmp;
+}
+
+bool IsInterestingCoverageFile(const std::string &FileName) {
+  if (FileName.find("Program Files") != std::string::npos)
+    return false;
+  if (FileName.find("compiler-rt\\lib\\") != std::string::npos)
+    return false; // sanitizer internal.
+  if (FileName == "<null>")
+    return false;
+  return true;
+}
+
+void RawPrint(const char *Str) {
+  _write(2, Str, strlen(Str));
+}
+
+void MkDir(const std::string &Path) {
+  if (CreateDirectoryA(Path.c_str(), nullptr)) return;
+  Printf("CreateDirectoryA failed for %s (Error code: %lu).\n", Path.c_str(),
+         GetLastError());
+}
+
+void RmDir(const std::string &Path) {
+  if (RemoveDirectoryA(Path.c_str())) return;
+  Printf("RemoveDirectoryA failed for %s (Error code: %lu).\n", Path.c_str(),
+         GetLastError());
+}
+
+const std::string &getDevNull() {
+  static const std::string devNull = "NUL";
+  return devNull;
+}
+
+}  // namespace fuzzer
+
+#endif // LIBFUZZER_WINDOWS
diff --git a/libfuzzer/FuzzerInterceptors.cpp b/libfuzzer/FuzzerInterceptors.cpp
new file mode 100644
index 0000000..a1a6478
--- /dev/null
+++ b/libfuzzer/FuzzerInterceptors.cpp
@@ -0,0 +1,235 @@
+//===-- FuzzerInterceptors.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Intercept certain libc functions to aid fuzzing.
+// Linked only when other RTs that define their own interceptors are not linked.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerPlatform.h"
+
+#if LIBFUZZER_LINUX
+
+#define GET_CALLER_PC() __builtin_return_address(0)
+
+#define PTR_TO_REAL(x) real_##x
+#define REAL(x) __interception::PTR_TO_REAL(x)
+#define FUNC_TYPE(x) x##_type
+#define DEFINE_REAL(ret_type, func, ...)                                       \
+  typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__);                            \
+  namespace __interception {                                                   \
+  FUNC_TYPE(func) PTR_TO_REAL(func);                                           \
+  }
+
+#include <cassert>
+#include <cstdint>
+#include <dlfcn.h> // for dlsym()
+#include <sanitizer/common_interface_defs.h>
+
+static void *getFuncAddr(const char *name, uintptr_t wrapper_addr) {
+  void *addr = dlsym(RTLD_NEXT, name);
+  if (!addr) {
+    // If the lookup using RTLD_NEXT failed, the sanitizer runtime library is
+    // later in the library search order than the DSO that we are trying to
+    // intercept, which means that we cannot intercept this function. We still
+    // want the address of the real definition, though, so look it up using
+    // RTLD_DEFAULT.
+    addr = dlsym(RTLD_DEFAULT, name);
+
+    // In case `name' is not loaded, dlsym ends up finding the actual wrapper.
+    // We don't want to intercept the wrapper and have it point to itself.
+    if (reinterpret_cast<uintptr_t>(addr) == wrapper_addr)
+      addr = nullptr;
+  }
+  return addr;
+}
+
+static int FuzzerInited = 0;
+static bool FuzzerInitIsRunning;
+
+static void fuzzerInit();
+
+static void ensureFuzzerInited() {
+  assert(!FuzzerInitIsRunning);
+  if (!FuzzerInited) {
+    fuzzerInit();
+  }
+}
+
+static int internal_strcmp_strncmp(const char *s1, const char *s2, bool strncmp,
+                                   size_t n) {
+  size_t i = 0;
+  while (true) {
+    if (strncmp) {
+      if (i == n)
+        break;
+      i++;
+    }
+    unsigned c1 = *s1;
+    unsigned c2 = *s2;
+    if (c1 != c2)
+      return (c1 < c2) ? -1 : 1;
+    if (c1 == 0)
+      break;
+    s1++;
+    s2++;
+  }
+  return 0;
+}
+
+static int internal_strncmp(const char *s1, const char *s2, size_t n) {
+  return internal_strcmp_strncmp(s1, s2, true, n);
+}
+
+static int internal_strcmp(const char *s1, const char *s2) {
+  return internal_strcmp_strncmp(s1, s2, false, 0);
+}
+
+static int internal_memcmp(const void *s1, const void *s2, size_t n) {
+  const uint8_t *t1 = static_cast<const uint8_t *>(s1);
+  const uint8_t *t2 = static_cast<const uint8_t *>(s2);
+  for (size_t i = 0; i < n; ++i, ++t1, ++t2)
+    if (*t1 != *t2)
+      return *t1 < *t2 ? -1 : 1;
+  return 0;
+}
+
+static size_t internal_strlen(const char *s) {
+  size_t i = 0;
+  while (s[i])
+    i++;
+  return i;
+}
+
+static char *internal_strstr(const char *haystack, const char *needle) {
+  // This is O(N^2), but we are not using it in hot places.
+  size_t len1 = internal_strlen(haystack);
+  size_t len2 = internal_strlen(needle);
+  if (len1 < len2)
+    return nullptr;
+  for (size_t pos = 0; pos <= len1 - len2; pos++) {
+    if (internal_memcmp(haystack + pos, needle, len2) == 0)
+      return const_cast<char *>(haystack) + pos;
+  }
+  return nullptr;
+}
+
+extern "C" {
+
+DEFINE_REAL(int, bcmp, const void *, const void *, size_t)
+DEFINE_REAL(int, memcmp, const void *, const void *, size_t)
+DEFINE_REAL(int, strncmp, const char *, const char *, size_t)
+DEFINE_REAL(int, strcmp, const char *, const char *)
+DEFINE_REAL(int, strncasecmp, const char *, const char *, size_t)
+DEFINE_REAL(int, strcasecmp, const char *, const char *)
+DEFINE_REAL(char *, strstr, const char *, const char *)
+DEFINE_REAL(char *, strcasestr, const char *, const char *)
+DEFINE_REAL(void *, memmem, const void *, size_t, const void *, size_t)
+
+ATTRIBUTE_INTERFACE int bcmp(const char *s1, const char *s2, size_t n) {
+  if (!FuzzerInited)
+    return internal_memcmp(s1, s2, n);
+  int result = REAL(bcmp)(s1, s2, n);
+  __sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1, s2, n, result);
+  return result;
+}
+
+ATTRIBUTE_INTERFACE int memcmp(const void *s1, const void *s2, size_t n) {
+  if (!FuzzerInited)
+    return internal_memcmp(s1, s2, n);
+  int result = REAL(memcmp)(s1, s2, n);
+  __sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1, s2, n, result);
+  return result;
+}
+
+ATTRIBUTE_INTERFACE int strncmp(const char *s1, const char *s2, size_t n) {
+  if (!FuzzerInited)
+    return internal_strncmp(s1, s2, n);
+  int result = REAL(strncmp)(s1, s2, n);
+  __sanitizer_weak_hook_strncmp(GET_CALLER_PC(), s1, s2, n, result);
+  return result;
+}
+
+ATTRIBUTE_INTERFACE int strcmp(const char *s1, const char *s2) {
+  if (!FuzzerInited)
+    return internal_strcmp(s1, s2);
+  int result = REAL(strcmp)(s1, s2);
+  __sanitizer_weak_hook_strcmp(GET_CALLER_PC(), s1, s2, result);
+  return result;
+}
+
+ATTRIBUTE_INTERFACE int strncasecmp(const char *s1, const char *s2, size_t n) {
+  ensureFuzzerInited();
+  int result = REAL(strncasecmp)(s1, s2, n);
+  __sanitizer_weak_hook_strncasecmp(GET_CALLER_PC(), s1, s2, n, result);
+  return result;
+}
+
+ATTRIBUTE_INTERFACE int strcasecmp(const char *s1, const char *s2) {
+  ensureFuzzerInited();
+  int result = REAL(strcasecmp)(s1, s2);
+  __sanitizer_weak_hook_strcasecmp(GET_CALLER_PC(), s1, s2, result);
+  return result;
+}
+
+ATTRIBUTE_INTERFACE char *strstr(const char *s1, const char *s2) {
+  if (!FuzzerInited)
+    return internal_strstr(s1, s2);
+  char *result = REAL(strstr)(s1, s2);
+  __sanitizer_weak_hook_strstr(GET_CALLER_PC(), s1, s2, result);
+  return result;
+}
+
+ATTRIBUTE_INTERFACE char *strcasestr(const char *s1, const char *s2) {
+  ensureFuzzerInited();
+  char *result = REAL(strcasestr)(s1, s2);
+  __sanitizer_weak_hook_strcasestr(GET_CALLER_PC(), s1, s2, result);
+  return result;
+}
+
+ATTRIBUTE_INTERFACE
+void *memmem(const void *s1, size_t len1, const void *s2, size_t len2) {
+  ensureFuzzerInited();
+  void *result = REAL(memmem)(s1, len1, s2, len2);
+  __sanitizer_weak_hook_memmem(GET_CALLER_PC(), s1, len1, s2, len2, result);
+  return result;
+}
+
+__attribute__((section(".preinit_array"),
+               used)) static void (*__local_fuzzer_preinit)(void) = fuzzerInit;
+
+} // extern "C"
+
+static void fuzzerInit() {
+  assert(!FuzzerInitIsRunning);
+  if (FuzzerInited)
+    return;
+  FuzzerInitIsRunning = true;
+
+  REAL(bcmp) = reinterpret_cast<memcmp_type>(
+      getFuncAddr("bcmp", reinterpret_cast<uintptr_t>(&bcmp)));
+  REAL(memcmp) = reinterpret_cast<memcmp_type>(
+      getFuncAddr("memcmp", reinterpret_cast<uintptr_t>(&memcmp)));
+  REAL(strncmp) = reinterpret_cast<strncmp_type>(
+      getFuncAddr("strncmp", reinterpret_cast<uintptr_t>(&strncmp)));
+  REAL(strcmp) = reinterpret_cast<strcmp_type>(
+      getFuncAddr("strcmp", reinterpret_cast<uintptr_t>(&strcmp)));
+  REAL(strncasecmp) = reinterpret_cast<strncasecmp_type>(
+      getFuncAddr("strncasecmp", reinterpret_cast<uintptr_t>(&strncasecmp)));
+  REAL(strcasecmp) = reinterpret_cast<strcasecmp_type>(
+      getFuncAddr("strcasecmp", reinterpret_cast<uintptr_t>(&strcasecmp)));
+  REAL(strstr) = reinterpret_cast<strstr_type>(
+      getFuncAddr("strstr", reinterpret_cast<uintptr_t>(&strstr)));
+  REAL(strcasestr) = reinterpret_cast<strcasestr_type>(
+      getFuncAddr("strcasestr", reinterpret_cast<uintptr_t>(&strcasestr)));
+  REAL(memmem) = reinterpret_cast<memmem_type>(
+      getFuncAddr("memmem", reinterpret_cast<uintptr_t>(&memmem)));
+
+  FuzzerInitIsRunning = false;
+  FuzzerInited = 1;
+}
+
+#endif
diff --git a/libfuzzer/FuzzerInterface.h b/libfuzzer/FuzzerInterface.h
new file mode 100644
index 0000000..4f62822
--- /dev/null
+++ b/libfuzzer/FuzzerInterface.h
@@ -0,0 +1,79 @@
+//===- FuzzerInterface.h - Interface header for the Fuzzer ------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Define the interface between libFuzzer and the library being tested.
+//===----------------------------------------------------------------------===//
+
+// NOTE: the libFuzzer interface is thin and in the majority of cases
+// you should not include this file into your target. In 95% of cases
+// all you need is to define the following function in your file:
+// extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+
+// WARNING: keep the interface in C.
+
+#ifndef LLVM_FUZZER_INTERFACE_H
+#define LLVM_FUZZER_INTERFACE_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __cplusplus
+
+// Define FUZZER_INTERFACE_VISIBILITY to set default visibility in a way that
+// doesn't break MSVC.
+#if defined(_WIN32)
+#define FUZZER_INTERFACE_VISIBILITY __declspec(dllexport)
+#else
+#define FUZZER_INTERFACE_VISIBILITY __attribute__((visibility("default")))
+#endif
+
+// 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.
+FUZZER_INTERFACE_VISIBILITY int
+LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+
+// Optional user-provided initialization function.
+// If provided, this function will be called by libFuzzer once at startup.
+// It may read and modify argc/argv.
+// Must return 0.
+FUZZER_INTERFACE_VISIBILITY int LLVMFuzzerInitialize(int *argc, char ***argv);
+
+// Optional user-provided custom mutator.
+// Mutates raw data in [Data, Data+Size) inplace.
+// Returns the new size, which is not greater than MaxSize.
+// Given the same Seed produces the same mutation.
+FUZZER_INTERFACE_VISIBILITY size_t
+LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize,
+                        unsigned int Seed);
+
+// Optional user-provided custom cross-over function.
+// Combines pieces of Data1 & Data2 together into Out.
+// Returns the new size, which is not greater than MaxOutSize.
+// Should produce the same mutation given the same Seed.
+FUZZER_INTERFACE_VISIBILITY size_t
+LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1,
+                          const uint8_t *Data2, size_t Size2, uint8_t *Out,
+                          size_t MaxOutSize, unsigned int Seed);
+
+// Experimental, may go away in future.
+// libFuzzer-provided function to be used inside LLVMFuzzerCustomMutator.
+// Mutates raw data in [Data, Data+Size) inplace.
+// Returns the new size, which is not greater than MaxSize.
+FUZZER_INTERFACE_VISIBILITY size_t
+LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
+
+#undef FUZZER_INTERFACE_VISIBILITY
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif  // __cplusplus
+
+#endif  // LLVM_FUZZER_INTERFACE_H
diff --git a/libfuzzer/FuzzerInternal.h b/libfuzzer/FuzzerInternal.h
new file mode 100644
index 0000000..31096ce
--- /dev/null
+++ b/libfuzzer/FuzzerInternal.h
@@ -0,0 +1,172 @@
+//===- FuzzerInternal.h - Internal header for the Fuzzer --------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Define the main class fuzzer::Fuzzer and most functions.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_INTERNAL_H
+#define LLVM_FUZZER_INTERNAL_H
+
+#include "FuzzerDataFlowTrace.h"
+#include "FuzzerDefs.h"
+#include "FuzzerExtFunctions.h"
+#include "FuzzerInterface.h"
+#include "FuzzerOptions.h"
+#include "FuzzerSHA1.h"
+#include "FuzzerValueBitMap.h"
+#include <algorithm>
+#include <atomic>
+#include <chrono>
+#include <climits>
+#include <cstdlib>
+#include <string.h>
+
+namespace fuzzer {
+
+using namespace std::chrono;
+
+class Fuzzer {
+public:
+
+  Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
+         FuzzingOptions Options);
+  ~Fuzzer();
+  void Loop(Vector<SizedFile> &CorporaFiles);
+  void ReadAndExecuteSeedCorpora(Vector<SizedFile> &CorporaFiles);
+  void MinimizeCrashLoop(const Unit &U);
+  void RereadOutputCorpus(size_t MaxSize);
+
+  size_t secondsSinceProcessStartUp() {
+    return duration_cast<seconds>(system_clock::now() - ProcessStartTime)
+        .count();
+  }
+
+  bool TimedOut() {
+    return Options.MaxTotalTimeSec > 0 &&
+           secondsSinceProcessStartUp() >
+               static_cast<size_t>(Options.MaxTotalTimeSec);
+  }
+
+  size_t execPerSec() {
+    size_t Seconds = secondsSinceProcessStartUp();
+    return Seconds ? TotalNumberOfRuns / Seconds : 0;
+  }
+
+  size_t getTotalNumberOfRuns() { return TotalNumberOfRuns; }
+
+  static void StaticAlarmCallback();
+  static void StaticCrashSignalCallback();
+  static void StaticExitCallback();
+  static void StaticInterruptCallback();
+  static void StaticFileSizeExceedCallback();
+  static void StaticGracefulExitCallback();
+
+  void ExecuteCallback(const uint8_t *Data, size_t Size);
+  bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false,
+              InputInfo *II = nullptr, bool *FoundUniqFeatures = nullptr);
+
+  // Merge Corpora[1:] into Corpora[0].
+  void Merge(const Vector<std::string> &Corpora);
+  void CrashResistantMergeInternalStep(const std::string &ControlFilePath);
+  MutationDispatcher &GetMD() { return MD; }
+  void PrintFinalStats();
+  void SetMaxInputLen(size_t MaxInputLen);
+  void SetMaxMutationLen(size_t MaxMutationLen);
+  void RssLimitCallback();
+
+  bool InFuzzingThread() const { return IsMyThread; }
+  size_t GetCurrentUnitInFuzzingThead(const uint8_t **Data) const;
+  void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
+                               bool DuringInitialCorpusExecution);
+
+  void HandleMalloc(size_t Size);
+  static void MaybeExitGracefully();
+  std::string WriteToOutputCorpus(const Unit &U);
+
+private:
+  void AlarmCallback();
+  void CrashCallback();
+  void ExitCallback();
+  void CrashOnOverwrittenData();
+  void InterruptCallback();
+  void MutateAndTestOne();
+  void PurgeAllocator();
+  void ReportNewCoverage(InputInfo *II, const Unit &U);
+  void PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size);
+  void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix);
+  void PrintStats(const char *Where, const char *End = "\n", size_t Units = 0,
+                  size_t Features = 0);
+  void PrintStatusForNewUnit(const Unit &U, const char *Text);
+  void CheckExitOnSrcPosOrItem();
+
+  static void StaticDeathCallback();
+  void DumpCurrentUnit(const char *Prefix);
+  void DeathCallback();
+
+  void AllocateCurrentUnitData();
+  uint8_t *CurrentUnitData = nullptr;
+  std::atomic<size_t> CurrentUnitSize;
+  uint8_t BaseSha1[kSHA1NumBytes];  // Checksum of the base unit.
+
+  bool GracefulExitRequested = false;
+
+  size_t TotalNumberOfRuns = 0;
+  size_t NumberOfNewUnitsAdded = 0;
+
+  size_t LastCorpusUpdateRun = 0;
+
+  bool HasMoreMallocsThanFrees = false;
+  size_t NumberOfLeakDetectionAttempts = 0;
+
+  system_clock::time_point LastAllocatorPurgeAttemptTime = system_clock::now();
+
+  UserCallback CB;
+  InputCorpus &Corpus;
+  MutationDispatcher &MD;
+  FuzzingOptions Options;
+  DataFlowTrace DFT;
+
+  system_clock::time_point ProcessStartTime = system_clock::now();
+  system_clock::time_point UnitStartTime, UnitStopTime;
+  long TimeOfLongestUnitInSeconds = 0;
+  long EpochOfLastReadOfOutputCorpus = 0;
+
+  size_t MaxInputLen = 0;
+  size_t MaxMutationLen = 0;
+  size_t TmpMaxMutationLen = 0;
+
+  Vector<uint32_t> UniqFeatureSetTmp;
+
+  // Need to know our own thread.
+  static thread_local bool IsMyThread;
+};
+
+struct ScopedEnableMsanInterceptorChecks {
+  ScopedEnableMsanInterceptorChecks() {
+    if (EF->__msan_scoped_enable_interceptor_checks)
+      EF->__msan_scoped_enable_interceptor_checks();
+  }
+  ~ScopedEnableMsanInterceptorChecks() {
+    if (EF->__msan_scoped_disable_interceptor_checks)
+      EF->__msan_scoped_disable_interceptor_checks();
+  }
+};
+
+struct ScopedDisableMsanInterceptorChecks {
+  ScopedDisableMsanInterceptorChecks() {
+    if (EF->__msan_scoped_disable_interceptor_checks)
+      EF->__msan_scoped_disable_interceptor_checks();
+  }
+  ~ScopedDisableMsanInterceptorChecks() {
+    if (EF->__msan_scoped_enable_interceptor_checks)
+      EF->__msan_scoped_enable_interceptor_checks();
+  }
+};
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_INTERNAL_H
diff --git a/libfuzzer/FuzzerLoop.cpp b/libfuzzer/FuzzerLoop.cpp
new file mode 100644
index 0000000..02db6d2
--- /dev/null
+++ b/libfuzzer/FuzzerLoop.cpp
@@ -0,0 +1,874 @@
+//===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Fuzzer's main loop.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerCorpus.h"
+#include "FuzzerIO.h"
+#include "FuzzerInternal.h"
+#include "FuzzerMutate.h"
+#include "FuzzerPlatform.h"
+#include "FuzzerRandom.h"
+#include "FuzzerTracePC.h"
+#include <algorithm>
+#include <cstring>
+#include <memory>
+#include <mutex>
+#include <set>
+
+#if defined(__has_include)
+#if __has_include(<sanitizer / lsan_interface.h>)
+#include <sanitizer/lsan_interface.h>
+#endif
+#endif
+
+#define NO_SANITIZE_MEMORY
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#undef NO_SANITIZE_MEMORY
+#define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
+#endif
+#endif
+
+namespace fuzzer {
+static const size_t kMaxUnitSizeToPrint = 256;
+
+thread_local bool Fuzzer::IsMyThread;
+
+bool RunningUserCallback = false;
+
+// Only one Fuzzer per process.
+static Fuzzer *F;
+
+// Leak detection is expensive, so we first check if there were more mallocs
+// than frees (using the sanitizer malloc hooks) and only then try to call lsan.
+struct MallocFreeTracer {
+  void Start(int TraceLevel) {
+    this->TraceLevel = TraceLevel;
+    if (TraceLevel)
+      Printf("MallocFreeTracer: START\n");
+    Mallocs = 0;
+    Frees = 0;
+  }
+  // Returns true if there were more mallocs than frees.
+  bool Stop() {
+    if (TraceLevel)
+      Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs.load(),
+             Frees.load(), Mallocs == Frees ? "same" : "DIFFERENT");
+    bool Result = Mallocs > Frees;
+    Mallocs = 0;
+    Frees = 0;
+    TraceLevel = 0;
+    return Result;
+  }
+  std::atomic<size_t> Mallocs;
+  std::atomic<size_t> Frees;
+  int TraceLevel = 0;
+
+  std::recursive_mutex TraceMutex;
+  bool TraceDisabled = false;
+};
+
+static MallocFreeTracer AllocTracer;
+
+// Locks printing and avoids nested hooks triggered from mallocs/frees in
+// sanitizer.
+class TraceLock {
+public:
+  TraceLock() : Lock(AllocTracer.TraceMutex) {
+    AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled;
+  }
+  ~TraceLock() { AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled; }
+
+  bool IsDisabled() const {
+    // This is already inverted value.
+    return !AllocTracer.TraceDisabled;
+  }
+
+private:
+  std::lock_guard<std::recursive_mutex> Lock;
+};
+
+ATTRIBUTE_NO_SANITIZE_MEMORY
+void MallocHook(const volatile void *ptr, size_t size) {
+  size_t N = AllocTracer.Mallocs++;
+  F->HandleMalloc(size);
+  if (int TraceLevel = AllocTracer.TraceLevel) {
+    TraceLock Lock;
+    if (Lock.IsDisabled())
+      return;
+    Printf("MALLOC[%zd] %p %zd\n", N, ptr, size);
+    if (TraceLevel >= 2 && EF)
+      PrintStackTrace();
+  }
+}
+
+ATTRIBUTE_NO_SANITIZE_MEMORY
+void FreeHook(const volatile void *ptr) {
+  size_t N = AllocTracer.Frees++;
+  if (int TraceLevel = AllocTracer.TraceLevel) {
+    TraceLock Lock;
+    if (Lock.IsDisabled())
+      return;
+    Printf("FREE[%zd]   %p\n", N, ptr);
+    if (TraceLevel >= 2 && EF)
+      PrintStackTrace();
+  }
+}
+
+// Crash on a single malloc that exceeds the rss limit.
+void Fuzzer::HandleMalloc(size_t Size) {
+  if (!Options.MallocLimitMb || (Size >> 20) < (size_t)Options.MallocLimitMb)
+    return;
+  Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(),
+         Size);
+  Printf("   To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
+  PrintStackTrace();
+  DumpCurrentUnit("oom-");
+  Printf("SUMMARY: libFuzzer: out-of-memory\n");
+  PrintFinalStats();
+  _Exit(Options.OOMExitCode); // Stop right now.
+}
+
+Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
+               FuzzingOptions Options)
+    : CB(CB), Corpus(Corpus), MD(MD), Options(Options) {
+  if (EF->__sanitizer_set_death_callback)
+    EF->__sanitizer_set_death_callback(StaticDeathCallback);
+  assert(!F);
+  F = this;
+  TPC.ResetMaps();
+  IsMyThread = true;
+  if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks)
+    EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);
+  TPC.SetUseCounters(Options.UseCounters);
+  TPC.SetUseValueProfileMask(Options.UseValueProfile);
+
+  if (Options.Verbosity)
+    TPC.PrintModuleInfo();
+  if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec)
+    EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus);
+  MaxInputLen = MaxMutationLen = Options.MaxLen;
+  TmpMaxMutationLen = 0;  // Will be set once we load the corpus.
+  AllocateCurrentUnitData();
+  CurrentUnitSize = 0;
+  memset(BaseSha1, 0, sizeof(BaseSha1));
+}
+
+Fuzzer::~Fuzzer() {}
+
+void Fuzzer::AllocateCurrentUnitData() {
+  if (CurrentUnitData || MaxInputLen == 0)
+    return;
+  CurrentUnitData = new uint8_t[MaxInputLen];
+}
+
+void Fuzzer::StaticDeathCallback() {
+  assert(F);
+  F->DeathCallback();
+}
+
+void Fuzzer::DumpCurrentUnit(const char *Prefix) {
+  if (!CurrentUnitData)
+    return; // Happens when running individual inputs.
+  ScopedDisableMsanInterceptorChecks S;
+  MD.PrintMutationSequence();
+  Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str());
+  size_t UnitSize = CurrentUnitSize;
+  if (UnitSize <= kMaxUnitSizeToPrint) {
+    PrintHexArray(CurrentUnitData, UnitSize, "\n");
+    PrintASCII(CurrentUnitData, UnitSize, "\n");
+  }
+  WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize},
+                            Prefix);
+}
+
+NO_SANITIZE_MEMORY
+void Fuzzer::DeathCallback() {
+  DumpCurrentUnit("crash-");
+  PrintFinalStats();
+}
+
+void Fuzzer::StaticAlarmCallback() {
+  assert(F);
+  F->AlarmCallback();
+}
+
+void Fuzzer::StaticCrashSignalCallback() {
+  assert(F);
+  F->CrashCallback();
+}
+
+void Fuzzer::StaticExitCallback() {
+  assert(F);
+  F->ExitCallback();
+}
+
+void Fuzzer::StaticInterruptCallback() {
+  assert(F);
+  F->InterruptCallback();
+}
+
+void Fuzzer::StaticGracefulExitCallback() {
+  assert(F);
+  F->GracefulExitRequested = true;
+  Printf("INFO: signal received, trying to exit gracefully\n");
+}
+
+void Fuzzer::StaticFileSizeExceedCallback() {
+  Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid());
+  exit(1);
+}
+
+void Fuzzer::CrashCallback() {
+  if (EF->__sanitizer_acquire_crash_state &&
+      !EF->__sanitizer_acquire_crash_state())
+    return;
+  Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid());
+  PrintStackTrace();
+  Printf("NOTE: libFuzzer has rudimentary signal handlers.\n"
+         "      Combine libFuzzer with AddressSanitizer or similar for better "
+         "crash reports.\n");
+  Printf("SUMMARY: libFuzzer: deadly signal\n");
+  DumpCurrentUnit("crash-");
+  PrintFinalStats();
+  _Exit(Options.ErrorExitCode); // Stop right now.
+}
+
+void Fuzzer::ExitCallback() {
+  if (!RunningUserCallback)
+    return; // This exit did not come from the user callback
+  if (EF->__sanitizer_acquire_crash_state &&
+      !EF->__sanitizer_acquire_crash_state())
+    return;
+  Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid());
+  PrintStackTrace();
+  Printf("SUMMARY: libFuzzer: fuzz target exited\n");
+  DumpCurrentUnit("crash-");
+  PrintFinalStats();
+  _Exit(Options.ErrorExitCode);
+}
+
+void Fuzzer::MaybeExitGracefully() {
+  if (!F->GracefulExitRequested) return;
+  Printf("==%lu== INFO: libFuzzer: exiting as requested\n", GetPid());
+  RmDirRecursive(TempPath("FuzzWithFork", ".dir"));
+  F->PrintFinalStats();
+  _Exit(0);
+}
+
+void Fuzzer::InterruptCallback() {
+  Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid());
+  PrintFinalStats();
+  ScopedDisableMsanInterceptorChecks S; // RmDirRecursive may call opendir().
+  RmDirRecursive(TempPath("FuzzWithFork", ".dir"));
+  // Stop right now, don't perform any at-exit actions.
+  _Exit(Options.InterruptExitCode);
+}
+
+NO_SANITIZE_MEMORY
+void Fuzzer::AlarmCallback() {
+  assert(Options.UnitTimeoutSec > 0);
+  // In Windows and Fuchsia, Alarm callback is executed by a different thread.
+  // NetBSD's current behavior needs this change too.
+#if !LIBFUZZER_WINDOWS && !LIBFUZZER_NETBSD && !LIBFUZZER_FUCHSIA
+  if (!InFuzzingThread())
+    return;
+#endif
+  if (!RunningUserCallback)
+    return; // We have not started running units yet.
+  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) {
+    if (EF->__sanitizer_acquire_crash_state &&
+        !EF->__sanitizer_acquire_crash_state())
+      return;
+    Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds);
+    Printf("       and the timeout value is %d (use -timeout=N to change)\n",
+           Options.UnitTimeoutSec);
+    DumpCurrentUnit("timeout-");
+    Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(),
+           Seconds);
+    PrintStackTrace();
+    Printf("SUMMARY: libFuzzer: timeout\n");
+    PrintFinalStats();
+    _Exit(Options.TimeoutExitCode); // Stop right now.
+  }
+}
+
+void Fuzzer::RssLimitCallback() {
+  if (EF->__sanitizer_acquire_crash_state &&
+      !EF->__sanitizer_acquire_crash_state())
+    return;
+  Printf(
+      "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n",
+      GetPid(), GetPeakRSSMb(), Options.RssLimitMb);
+  Printf("   To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
+  PrintMemoryProfile();
+  DumpCurrentUnit("oom-");
+  Printf("SUMMARY: libFuzzer: out-of-memory\n");
+  PrintFinalStats();
+  _Exit(Options.OOMExitCode); // Stop right now.
+}
+
+void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units,
+                        size_t Features) {
+  size_t ExecPerSec = execPerSec();
+  if (!Options.Verbosity)
+    return;
+  Printf("#%zd\t%s", TotalNumberOfRuns, Where);
+  if (size_t N = TPC.GetTotalPCCoverage())
+    Printf(" cov: %zd", N);
+  if (size_t N = Features ? Features : Corpus.NumFeatures())
+    Printf(" ft: %zd", N);
+  if (!Corpus.empty()) {
+    Printf(" corp: %zd", Corpus.NumActiveUnits());
+    if (size_t N = Corpus.SizeInBytes()) {
+      if (N < (1 << 14))
+        Printf("/%zdb", N);
+      else if (N < (1 << 24))
+        Printf("/%zdKb", N >> 10);
+      else
+        Printf("/%zdMb", N >> 20);
+    }
+    if (size_t FF = Corpus.NumInputsThatTouchFocusFunction())
+      Printf(" focus: %zd", FF);
+  }
+  if (TmpMaxMutationLen)
+    Printf(" lim: %zd", TmpMaxMutationLen);
+  if (Units)
+    Printf(" units: %zd", Units);
+
+  Printf(" exec/s: %zd", ExecPerSec);
+  Printf(" rss: %zdMb", GetPeakRSSMb());
+  Printf("%s", End);
+}
+
+void Fuzzer::PrintFinalStats() {
+  if (Options.PrintCoverage)
+    TPC.PrintCoverage();
+  if (Options.PrintCorpusStats)
+    Corpus.PrintStats();
+  if (!Options.PrintFinalStats)
+    return;
+  size_t ExecPerSec = execPerSec();
+  Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns);
+  Printf("stat::average_exec_per_sec:     %zd\n", ExecPerSec);
+  Printf("stat::new_units_added:          %zd\n", NumberOfNewUnitsAdded);
+  Printf("stat::slowest_unit_time_sec:    %zd\n", TimeOfLongestUnitInSeconds);
+  Printf("stat::peak_rss_mb:              %zd\n", GetPeakRSSMb());
+}
+
+void Fuzzer::SetMaxInputLen(size_t MaxInputLen) {
+  assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0.
+  assert(MaxInputLen);
+  this->MaxInputLen = MaxInputLen;
+  this->MaxMutationLen = MaxInputLen;
+  AllocateCurrentUnitData();
+  Printf("INFO: -max_len is not provided; "
+         "libFuzzer will not generate inputs larger than %zd bytes\n",
+         MaxInputLen);
+}
+
+void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) {
+  assert(MaxMutationLen && MaxMutationLen <= MaxInputLen);
+  this->MaxMutationLen = MaxMutationLen;
+}
+
+void Fuzzer::CheckExitOnSrcPosOrItem() {
+  if (!Options.ExitOnSrcPos.empty()) {
+    static auto *PCsSet = new Set<uintptr_t>;
+    auto HandlePC = [&](const TracePC::PCTableEntry *TE) {
+      if (!PCsSet->insert(TE->PC).second)
+        return;
+      std::string Descr = DescribePC("%F %L", TE->PC + 1);
+      if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) {
+        Printf("INFO: found line matching '%s', exiting.\n",
+               Options.ExitOnSrcPos.c_str());
+        _Exit(0);
+      }
+    };
+    TPC.ForEachObservedPC(HandlePC);
+  }
+  if (!Options.ExitOnItem.empty()) {
+    if (Corpus.HasUnit(Options.ExitOnItem)) {
+      Printf("INFO: found item with checksum '%s', exiting.\n",
+             Options.ExitOnItem.c_str());
+      _Exit(0);
+    }
+  }
+}
+
+void Fuzzer::RereadOutputCorpus(size_t MaxSize) {
+  if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec)
+    return;
+  Vector<Unit> AdditionalCorpus;
+  ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus,
+                         &EpochOfLastReadOfOutputCorpus, MaxSize,
+                         /*ExitOnError*/ false);
+  if (Options.Verbosity >= 2)
+    Printf("Reload: read %zd new units.\n", AdditionalCorpus.size());
+  bool Reloaded = false;
+  for (auto &U : AdditionalCorpus) {
+    if (U.size() > MaxSize)
+      U.resize(MaxSize);
+    if (!Corpus.HasUnit(U)) {
+      if (RunOne(U.data(), U.size())) {
+        CheckExitOnSrcPosOrItem();
+        Reloaded = true;
+      }
+    }
+  }
+  if (Reloaded)
+    PrintStats("RELOAD");
+}
+
+void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) {
+  auto TimeOfUnit =
+      duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
+  if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) &&
+      secondsSinceProcessStartUp() >= 2)
+    PrintStats("pulse ");
+  if (TimeOfUnit > TimeOfLongestUnitInSeconds * 1.1 &&
+      TimeOfUnit >= Options.ReportSlowUnits) {
+    TimeOfLongestUnitInSeconds = TimeOfUnit;
+    Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds);
+    WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-");
+  }
+}
+
+static void WriteFeatureSetToFile(const std::string &FeaturesDir,
+                                  const std::string &FileName,
+                                  const Vector<uint32_t> &FeatureSet) {
+  if (FeaturesDir.empty() || FeatureSet.empty()) return;
+  WriteToFile(reinterpret_cast<const uint8_t *>(FeatureSet.data()),
+              FeatureSet.size() * sizeof(FeatureSet[0]),
+              DirPlusFile(FeaturesDir, FileName));
+}
+
+static void RenameFeatureSetFile(const std::string &FeaturesDir,
+                                 const std::string &OldFile,
+                                 const std::string &NewFile) {
+  if (FeaturesDir.empty()) return;
+  RenameFile(DirPlusFile(FeaturesDir, OldFile),
+             DirPlusFile(FeaturesDir, NewFile));
+}
+
+bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
+                    InputInfo *II, bool *FoundUniqFeatures) {
+  if (!Size)
+    return false;
+
+  ExecuteCallback(Data, Size);
+
+  UniqFeatureSetTmp.clear();
+  size_t FoundUniqFeaturesOfII = 0;
+  size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
+  TPC.CollectFeatures([&](size_t Feature) {
+    if (Corpus.AddFeature(Feature, Size, Options.Shrink))
+      UniqFeatureSetTmp.push_back(Feature);
+    if (Options.Entropic)
+      Corpus.UpdateFeatureFrequency(II, Feature);
+    if (Options.ReduceInputs && II)
+      if (std::binary_search(II->UniqFeatureSet.begin(),
+                             II->UniqFeatureSet.end(), Feature))
+        FoundUniqFeaturesOfII++;
+  });
+  if (FoundUniqFeatures)
+    *FoundUniqFeatures = FoundUniqFeaturesOfII;
+  PrintPulseAndReportSlowInput(Data, Size);
+  size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore;
+  if (NumNewFeatures) {
+    TPC.UpdateObservedPCs();
+    auto NewII = Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures,
+                                    MayDeleteFile, TPC.ObservedFocusFunction(),
+                                    UniqFeatureSetTmp, DFT, II);
+    WriteFeatureSetToFile(Options.FeaturesDir, Sha1ToString(NewII->Sha1),
+                          NewII->UniqFeatureSet);
+    return true;
+  }
+  if (II && FoundUniqFeaturesOfII &&
+      II->DataFlowTraceForFocusFunction.empty() &&
+      FoundUniqFeaturesOfII == II->UniqFeatureSet.size() &&
+      II->U.size() > Size) {
+    auto OldFeaturesFile = Sha1ToString(II->Sha1);
+    Corpus.Replace(II, {Data, Data + Size});
+    RenameFeatureSetFile(Options.FeaturesDir, OldFeaturesFile,
+                         Sha1ToString(II->Sha1));
+    return true;
+  }
+  return false;
+}
+
+size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
+  assert(InFuzzingThread());
+  *Data = CurrentUnitData;
+  return CurrentUnitSize;
+}
+
+void Fuzzer::CrashOnOverwrittenData() {
+  Printf("==%d== ERROR: libFuzzer: fuzz target overwrites its const input\n",
+         GetPid());
+  PrintStackTrace();
+  Printf("SUMMARY: libFuzzer: overwrites-const-input\n");
+  DumpCurrentUnit("crash-");
+  PrintFinalStats();
+  _Exit(Options.ErrorExitCode); // Stop right now.
+}
+
+// Compare two arrays, but not all bytes if the arrays are large.
+static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) {
+  const size_t Limit = 64;
+  if (Size <= 64)
+    return !memcmp(A, B, Size);
+  // Compare first and last Limit/2 bytes.
+  return !memcmp(A, B, Limit / 2) &&
+         !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2);
+}
+
+void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
+  TPC.RecordInitialStack();
+  TotalNumberOfRuns++;
+  assert(InFuzzingThread());
+  // We copy the contents of Unit into a separate heap buffer
+  // so that we reliably find buffer overflows in it.
+  uint8_t *DataCopy = new uint8_t[Size];
+  memcpy(DataCopy, Data, Size);
+  if (EF->__msan_unpoison)
+    EF->__msan_unpoison(DataCopy, Size);
+  if (EF->__msan_unpoison_param)
+    EF->__msan_unpoison_param(2);
+  if (CurrentUnitData && CurrentUnitData != Data)
+    memcpy(CurrentUnitData, Data, Size);
+  CurrentUnitSize = Size;
+  {
+    ScopedEnableMsanInterceptorChecks S;
+    AllocTracer.Start(Options.TraceMalloc);
+    UnitStartTime = system_clock::now();
+    TPC.ResetMaps();
+    RunningUserCallback = true;
+    int Res = CB(DataCopy, Size);
+    RunningUserCallback = false;
+    UnitStopTime = system_clock::now();
+    (void)Res;
+    assert(Res == 0);
+    HasMoreMallocsThanFrees = AllocTracer.Stop();
+  }
+  if (!LooseMemeq(DataCopy, Data, Size))
+    CrashOnOverwrittenData();
+  CurrentUnitSize = 0;
+  delete[] DataCopy;
+}
+
+std::string Fuzzer::WriteToOutputCorpus(const Unit &U) {
+  if (Options.OnlyASCII)
+    assert(IsASCII(U));
+  if (Options.OutputCorpus.empty())
+    return "";
+  std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
+  WriteToFile(U, Path);
+  if (Options.Verbosity >= 2)
+    Printf("Written %zd bytes to %s\n", U.size(), Path.c_str());
+  return Path;
+}
+
+void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) {
+  if (!Options.SaveArtifacts)
+    return;
+  std::string Path = Options.ArtifactPrefix + Prefix + Hash(U);
+  if (!Options.ExactArtifactPath.empty())
+    Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix.
+  WriteToFile(U, Path);
+  Printf("artifact_prefix='%s'; Test unit written to %s\n",
+         Options.ArtifactPrefix.c_str(), Path.c_str());
+  if (U.size() <= kMaxUnitSizeToPrint)
+    Printf("Base64: %s\n", Base64(U).c_str());
+}
+
+void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) {
+  if (!Options.PrintNEW)
+    return;
+  PrintStats(Text, "");
+  if (Options.Verbosity) {
+    Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize());
+    MD.PrintMutationSequence();
+    Printf("\n");
+  }
+}
+
+void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) {
+  II->NumSuccessfullMutations++;
+  MD.RecordSuccessfulMutationSequence();
+  PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : "NEW   ");
+  WriteToOutputCorpus(U);
+  NumberOfNewUnitsAdded++;
+  CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus.
+  LastCorpusUpdateRun = TotalNumberOfRuns;
+}
+
+// Tries detecting a memory leak on the particular input that we have just
+// executed before calling this function.
+void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
+                                     bool DuringInitialCorpusExecution) {
+  if (!HasMoreMallocsThanFrees)
+    return; // mallocs==frees, a leak is unlikely.
+  if (!Options.DetectLeaks)
+    return;
+  if (!DuringInitialCorpusExecution &&
+      TotalNumberOfRuns >= Options.MaxNumberOfRuns)
+    return;
+  if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) ||
+      !(EF->__lsan_do_recoverable_leak_check))
+    return; // No lsan.
+  // Run the target once again, but with lsan disabled so that if there is
+  // a real leak we do not report it twice.
+  EF->__lsan_disable();
+  ExecuteCallback(Data, Size);
+  EF->__lsan_enable();
+  if (!HasMoreMallocsThanFrees)
+    return; // a leak is unlikely.
+  if (NumberOfLeakDetectionAttempts++ > 1000) {
+    Options.DetectLeaks = false;
+    Printf("INFO: libFuzzer disabled leak detection after every mutation.\n"
+           "      Most likely the target function accumulates allocated\n"
+           "      memory in a global state w/o actually leaking it.\n"
+           "      You may try running this binary with -trace_malloc=[12]"
+           "      to get a trace of mallocs and frees.\n"
+           "      If LeakSanitizer is enabled in this process it will still\n"
+           "      run on the process shutdown.\n");
+    return;
+  }
+  // Now perform the actual lsan pass. This is expensive and we must ensure
+  // we don't call it too often.
+  if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it.
+    if (DuringInitialCorpusExecution)
+      Printf("\nINFO: a leak has been found in the initial corpus.\n\n");
+    Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n");
+    CurrentUnitSize = Size;
+    DumpCurrentUnit("leak-");
+    PrintFinalStats();
+    _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on.
+  }
+}
+
+void Fuzzer::MutateAndTestOne() {
+  MD.StartMutationSequence();
+
+  auto &II = Corpus.ChooseUnitToMutate(MD.GetRand());
+  if (Options.DoCrossOver)
+    MD.SetCrossOverWith(&Corpus.ChooseUnitToMutate(MD.GetRand()).U);
+  const auto &U = II.U;
+  memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1));
+  assert(CurrentUnitData);
+  size_t Size = U.size();
+  assert(Size <= MaxInputLen && "Oversized Unit");
+  memcpy(CurrentUnitData, U.data(), Size);
+
+  assert(MaxMutationLen > 0);
+
+  size_t CurrentMaxMutationLen =
+      Min(MaxMutationLen, Max(U.size(), TmpMaxMutationLen));
+  assert(CurrentMaxMutationLen > 0);
+
+  for (int i = 0; i < Options.MutateDepth; i++) {
+    if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
+      break;
+    MaybeExitGracefully();
+    size_t NewSize = 0;
+    if (II.HasFocusFunction && !II.DataFlowTraceForFocusFunction.empty() &&
+        Size <= CurrentMaxMutationLen)
+      NewSize = MD.MutateWithMask(CurrentUnitData, Size, Size,
+                                  II.DataFlowTraceForFocusFunction);
+
+    // If MutateWithMask either failed or wasn't called, call default Mutate.
+    if (!NewSize)
+      NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen);
+    assert(NewSize > 0 && "Mutator returned empty unit");
+    assert(NewSize <= CurrentMaxMutationLen && "Mutator return oversized unit");
+    Size = NewSize;
+    II.NumExecutedMutations++;
+    Corpus.IncrementNumExecutedMutations();
+
+    bool FoundUniqFeatures = false;
+    bool NewCov = RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II,
+                         &FoundUniqFeatures);
+    TryDetectingAMemoryLeak(CurrentUnitData, Size,
+                            /*DuringInitialCorpusExecution*/ false);
+    if (NewCov) {
+      ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size});
+      break;  // We will mutate this input more in the next rounds.
+    }
+    if (Options.ReduceDepth && !FoundUniqFeatures)
+      break;
+  }
+
+  II.NeedsEnergyUpdate = true;
+}
+
+void Fuzzer::PurgeAllocator() {
+  if (Options.PurgeAllocatorIntervalSec < 0 || !EF->__sanitizer_purge_allocator)
+    return;
+  if (duration_cast<seconds>(system_clock::now() -
+                             LastAllocatorPurgeAttemptTime)
+          .count() < Options.PurgeAllocatorIntervalSec)
+    return;
+
+  if (Options.RssLimitMb <= 0 ||
+      GetPeakRSSMb() > static_cast<size_t>(Options.RssLimitMb) / 2)
+    EF->__sanitizer_purge_allocator();
+
+  LastAllocatorPurgeAttemptTime = system_clock::now();
+}
+
+void Fuzzer::ReadAndExecuteSeedCorpora(Vector<SizedFile> &CorporaFiles) {
+  const size_t kMaxSaneLen = 1 << 20;
+  const size_t kMinDefaultLen = 4096;
+  size_t MaxSize = 0;
+  size_t MinSize = -1;
+  size_t TotalSize = 0;
+  for (auto &File : CorporaFiles) {
+    MaxSize = Max(File.Size, MaxSize);
+    MinSize = Min(File.Size, MinSize);
+    TotalSize += File.Size;
+  }
+  if (Options.MaxLen == 0)
+    SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxSize), kMaxSaneLen));
+  assert(MaxInputLen > 0);
+
+  // Test the callback with empty input and never try it again.
+  uint8_t dummy = 0;
+  ExecuteCallback(&dummy, 0);
+
+  if (CorporaFiles.empty()) {
+    Printf("INFO: A corpus is not provided, starting from an empty corpus\n");
+    Unit U({'\n'}); // Valid ASCII input.
+    RunOne(U.data(), U.size());
+  } else {
+    Printf("INFO: seed corpus: files: %zd min: %zdb max: %zdb total: %zdb"
+           " rss: %zdMb\n",
+           CorporaFiles.size(), MinSize, MaxSize, TotalSize, GetPeakRSSMb());
+    if (Options.ShuffleAtStartUp)
+      std::shuffle(CorporaFiles.begin(), CorporaFiles.end(), MD.GetRand());
+
+    if (Options.PreferSmall) {
+      std::stable_sort(CorporaFiles.begin(), CorporaFiles.end());
+      assert(CorporaFiles.front().Size <= CorporaFiles.back().Size);
+    }
+
+    // Load and execute inputs one by one.
+    for (auto &SF : CorporaFiles) {
+      auto U = FileToVector(SF.File, MaxInputLen, /*ExitOnError=*/false);
+      assert(U.size() <= MaxInputLen);
+      RunOne(U.data(), U.size());
+      CheckExitOnSrcPosOrItem();
+      TryDetectingAMemoryLeak(U.data(), U.size(),
+                              /*DuringInitialCorpusExecution*/ true);
+    }
+  }
+
+  PrintStats("INITED");
+  if (!Options.FocusFunction.empty()) {
+    Printf("INFO: %zd/%zd inputs touch the focus function\n",
+           Corpus.NumInputsThatTouchFocusFunction(), Corpus.size());
+    if (!Options.DataFlowTrace.empty())
+      Printf("INFO: %zd/%zd inputs have the Data Flow Trace\n",
+             Corpus.NumInputsWithDataFlowTrace(),
+             Corpus.NumInputsThatTouchFocusFunction());
+  }
+
+  if (Corpus.empty() && Options.MaxNumberOfRuns) {
+    Printf("ERROR: no interesting inputs were found. "
+           "Is the code instrumented for coverage? Exiting.\n");
+    exit(1);
+  }
+}
+
+void Fuzzer::Loop(Vector<SizedFile> &CorporaFiles) {
+  auto FocusFunctionOrAuto = Options.FocusFunction;
+  DFT.Init(Options.DataFlowTrace, &FocusFunctionOrAuto, CorporaFiles,
+           MD.GetRand());
+  TPC.SetFocusFunction(FocusFunctionOrAuto);
+  ReadAndExecuteSeedCorpora(CorporaFiles);
+  DFT.Clear();  // No need for DFT any more.
+  TPC.SetPrintNewPCs(Options.PrintNewCovPcs);
+  TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs);
+  system_clock::time_point LastCorpusReload = system_clock::now();
+
+  TmpMaxMutationLen =
+      Min(MaxMutationLen, Max(size_t(4), Corpus.MaxInputSize()));
+
+  while (true) {
+    auto Now = system_clock::now();
+    if (!Options.StopFile.empty() &&
+        !FileToVector(Options.StopFile, 1, false).empty())
+      break;
+    if (duration_cast<seconds>(Now - LastCorpusReload).count() >=
+        Options.ReloadIntervalSec) {
+      RereadOutputCorpus(MaxInputLen);
+      LastCorpusReload = system_clock::now();
+    }
+    if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
+      break;
+    if (TimedOut())
+      break;
+
+    // Update TmpMaxMutationLen
+    if (Options.LenControl) {
+      if (TmpMaxMutationLen < MaxMutationLen &&
+          TotalNumberOfRuns - LastCorpusUpdateRun >
+              Options.LenControl * Log(TmpMaxMutationLen)) {
+        TmpMaxMutationLen =
+            Min(MaxMutationLen, TmpMaxMutationLen + Log(TmpMaxMutationLen));
+        LastCorpusUpdateRun = TotalNumberOfRuns;
+      }
+    } else {
+      TmpMaxMutationLen = MaxMutationLen;
+    }
+
+    // Perform several mutations and runs.
+    MutateAndTestOne();
+
+    PurgeAllocator();
+  }
+
+  PrintStats("DONE  ", "\n");
+  MD.PrintRecommendedDictionary();
+}
+
+void Fuzzer::MinimizeCrashLoop(const Unit &U) {
+  if (U.size() <= 1)
+    return;
+  while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) {
+    MD.StartMutationSequence();
+    memcpy(CurrentUnitData, U.data(), U.size());
+    for (int i = 0; i < Options.MutateDepth; i++) {
+      size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen);
+      assert(NewSize > 0 && NewSize <= MaxMutationLen);
+      ExecuteCallback(CurrentUnitData, NewSize);
+      PrintPulseAndReportSlowInput(CurrentUnitData, NewSize);
+      TryDetectingAMemoryLeak(CurrentUnitData, NewSize,
+                              /*DuringInitialCorpusExecution*/ false);
+    }
+  }
+}
+
+} // namespace fuzzer
+
+extern "C" {
+
+ATTRIBUTE_INTERFACE 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/libfuzzer/FuzzerMain.cpp b/libfuzzer/FuzzerMain.cpp
new file mode 100644
index 0000000..75f2f8e
--- /dev/null
+++ b/libfuzzer/FuzzerMain.cpp
@@ -0,0 +1,21 @@
+//===- FuzzerMain.cpp - main() function and flags -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// main() and flags.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerDefs.h"
+#include "FuzzerPlatform.h"
+
+extern "C" {
+// This function should be defined by the user.
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+}  // extern "C"
+
+ATTRIBUTE_INTERFACE int main(int argc, char **argv) {
+  return fuzzer::FuzzerDriver(&argc, &argv, LLVMFuzzerTestOneInput);
+}
diff --git a/libfuzzer/FuzzerMerge.cpp b/libfuzzer/FuzzerMerge.cpp
new file mode 100644
index 0000000..e3ad8b3
--- /dev/null
+++ b/libfuzzer/FuzzerMerge.cpp
@@ -0,0 +1,402 @@
+//===- FuzzerMerge.cpp - merging corpora ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Merging corpora.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerCommand.h"
+#include "FuzzerMerge.h"
+#include "FuzzerIO.h"
+#include "FuzzerInternal.h"
+#include "FuzzerTracePC.h"
+#include "FuzzerUtil.h"
+
+#include <fstream>
+#include <iterator>
+#include <set>
+#include <sstream>
+#include <unordered_set>
+
+namespace fuzzer {
+
+bool Merger::Parse(const std::string &Str, bool ParseCoverage) {
+  std::istringstream SS(Str);
+  return Parse(SS, ParseCoverage);
+}
+
+void Merger::ParseOrExit(std::istream &IS, bool ParseCoverage) {
+  if (!Parse(IS, ParseCoverage)) {
+    Printf("MERGE: failed to parse the control file (unexpected error)\n");
+    exit(1);
+  }
+}
+
+// The control file example:
+//
+// 3 # The number of inputs
+// 1 # The number of inputs in the first corpus, <= the previous number
+// file0
+// file1
+// file2  # One file name per line.
+// STARTED 0 123  # FileID, file size
+// FT 0 1 4 6 8  # FileID COV1 COV2 ...
+// COV 0 7 8 9 # FileID COV1 COV1
+// STARTED 1 456  # If FT is missing, the input crashed while processing.
+// STARTED 2 567
+// FT 2 8 9
+// COV 2 11 12
+bool Merger::Parse(std::istream &IS, bool ParseCoverage) {
+  LastFailure.clear();
+  std::string Line;
+
+  // Parse NumFiles.
+  if (!std::getline(IS, Line, '\n')) return false;
+  std::istringstream L1(Line);
+  size_t NumFiles = 0;
+  L1 >> NumFiles;
+  if (NumFiles == 0 || NumFiles > 10000000) return false;
+
+  // Parse NumFilesInFirstCorpus.
+  if (!std::getline(IS, Line, '\n')) return false;
+  std::istringstream L2(Line);
+  NumFilesInFirstCorpus = NumFiles + 1;
+  L2 >> NumFilesInFirstCorpus;
+  if (NumFilesInFirstCorpus > NumFiles) return false;
+
+  // Parse file names.
+  Files.resize(NumFiles);
+  for (size_t i = 0; i < NumFiles; i++)
+    if (!std::getline(IS, Files[i].Name, '\n'))
+      return false;
+
+  // Parse STARTED, FT, and COV lines.
+  size_t ExpectedStartMarker = 0;
+  const size_t kInvalidStartMarker = -1;
+  size_t LastSeenStartMarker = kInvalidStartMarker;
+  Vector<uint32_t> TmpFeatures;
+  Set<uint32_t> PCs;
+  while (std::getline(IS, Line, '\n')) {
+    std::istringstream ISS1(Line);
+    std::string Marker;
+    size_t N;
+    ISS1 >> Marker;
+    ISS1 >> N;
+    if (Marker == "STARTED") {
+      // STARTED FILE_ID FILE_SIZE
+      if (ExpectedStartMarker != N)
+        return false;
+      ISS1 >> Files[ExpectedStartMarker].Size;
+      LastSeenStartMarker = ExpectedStartMarker;
+      assert(ExpectedStartMarker < Files.size());
+      ExpectedStartMarker++;
+    } else if (Marker == "FT") {
+      // FT FILE_ID COV1 COV2 COV3 ...
+      size_t CurrentFileIdx = N;
+      if (CurrentFileIdx != LastSeenStartMarker)
+        return false;
+      LastSeenStartMarker = kInvalidStartMarker;
+      if (ParseCoverage) {
+        TmpFeatures.clear();  // use a vector from outer scope to avoid resizes.
+        while (ISS1 >> N)
+          TmpFeatures.push_back(N);
+        std::sort(TmpFeatures.begin(), TmpFeatures.end());
+        Files[CurrentFileIdx].Features = TmpFeatures;
+      }
+    } else if (Marker == "COV") {
+      size_t CurrentFileIdx = N;
+      if (ParseCoverage)
+        while (ISS1 >> N)
+          if (PCs.insert(N).second)
+            Files[CurrentFileIdx].Cov.push_back(N);
+    } else {
+      return false;
+    }
+  }
+  if (LastSeenStartMarker != kInvalidStartMarker)
+    LastFailure = Files[LastSeenStartMarker].Name;
+
+  FirstNotProcessedFile = ExpectedStartMarker;
+  return true;
+}
+
+size_t Merger::ApproximateMemoryConsumption() const  {
+  size_t Res = 0;
+  for (const auto &F: Files)
+    Res += sizeof(F) + F.Features.size() * sizeof(F.Features[0]);
+  return Res;
+}
+
+// Decides which files need to be merged (add those to NewFiles).
+// Returns the number of new features added.
+size_t Merger::Merge(const Set<uint32_t> &InitialFeatures,
+                     Set<uint32_t> *NewFeatures,
+                     const Set<uint32_t> &InitialCov, Set<uint32_t> *NewCov,
+                     Vector<std::string> *NewFiles) {
+  NewFiles->clear();
+  assert(NumFilesInFirstCorpus <= Files.size());
+  Set<uint32_t> AllFeatures = InitialFeatures;
+
+  // What features are in the initial corpus?
+  for (size_t i = 0; i < NumFilesInFirstCorpus; i++) {
+    auto &Cur = Files[i].Features;
+    AllFeatures.insert(Cur.begin(), Cur.end());
+  }
+  // Remove all features that we already know from all other inputs.
+  for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) {
+    auto &Cur = Files[i].Features;
+    Vector<uint32_t> Tmp;
+    std::set_difference(Cur.begin(), Cur.end(), AllFeatures.begin(),
+                        AllFeatures.end(), std::inserter(Tmp, Tmp.begin()));
+    Cur.swap(Tmp);
+  }
+
+  // Sort. Give preference to
+  //   * smaller files
+  //   * files with more features.
+  std::sort(Files.begin() + NumFilesInFirstCorpus, Files.end(),
+            [&](const MergeFileInfo &a, const MergeFileInfo &b) -> bool {
+              if (a.Size != b.Size)
+                return a.Size < b.Size;
+              return a.Features.size() > b.Features.size();
+            });
+
+  // One greedy pass: add the file's features to AllFeatures.
+  // If new features were added, add this file to NewFiles.
+  for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) {
+    auto &Cur = Files[i].Features;
+    // Printf("%s -> sz %zd ft %zd\n", Files[i].Name.c_str(),
+    //       Files[i].Size, Cur.size());
+    bool FoundNewFeatures = false;
+    for (auto Fe: Cur) {
+      if (AllFeatures.insert(Fe).second) {
+        FoundNewFeatures = true;
+        NewFeatures->insert(Fe);
+      }
+    }
+    if (FoundNewFeatures)
+      NewFiles->push_back(Files[i].Name);
+    for (auto Cov : Files[i].Cov)
+      if (InitialCov.find(Cov) == InitialCov.end())
+        NewCov->insert(Cov);
+  }
+  return NewFeatures->size();
+}
+
+Set<uint32_t> Merger::AllFeatures() const {
+  Set<uint32_t> S;
+  for (auto &File : Files)
+    S.insert(File.Features.begin(), File.Features.end());
+  return S;
+}
+
+// Inner process. May crash if the target crashes.
+void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
+  Printf("MERGE-INNER: using the control file '%s'\n", CFPath.c_str());
+  Merger M;
+  std::ifstream IF(CFPath);
+  M.ParseOrExit(IF, false);
+  IF.close();
+  if (!M.LastFailure.empty())
+    Printf("MERGE-INNER: '%s' caused a failure at the previous merge step\n",
+           M.LastFailure.c_str());
+
+  Printf("MERGE-INNER: %zd total files;"
+         " %zd processed earlier; will process %zd files now\n",
+         M.Files.size(), M.FirstNotProcessedFile,
+         M.Files.size() - M.FirstNotProcessedFile);
+
+  std::ofstream OF(CFPath, std::ofstream::out | std::ofstream::app);
+  Set<size_t> AllFeatures;
+  auto PrintStatsWrapper = [this, &AllFeatures](const char* Where) {
+    this->PrintStats(Where, "\n", 0, AllFeatures.size());
+  };
+  Set<const TracePC::PCTableEntry *> AllPCs;
+  for (size_t i = M.FirstNotProcessedFile; i < M.Files.size(); i++) {
+    Fuzzer::MaybeExitGracefully();
+    auto U = FileToVector(M.Files[i].Name);
+    if (U.size() > MaxInputLen) {
+      U.resize(MaxInputLen);
+      U.shrink_to_fit();
+    }
+
+    // Write the pre-run marker.
+    OF << "STARTED " << i << " " << U.size() << "\n";
+    OF.flush();  // Flush is important since Command::Execute may crash.
+    // Run.
+    TPC.ResetMaps();
+    ExecuteCallback(U.data(), U.size());
+    // Collect coverage. We are iterating over the files in this order:
+    // * First, files in the initial corpus ordered by size, smallest first.
+    // * Then, all other files, smallest first.
+    // So it makes no sense to record all features for all files, instead we
+    // only record features that were not seen before.
+    Set<size_t> UniqFeatures;
+    TPC.CollectFeatures([&](size_t Feature) {
+      if (AllFeatures.insert(Feature).second)
+        UniqFeatures.insert(Feature);
+    });
+    TPC.UpdateObservedPCs();
+    // Show stats.
+    if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)))
+      PrintStatsWrapper("pulse ");
+    if (TotalNumberOfRuns == M.NumFilesInFirstCorpus)
+      PrintStatsWrapper("LOADED");
+    // Write the post-run marker and the coverage.
+    OF << "FT " << i;
+    for (size_t F : UniqFeatures)
+      OF << " " << F;
+    OF << "\n";
+    OF << "COV " << i;
+    TPC.ForEachObservedPC([&](const TracePC::PCTableEntry *TE) {
+      if (AllPCs.insert(TE).second)
+        OF << " " << TPC.PCTableEntryIdx(TE);
+    });
+    OF << "\n";
+    OF.flush();
+  }
+  PrintStatsWrapper("DONE  ");
+}
+
+static size_t WriteNewControlFile(const std::string &CFPath,
+                                  const Vector<SizedFile> &OldCorpus,
+                                  const Vector<SizedFile> &NewCorpus,
+                                  const Vector<MergeFileInfo> &KnownFiles) {
+  std::unordered_set<std::string> FilesToSkip;
+  for (auto &SF: KnownFiles)
+    FilesToSkip.insert(SF.Name);
+
+  Vector<std::string> FilesToUse;
+  auto MaybeUseFile = [=, &FilesToUse](std::string Name) {
+    if (FilesToSkip.find(Name) == FilesToSkip.end())
+      FilesToUse.push_back(Name);
+  };
+  for (auto &SF: OldCorpus)
+    MaybeUseFile(SF.File);
+  auto FilesToUseFromOldCorpus = FilesToUse.size();
+  for (auto &SF: NewCorpus)
+    MaybeUseFile(SF.File);
+
+  RemoveFile(CFPath);
+  std::ofstream ControlFile(CFPath);
+  ControlFile << FilesToUse.size() << "\n";
+  ControlFile << FilesToUseFromOldCorpus << "\n";
+  for (auto &FN: FilesToUse)
+    ControlFile << FN << "\n";
+
+  if (!ControlFile) {
+    Printf("MERGE-OUTER: failed to write to the control file: %s\n",
+           CFPath.c_str());
+    exit(1);
+  }
+
+  return FilesToUse.size();
+}
+
+// Outer process. Does not call the target code and thus should not fail.
+void CrashResistantMerge(const Vector<std::string> &Args,
+                         const Vector<SizedFile> &OldCorpus,
+                         const Vector<SizedFile> &NewCorpus,
+                         Vector<std::string> *NewFiles,
+                         const Set<uint32_t> &InitialFeatures,
+                         Set<uint32_t> *NewFeatures,
+                         const Set<uint32_t> &InitialCov,
+                         Set<uint32_t> *NewCov,
+                         const std::string &CFPath,
+                         bool V /*Verbose*/) {
+  if (NewCorpus.empty() && OldCorpus.empty()) return;  // Nothing to merge.
+  size_t NumAttempts = 0;
+  Vector<MergeFileInfo> KnownFiles;
+  if (FileSize(CFPath)) {
+    VPrintf(V, "MERGE-OUTER: non-empty control file provided: '%s'\n",
+           CFPath.c_str());
+    Merger M;
+    std::ifstream IF(CFPath);
+    if (M.Parse(IF, /*ParseCoverage=*/true)) {
+      VPrintf(V, "MERGE-OUTER: control file ok, %zd files total,"
+             " first not processed file %zd\n",
+             M.Files.size(), M.FirstNotProcessedFile);
+      if (!M.LastFailure.empty())
+        VPrintf(V, "MERGE-OUTER: '%s' will be skipped as unlucky "
+               "(merge has stumbled on it the last time)\n",
+               M.LastFailure.c_str());
+      if (M.FirstNotProcessedFile >= M.Files.size()) {
+        // Merge has already been completed with the given merge control file.
+        if (M.Files.size() == OldCorpus.size() + NewCorpus.size()) {
+          VPrintf(
+              V,
+              "MERGE-OUTER: nothing to do, merge has been completed before\n");
+          exit(0);
+        }
+
+        // Number of input files likely changed, start merge from scratch, but
+        // reuse coverage information from the given merge control file.
+        VPrintf(
+            V,
+            "MERGE-OUTER: starting merge from scratch, but reusing coverage "
+            "information from the given control file\n");
+        KnownFiles = M.Files;
+      } else {
+        // There is a merge in progress, continue.
+        NumAttempts = M.Files.size() - M.FirstNotProcessedFile;
+      }
+    } else {
+      VPrintf(V, "MERGE-OUTER: bad control file, will overwrite it\n");
+    }
+  }
+
+  if (!NumAttempts) {
+    // The supplied control file is empty or bad, create a fresh one.
+    VPrintf(V, "MERGE-OUTER: "
+            "%zd files, %zd in the initial corpus, %zd processed earlier\n",
+            OldCorpus.size() + NewCorpus.size(), OldCorpus.size(),
+            KnownFiles.size());
+    NumAttempts = WriteNewControlFile(CFPath, OldCorpus, NewCorpus, KnownFiles);
+  }
+
+  // Execute the inner process until it passes.
+  // Every inner process should execute at least one input.
+  Command BaseCmd(Args);
+  BaseCmd.removeFlag("merge");
+  BaseCmd.removeFlag("fork");
+  BaseCmd.removeFlag("collect_data_flow");
+  for (size_t Attempt = 1; Attempt <= NumAttempts; Attempt++) {
+    Fuzzer::MaybeExitGracefully();
+    VPrintf(V, "MERGE-OUTER: attempt %zd\n", Attempt);
+    Command Cmd(BaseCmd);
+    Cmd.addFlag("merge_control_file", CFPath);
+    Cmd.addFlag("merge_inner", "1");
+    if (!V) {
+      Cmd.setOutputFile(getDevNull());
+      Cmd.combineOutAndErr();
+    }
+    auto ExitCode = ExecuteCommand(Cmd);
+    if (!ExitCode) {
+      VPrintf(V, "MERGE-OUTER: succesfull in %zd attempt(s)\n", Attempt);
+      break;
+    }
+  }
+  // Read the control file and do the merge.
+  Merger M;
+  std::ifstream IF(CFPath);
+  IF.seekg(0, IF.end);
+  VPrintf(V, "MERGE-OUTER: the control file has %zd bytes\n",
+          (size_t)IF.tellg());
+  IF.seekg(0, IF.beg);
+  M.ParseOrExit(IF, true);
+  IF.close();
+  VPrintf(V,
+          "MERGE-OUTER: consumed %zdMb (%zdMb rss) to parse the control file\n",
+          M.ApproximateMemoryConsumption() >> 20, GetPeakRSSMb());
+
+  M.Files.insert(M.Files.end(), KnownFiles.begin(), KnownFiles.end());
+  M.Merge(InitialFeatures, NewFeatures, InitialCov, NewCov, NewFiles);
+  VPrintf(V, "MERGE-OUTER: %zd new files with %zd new features added; "
+          "%zd new coverage edges\n",
+         NewFiles->size(), NewFeatures->size(), NewCov->size());
+}
+
+} // namespace fuzzer
diff --git a/libfuzzer/FuzzerMerge.h b/libfuzzer/FuzzerMerge.h
new file mode 100644
index 0000000..e0c6bc5
--- /dev/null
+++ b/libfuzzer/FuzzerMerge.h
@@ -0,0 +1,87 @@
+//===- FuzzerMerge.h - merging corpa ----------------------------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Merging Corpora.
+//
+// The task:
+//   Take the existing corpus (possibly empty) and merge new inputs into
+//   it so that only inputs with new coverage ('features') are added.
+//   The process should tolerate the crashes, OOMs, leaks, etc.
+//
+// Algorithm:
+//   The outer process collects the set of files and writes their names
+//   into a temporary "control" file, then repeatedly launches the inner
+//   process until all inputs are processed.
+//   The outer process does not actually execute the target code.
+//
+//   The inner process reads the control file and sees a) list of all the inputs
+//   and b) the last processed input. Then it starts processing the inputs one
+//   by one. Before processing every input it writes one line to control file:
+//   STARTED INPUT_ID INPUT_SIZE
+//   After processing an input it writes the following lines:
+//   FT INPUT_ID Feature1 Feature2 Feature3 ...
+//   COV INPUT_ID Coverage1 Coverage2 Coverage3 ...
+//   If a crash happens while processing an input the last line in the control
+//   file will be "STARTED INPUT_ID" and so the next process will know
+//   where to resume.
+//
+//   Once all inputs are processed by the inner process(es) the outer process
+//   reads the control files and does the merge based entirely on the contents
+//   of control file.
+//   It uses a single pass greedy algorithm choosing first the smallest inputs
+//   within the same size the inputs that have more new features.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_MERGE_H
+#define LLVM_FUZZER_MERGE_H
+
+#include "FuzzerDefs.h"
+
+#include <istream>
+#include <ostream>
+#include <set>
+#include <vector>
+
+namespace fuzzer {
+
+struct MergeFileInfo {
+  std::string Name;
+  size_t Size = 0;
+  Vector<uint32_t> Features, Cov;
+};
+
+struct Merger {
+  Vector<MergeFileInfo> Files;
+  size_t NumFilesInFirstCorpus = 0;
+  size_t FirstNotProcessedFile = 0;
+  std::string LastFailure;
+
+  bool Parse(std::istream &IS, bool ParseCoverage);
+  bool Parse(const std::string &Str, bool ParseCoverage);
+  void ParseOrExit(std::istream &IS, bool ParseCoverage);
+  size_t Merge(const Set<uint32_t> &InitialFeatures, Set<uint32_t> *NewFeatures,
+               const Set<uint32_t> &InitialCov, Set<uint32_t> *NewCov,
+               Vector<std::string> *NewFiles);
+  size_t ApproximateMemoryConsumption() const;
+  Set<uint32_t> AllFeatures() const;
+};
+
+void CrashResistantMerge(const Vector<std::string> &Args,
+                         const Vector<SizedFile> &OldCorpus,
+                         const Vector<SizedFile> &NewCorpus,
+                         Vector<std::string> *NewFiles,
+                         const Set<uint32_t> &InitialFeatures,
+                         Set<uint32_t> *NewFeatures,
+                         const Set<uint32_t> &InitialCov,
+                         Set<uint32_t> *NewCov,
+                         const std::string &CFPath,
+                         bool Verbose);
+
+}  // namespace fuzzer
+
+#endif  // LLVM_FUZZER_MERGE_H
diff --git a/libfuzzer/FuzzerMutate.cpp b/libfuzzer/FuzzerMutate.cpp
new file mode 100644
index 0000000..29541ea
--- /dev/null
+++ b/libfuzzer/FuzzerMutate.cpp
@@ -0,0 +1,562 @@
+//===- FuzzerMutate.cpp - Mutate a test input -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Mutate a test input.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerDefs.h"
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+#include "FuzzerMutate.h"
+#include "FuzzerOptions.h"
+#include "FuzzerTracePC.h"
+
+namespace fuzzer {
+
+const size_t Dictionary::kMaxDictSize;
+
+static void PrintASCII(const Word &W, const char *PrintAfter) {
+  PrintASCII(W.data(), W.size(), PrintAfter);
+}
+
+MutationDispatcher::MutationDispatcher(Random &Rand,
+                                       const FuzzingOptions &Options)
+    : Rand(Rand), Options(Options) {
+  DefaultMutators.insert(
+      DefaultMutators.begin(),
+      {
+          {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"},
+          {&MutationDispatcher::Mutate_InsertByte, "InsertByte"},
+          {&MutationDispatcher::Mutate_InsertRepeatedBytes,
+           "InsertRepeatedBytes"},
+          {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"},
+          {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"},
+          {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"},
+          {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"},
+          {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"},
+          {&MutationDispatcher::Mutate_CopyPart, "CopyPart"},
+          {&MutationDispatcher::Mutate_CrossOver, "CrossOver"},
+          {&MutationDispatcher::Mutate_AddWordFromManualDictionary,
+           "ManualDict"},
+          {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
+           "PersAutoDict"},
+      });
+  if(Options.UseCmp)
+    DefaultMutators.push_back(
+        {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"});
+
+  if (EF->LLVMFuzzerCustomMutator)
+    Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
+  else
+    Mutators = DefaultMutators;
+
+  if (EF->LLVMFuzzerCustomCrossOver)
+    Mutators.push_back(
+        {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"});
+}
+
+static char RandCh(Random &Rand) {
+  if (Rand.RandBool()) return Rand(256);
+  const char Special[] = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00";
+  return Special[Rand(sizeof(Special) - 1)];
+}
+
+size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size,
+                                         size_t MaxSize) {
+  return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand());
+}
+
+size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size,
+                                                  size_t MaxSize) {
+  if (Size == 0)
+    return 0;
+  if (!CrossOverWith) return 0;
+  const Unit &Other = *CrossOverWith;
+  if (Other.empty())
+    return 0;
+  CustomCrossOverInPlaceHere.resize(MaxSize);
+  auto &U = CustomCrossOverInPlaceHere;
+  size_t NewSize = EF->LLVMFuzzerCustomCrossOver(
+      Data, Size, Other.data(), Other.size(), U.data(), U.size(), Rand.Rand());
+  if (!NewSize)
+    return 0;
+  assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit");
+  memcpy(Data, U.data(), NewSize);
+  return NewSize;
+}
+
+size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
+                                               size_t MaxSize) {
+  if (Size > MaxSize || Size == 0) return 0;
+  size_t ShuffleAmount =
+      Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size.
+  size_t ShuffleStart = Rand(Size - ShuffleAmount);
+  assert(ShuffleStart + ShuffleAmount <= Size);
+  std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand);
+  return Size;
+}
+
+size_t MutationDispatcher::Mutate_EraseBytes(uint8_t *Data, size_t Size,
+                                             size_t MaxSize) {
+  if (Size <= 1) return 0;
+  size_t N = Rand(Size / 2) + 1;
+  assert(N < Size);
+  size_t Idx = Rand(Size - N + 1);
+  // Erase Data[Idx:Idx+N].
+  memmove(Data + Idx, Data + Idx + N, Size - Idx - N);
+  // Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx);
+  return Size - N;
+}
+
+size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size,
+                                             size_t MaxSize) {
+  if (Size >= MaxSize) return 0;
+  size_t Idx = Rand(Size + 1);
+  // Insert new value at Data[Idx].
+  memmove(Data + Idx + 1, Data + Idx, Size - Idx);
+  Data[Idx] = RandCh(Rand);
+  return Size + 1;
+}
+
+size_t MutationDispatcher::Mutate_InsertRepeatedBytes(uint8_t *Data,
+                                                      size_t Size,
+                                                      size_t MaxSize) {
+  const size_t kMinBytesToInsert = 3;
+  if (Size + kMinBytesToInsert >= MaxSize) return 0;
+  size_t MaxBytesToInsert = std::min(MaxSize - Size, (size_t)128);
+  size_t N = Rand(MaxBytesToInsert - kMinBytesToInsert + 1) + kMinBytesToInsert;
+  assert(Size + N <= MaxSize && N);
+  size_t Idx = Rand(Size + 1);
+  // Insert new values at Data[Idx].
+  memmove(Data + Idx + N, Data + Idx, Size - Idx);
+  // Give preference to 0x00 and 0xff.
+  uint8_t Byte = Rand.RandBool() ? Rand(256) : (Rand.RandBool() ? 0 : 255);
+  for (size_t i = 0; i < N; i++)
+    Data[Idx + i] = Byte;
+  return Size + N;
+}
+
+size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size,
+                                             size_t MaxSize) {
+  if (Size > MaxSize) return 0;
+  size_t Idx = Rand(Size);
+  Data[Idx] = RandCh(Rand);
+  return Size;
+}
+
+size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size,
+                                            size_t MaxSize) {
+  if (Size > MaxSize) return 0;
+  size_t Idx = Rand(Size);
+  Data[Idx] ^= 1 << Rand(8);
+  return Size;
+}
+
+size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data,
+                                                              size_t Size,
+                                                              size_t MaxSize) {
+  return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize);
+}
+
+size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size,
+                                                size_t MaxSize,
+                                                DictionaryEntry &DE) {
+  const Word &W = DE.GetW();
+  bool UsePositionHint = DE.HasPositionHint() &&
+                         DE.GetPositionHint() + W.size() < Size &&
+                         Rand.RandBool();
+  if (Rand.RandBool()) {  // Insert W.
+    if (Size + W.size() > MaxSize) return 0;
+    size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1);
+    memmove(Data + Idx + W.size(), Data + Idx, Size - Idx);
+    memcpy(Data + Idx, W.data(), W.size());
+    Size += W.size();
+  } else {  // Overwrite some bytes with W.
+    if (W.size() > Size) return 0;
+    size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size - W.size());
+    memcpy(Data + Idx, W.data(), W.size());
+  }
+  return Size;
+}
+
+// Somewhere in the past we have observed a comparison instructions
+// with arguments Arg1 Arg2. This function tries to guess a dictionary
+// entry that will satisfy that comparison.
+// It first tries to find one of the arguments (possibly swapped) in the
+// input and if it succeeds it creates a DE with a position hint.
+// Otherwise it creates a DE with one of the arguments w/o a position hint.
+DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
+    const void *Arg1, const void *Arg2,
+    const void *Arg1Mutation, const void *Arg2Mutation,
+    size_t ArgSize, const uint8_t *Data,
+    size_t Size) {
+  bool HandleFirst = Rand.RandBool();
+  const void *ExistingBytes, *DesiredBytes;
+  Word W;
+  const uint8_t *End = Data + Size;
+  for (int Arg = 0; Arg < 2; Arg++) {
+    ExistingBytes = HandleFirst ? Arg1 : Arg2;
+    DesiredBytes = HandleFirst ? Arg2Mutation : Arg1Mutation;
+    HandleFirst = !HandleFirst;
+    W.Set(reinterpret_cast<const uint8_t*>(DesiredBytes), ArgSize);
+    const size_t kMaxNumPositions = 8;
+    size_t Positions[kMaxNumPositions];
+    size_t NumPositions = 0;
+    for (const uint8_t *Cur = Data;
+         Cur < End && NumPositions < kMaxNumPositions; Cur++) {
+      Cur =
+          (const uint8_t *)SearchMemory(Cur, End - Cur, ExistingBytes, ArgSize);
+      if (!Cur) break;
+      Positions[NumPositions++] = Cur - Data;
+    }
+    if (!NumPositions) continue;
+    return DictionaryEntry(W, Positions[Rand(NumPositions)]);
+  }
+  DictionaryEntry DE(W);
+  return DE;
+}
+
+
+template <class T>
+DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
+    T Arg1, T Arg2, const uint8_t *Data, size_t Size) {
+  if (Rand.RandBool()) Arg1 = Bswap(Arg1);
+  if (Rand.RandBool()) Arg2 = Bswap(Arg2);
+  T Arg1Mutation = Arg1 + Rand(-1, 1);
+  T Arg2Mutation = Arg2 + Rand(-1, 1);
+  return MakeDictionaryEntryFromCMP(&Arg1, &Arg2, &Arg1Mutation, &Arg2Mutation,
+                                    sizeof(Arg1), Data, Size);
+}
+
+DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
+    const Word &Arg1, const Word &Arg2, const uint8_t *Data, size_t Size) {
+  return MakeDictionaryEntryFromCMP(Arg1.data(), Arg2.data(), Arg1.data(),
+                                    Arg2.data(), Arg1.size(), Data, Size);
+}
+
+size_t MutationDispatcher::Mutate_AddWordFromTORC(
+    uint8_t *Data, size_t Size, size_t MaxSize) {
+  Word W;
+  DictionaryEntry DE;
+  switch (Rand(4)) {
+  case 0: {
+    auto X = TPC.TORC8.Get(Rand.Rand());
+    DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
+  } break;
+  case 1: {
+    auto X = TPC.TORC4.Get(Rand.Rand());
+    if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool())
+      DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data, Size);
+    else
+      DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
+  } break;
+  case 2: {
+    auto X = TPC.TORCW.Get(Rand.Rand());
+    DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
+  } break;
+  case 3: if (Options.UseMemmem) {
+    auto X = TPC.MMT.Get(Rand.Rand());
+    DE = DictionaryEntry(X);
+  } break;
+  default:
+    assert(0);
+  }
+  if (!DE.GetW().size()) return 0;
+  Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
+  if (!Size) return 0;
+  DictionaryEntry &DERef =
+      CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ %
+                                kCmpDictionaryEntriesDequeSize];
+  DERef = DE;
+  CurrentDictionaryEntrySequence.push_back(&DERef);
+  return Size;
+}
+
+size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary(
+    uint8_t *Data, size_t Size, size_t MaxSize) {
+  return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize);
+}
+
+size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data,
+                                                 size_t Size, size_t MaxSize) {
+  if (Size > MaxSize) return 0;
+  if (D.empty()) return 0;
+  DictionaryEntry &DE = D[Rand(D.size())];
+  Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
+  if (!Size) return 0;
+  DE.IncUseCount();
+  CurrentDictionaryEntrySequence.push_back(&DE);
+  return Size;
+}
+
+// Overwrites part of To[0,ToSize) with a part of From[0,FromSize).
+// Returns ToSize.
+size_t MutationDispatcher::CopyPartOf(const uint8_t *From, size_t FromSize,
+                                      uint8_t *To, size_t ToSize) {
+  // Copy From[FromBeg, FromBeg + CopySize) into To[ToBeg, ToBeg + CopySize).
+  size_t ToBeg = Rand(ToSize);
+  size_t CopySize = Rand(ToSize - ToBeg) + 1;
+  assert(ToBeg + CopySize <= ToSize);
+  CopySize = std::min(CopySize, FromSize);
+  size_t FromBeg = Rand(FromSize - CopySize + 1);
+  assert(FromBeg + CopySize <= FromSize);
+  memmove(To + ToBeg, From + FromBeg, CopySize);
+  return ToSize;
+}
+
+// Inserts part of From[0,ToSize) into To.
+// Returns new size of To on success or 0 on failure.
+size_t MutationDispatcher::InsertPartOf(const uint8_t *From, size_t FromSize,
+                                        uint8_t *To, size_t ToSize,
+                                        size_t MaxToSize) {
+  if (ToSize >= MaxToSize) return 0;
+  size_t AvailableSpace = MaxToSize - ToSize;
+  size_t MaxCopySize = std::min(AvailableSpace, FromSize);
+  size_t CopySize = Rand(MaxCopySize) + 1;
+  size_t FromBeg = Rand(FromSize - CopySize + 1);
+  assert(FromBeg + CopySize <= FromSize);
+  size_t ToInsertPos = Rand(ToSize + 1);
+  assert(ToInsertPos + CopySize <= MaxToSize);
+  size_t TailSize = ToSize - ToInsertPos;
+  if (To == From) {
+    MutateInPlaceHere.resize(MaxToSize);
+    memcpy(MutateInPlaceHere.data(), From + FromBeg, CopySize);
+    memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);
+    memmove(To + ToInsertPos, MutateInPlaceHere.data(), CopySize);
+  } else {
+    memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);
+    memmove(To + ToInsertPos, From + FromBeg, CopySize);
+  }
+  return ToSize + CopySize;
+}
+
+size_t MutationDispatcher::Mutate_CopyPart(uint8_t *Data, size_t Size,
+                                           size_t MaxSize) {
+  if (Size > MaxSize || Size == 0) return 0;
+  // If Size == MaxSize, `InsertPartOf(...)` will
+  // fail so there's no point using it in this case.
+  if (Size == MaxSize || Rand.RandBool())
+    return CopyPartOf(Data, Size, Data, Size);
+  else
+    return InsertPartOf(Data, Size, Data, Size, MaxSize);
+}
+
+size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,
+                                                     size_t MaxSize) {
+  if (Size > MaxSize) return 0;
+  size_t B = Rand(Size);
+  while (B < Size && !isdigit(Data[B])) B++;
+  if (B == Size) return 0;
+  size_t E = B;
+  while (E < Size && isdigit(Data[E])) E++;
+  assert(B < E);
+  // now we have digits in [B, E).
+  // strtol and friends don't accept non-zero-teminated data, parse it manually.
+  uint64_t Val = Data[B] - '0';
+  for (size_t i = B + 1; i < E; i++)
+    Val = Val * 10 + Data[i] - '0';
+
+  // Mutate the integer value.
+  switch(Rand(5)) {
+    case 0: Val++; break;
+    case 1: Val--; break;
+    case 2: Val /= 2; break;
+    case 3: Val *= 2; break;
+    case 4: Val = Rand(Val * Val); break;
+    default: assert(0);
+  }
+  // Just replace the bytes with the new ones, don't bother moving bytes.
+  for (size_t i = B; i < E; i++) {
+    size_t Idx = E + B - i - 1;
+    assert(Idx >= B && Idx < E);
+    Data[Idx] = (Val % 10) + '0';
+    Val /= 10;
+  }
+  return Size;
+}
+
+template<class T>
+size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) {
+  if (Size < sizeof(T)) return 0;
+  size_t Off = Rand(Size - sizeof(T) + 1);
+  assert(Off + sizeof(T) <= Size);
+  T Val;
+  if (Off < 64 && !Rand(4)) {
+    Val = Size;
+    if (Rand.RandBool())
+      Val = Bswap(Val);
+  } else {
+    memcpy(&Val, Data + Off, sizeof(Val));
+    T Add = Rand(21);
+    Add -= 10;
+    if (Rand.RandBool())
+      Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes.
+    else
+      Val = Val + Add;               // Add assuming current endiannes.
+    if (Add == 0 || Rand.RandBool()) // Maybe negate.
+      Val = -Val;
+  }
+  memcpy(Data + Off, &Val, sizeof(Val));
+  return Size;
+}
+
+size_t MutationDispatcher::Mutate_ChangeBinaryInteger(uint8_t *Data,
+                                                      size_t Size,
+                                                      size_t MaxSize) {
+  if (Size > MaxSize) return 0;
+  switch (Rand(4)) {
+    case 3: return ChangeBinaryInteger<uint64_t>(Data, Size, Rand);
+    case 2: return ChangeBinaryInteger<uint32_t>(Data, Size, Rand);
+    case 1: return ChangeBinaryInteger<uint16_t>(Data, Size, Rand);
+    case 0: return ChangeBinaryInteger<uint8_t>(Data, Size, Rand);
+    default: assert(0);
+  }
+  return 0;
+}
+
+size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size,
+                                            size_t MaxSize) {
+  if (Size > MaxSize) return 0;
+  if (Size == 0) return 0;
+  if (!CrossOverWith) return 0;
+  const Unit &O = *CrossOverWith;
+  if (O.empty()) return 0;
+  MutateInPlaceHere.resize(MaxSize);
+  auto &U = MutateInPlaceHere;
+  size_t NewSize = 0;
+  switch(Rand(3)) {
+    case 0:
+      NewSize = CrossOver(Data, Size, O.data(), O.size(), U.data(), U.size());
+      break;
+    case 1:
+      NewSize = InsertPartOf(O.data(), O.size(), U.data(), U.size(), MaxSize);
+      if (!NewSize)
+        NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size());
+      break;
+    case 2:
+      NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size());
+      break;
+    default: assert(0);
+  }
+  assert(NewSize > 0 && "CrossOver returned empty unit");
+  assert(NewSize <= MaxSize && "CrossOver returned overisized unit");
+  memcpy(Data, U.data(), NewSize);
+  return NewSize;
+}
+
+void MutationDispatcher::StartMutationSequence() {
+  CurrentMutatorSequence.clear();
+  CurrentDictionaryEntrySequence.clear();
+}
+
+// Copy successful dictionary entries to PersistentAutoDictionary.
+void MutationDispatcher::RecordSuccessfulMutationSequence() {
+  for (auto DE : CurrentDictionaryEntrySequence) {
+    // PersistentAutoDictionary.AddWithSuccessCountOne(DE);
+    DE->IncSuccessCount();
+    assert(DE->GetW().size());
+    // Linear search is fine here as this happens seldom.
+    if (!PersistentAutoDictionary.ContainsWord(DE->GetW()))
+      PersistentAutoDictionary.push_back({DE->GetW(), 1});
+  }
+}
+
+void MutationDispatcher::PrintRecommendedDictionary() {
+  Vector<DictionaryEntry> V;
+  for (auto &DE : PersistentAutoDictionary)
+    if (!ManualDictionary.ContainsWord(DE.GetW()))
+      V.push_back(DE);
+  if (V.empty()) return;
+  Printf("###### Recommended dictionary. ######\n");
+  for (auto &DE: V) {
+    assert(DE.GetW().size());
+    Printf("\"");
+    PrintASCII(DE.GetW(), "\"");
+    Printf(" # Uses: %zd\n", DE.GetUseCount());
+  }
+  Printf("###### End of recommended dictionary. ######\n");
+}
+
+void MutationDispatcher::PrintMutationSequence() {
+  Printf("MS: %zd ", CurrentMutatorSequence.size());
+  for (auto M : CurrentMutatorSequence)
+    Printf("%s-", M.Name);
+  if (!CurrentDictionaryEntrySequence.empty()) {
+    Printf(" DE: ");
+    for (auto DE : CurrentDictionaryEntrySequence) {
+      Printf("\"");
+      PrintASCII(DE->GetW(), "\"-");
+    }
+  }
+}
+
+size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+  return MutateImpl(Data, Size, MaxSize, Mutators);
+}
+
+size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size,
+                                         size_t MaxSize) {
+  return MutateImpl(Data, Size, MaxSize, DefaultMutators);
+}
+
+// Mutates Data in place, returns new size.
+size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,
+                                      size_t MaxSize,
+                                      Vector<Mutator> &Mutators) {
+  assert(MaxSize > 0);
+  // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize),
+  // in which case they will return 0.
+  // Try several times before returning un-mutated data.
+  for (int Iter = 0; Iter < 100; Iter++) {
+    auto M = Mutators[Rand(Mutators.size())];
+    size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);
+    if (NewSize && NewSize <= MaxSize) {
+      if (Options.OnlyASCII)
+        ToASCII(Data, NewSize);
+      CurrentMutatorSequence.push_back(M);
+      return NewSize;
+    }
+  }
+  *Data = ' ';
+  return 1;   // Fallback, should not happen frequently.
+}
+
+// Mask represents the set of Data bytes that are worth mutating.
+size_t MutationDispatcher::MutateWithMask(uint8_t *Data, size_t Size,
+                                          size_t MaxSize,
+                                          const Vector<uint8_t> &Mask) {
+  size_t MaskedSize = std::min(Size, Mask.size());
+  // * Copy the worthy bytes into a temporary array T
+  // * Mutate T
+  // * Copy T back.
+  // This is totally unoptimized.
+  auto &T = MutateWithMaskTemp;
+  if (T.size() < Size)
+    T.resize(Size);
+  size_t OneBits = 0;
+  for (size_t I = 0; I < MaskedSize; I++)
+    if (Mask[I])
+      T[OneBits++] = Data[I];
+
+  if (!OneBits) return 0;
+  assert(!T.empty());
+  size_t NewSize = Mutate(T.data(), OneBits, OneBits);
+  assert(NewSize <= OneBits);
+  (void)NewSize;
+  // Even if NewSize < OneBits we still use all OneBits bytes.
+  for (size_t I = 0, J = 0; I < MaskedSize; I++)
+    if (Mask[I])
+      Data[I] = T[J++];
+  return Size;
+}
+
+void MutationDispatcher::AddWordToManualDictionary(const Word &W) {
+  ManualDictionary.push_back(
+      {W, std::numeric_limits<size_t>::max()});
+}
+
+}  // namespace fuzzer
diff --git a/libfuzzer/FuzzerMutate.h b/libfuzzer/FuzzerMutate.h
new file mode 100644
index 0000000..6cbce80
--- /dev/null
+++ b/libfuzzer/FuzzerMutate.h
@@ -0,0 +1,156 @@
+//===- FuzzerMutate.h - Internal header for the Fuzzer ----------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// fuzzer::MutationDispatcher
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_MUTATE_H
+#define LLVM_FUZZER_MUTATE_H
+
+#include "FuzzerDefs.h"
+#include "FuzzerDictionary.h"
+#include "FuzzerOptions.h"
+#include "FuzzerRandom.h"
+
+namespace fuzzer {
+
+class MutationDispatcher {
+public:
+  MutationDispatcher(Random &Rand, const FuzzingOptions &Options);
+  ~MutationDispatcher() {}
+  /// Indicate that we are about to start a new sequence of mutations.
+  void StartMutationSequence();
+  /// Print the current sequence of mutations.
+  void PrintMutationSequence();
+  /// Indicate that the current sequence of mutations was successful.
+  void RecordSuccessfulMutationSequence();
+  /// Mutates data by invoking user-provided mutator.
+  size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize);
+  /// Mutates data by invoking user-provided crossover.
+  size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize);
+  /// Mutates data by shuffling bytes.
+  size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize);
+  /// Mutates data by erasing bytes.
+  size_t Mutate_EraseBytes(uint8_t *Data, size_t Size, size_t MaxSize);
+  /// Mutates data by inserting a byte.
+  size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize);
+  /// Mutates data by inserting several repeated bytes.
+  size_t Mutate_InsertRepeatedBytes(uint8_t *Data, size_t Size, size_t MaxSize);
+  /// Mutates data by chanding one byte.
+  size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize);
+  /// Mutates data by chanding one bit.
+  size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize);
+  /// Mutates data by copying/inserting a part of data into a different place.
+  size_t Mutate_CopyPart(uint8_t *Data, size_t Size, size_t MaxSize);
+
+  /// Mutates data by adding a word from the manual dictionary.
+  size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size,
+                                            size_t MaxSize);
+
+  /// Mutates data by adding a word from the TORC.
+  size_t Mutate_AddWordFromTORC(uint8_t *Data, size_t Size, size_t MaxSize);
+
+  /// Mutates data by adding a word from the persistent automatic dictionary.
+  size_t Mutate_AddWordFromPersistentAutoDictionary(uint8_t *Data, size_t Size,
+                                                    size_t MaxSize);
+
+  /// Tries to find an ASCII integer in Data, changes it to another ASCII int.
+  size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize);
+  /// Change a 1-, 2-, 4-, or 8-byte integer in interesting ways.
+  size_t Mutate_ChangeBinaryInteger(uint8_t *Data, size_t Size, size_t MaxSize);
+
+  /// CrossOver Data with CrossOverWith.
+  size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize);
+
+  /// Applies one of the configured mutations.
+  /// Returns the new size of data which could be up to MaxSize.
+  size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize);
+
+  /// Applies one of the configured mutations to the bytes of Data
+  /// that have '1' in Mask.
+  /// Mask.size() should be >= Size.
+  size_t MutateWithMask(uint8_t *Data, size_t Size, size_t MaxSize,
+                        const Vector<uint8_t> &Mask);
+
+  /// Applies one of the default mutations. Provided as a service
+  /// to mutation authors.
+  size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize);
+
+  /// Creates a cross-over of two pieces of Data, returns its size.
+  size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2,
+                   size_t Size2, uint8_t *Out, size_t MaxOutSize);
+
+  void AddWordToManualDictionary(const Word &W);
+
+  void PrintRecommendedDictionary();
+
+  void SetCrossOverWith(const Unit *U) { CrossOverWith = U; }
+
+  Random &GetRand() { return Rand; }
+
+ private:
+  struct Mutator {
+    size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max);
+    const char *Name;
+  };
+
+  size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size,
+                               size_t MaxSize);
+  size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize,
+                    Vector<Mutator> &Mutators);
+
+  size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
+                      size_t ToSize, size_t MaxToSize);
+  size_t CopyPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
+                    size_t ToSize);
+  size_t ApplyDictionaryEntry(uint8_t *Data, size_t Size, size_t MaxSize,
+                              DictionaryEntry &DE);
+
+  template <class T>
+  DictionaryEntry MakeDictionaryEntryFromCMP(T Arg1, T Arg2,
+                                             const uint8_t *Data, size_t Size);
+  DictionaryEntry MakeDictionaryEntryFromCMP(const Word &Arg1, const Word &Arg2,
+                                             const uint8_t *Data, size_t Size);
+  DictionaryEntry MakeDictionaryEntryFromCMP(const void *Arg1, const void *Arg2,
+                                             const void *Arg1Mutation,
+                                             const void *Arg2Mutation,
+                                             size_t ArgSize,
+                                             const uint8_t *Data, size_t Size);
+
+  Random &Rand;
+  const FuzzingOptions Options;
+
+  // Dictionary provided by the user via -dict=DICT_FILE.
+  Dictionary ManualDictionary;
+  // Temporary dictionary modified by the fuzzer itself,
+  // recreated periodically.
+  Dictionary TempAutoDictionary;
+  // Persistent dictionary modified by the fuzzer, consists of
+  // entries that led to successful discoveries in the past mutations.
+  Dictionary PersistentAutoDictionary;
+
+  Vector<DictionaryEntry *> CurrentDictionaryEntrySequence;
+
+  static const size_t kCmpDictionaryEntriesDequeSize = 16;
+  DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize];
+  size_t CmpDictionaryEntriesDequeIdx = 0;
+
+  const Unit *CrossOverWith = nullptr;
+  Vector<uint8_t> MutateInPlaceHere;
+  Vector<uint8_t> MutateWithMaskTemp;
+  // CustomCrossOver needs its own buffer as a custom implementation may call
+  // LLVMFuzzerMutate, which in turn may resize MutateInPlaceHere.
+  Vector<uint8_t> CustomCrossOverInPlaceHere;
+
+  Vector<Mutator> Mutators;
+  Vector<Mutator> DefaultMutators;
+  Vector<Mutator> CurrentMutatorSequence;
+};
+
+}  // namespace fuzzer
+
+#endif  // LLVM_FUZZER_MUTATE_H
diff --git a/libfuzzer/FuzzerOptions.h b/libfuzzer/FuzzerOptions.h
new file mode 100644
index 0000000..9d975bd
--- /dev/null
+++ b/libfuzzer/FuzzerOptions.h
@@ -0,0 +1,85 @@
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// fuzzer::FuzzingOptions
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_OPTIONS_H
+#define LLVM_FUZZER_OPTIONS_H
+
+#include "FuzzerDefs.h"
+
+namespace fuzzer {
+
+struct FuzzingOptions {
+  int Verbosity = 1;
+  size_t MaxLen = 0;
+  size_t LenControl = 1000;
+  int UnitTimeoutSec = 300;
+  int TimeoutExitCode = 70;
+  int OOMExitCode = 71;
+  int InterruptExitCode = 72;
+  int ErrorExitCode = 77;
+  bool IgnoreTimeouts = true;
+  bool IgnoreOOMs = true;
+  bool IgnoreCrashes = false;
+  int MaxTotalTimeSec = 0;
+  int RssLimitMb = 0;
+  int MallocLimitMb = 0;
+  bool DoCrossOver = true;
+  int MutateDepth = 5;
+  bool ReduceDepth = false;
+  bool UseCounters = false;
+  bool UseMemmem = true;
+  bool UseCmp = false;
+  int UseValueProfile = false;
+  bool Shrink = false;
+  bool ReduceInputs = false;
+  int ReloadIntervalSec = 1;
+  bool ShuffleAtStartUp = true;
+  bool PreferSmall = true;
+  size_t MaxNumberOfRuns = -1L;
+  int ReportSlowUnits = 10;
+  bool OnlyASCII = false;
+  bool Entropic = false;
+  size_t EntropicFeatureFrequencyThreshold = 0xFF;
+  size_t EntropicNumberOfRarestFeatures = 100;
+  std::string OutputCorpus;
+  std::string ArtifactPrefix = "./";
+  std::string ExactArtifactPath;
+  std::string ExitOnSrcPos;
+  std::string ExitOnItem;
+  std::string FocusFunction;
+  std::string DataFlowTrace;
+  std::string CollectDataFlow;
+  std::string FeaturesDir;
+  std::string StopFile;
+  bool SaveArtifacts = true;
+  bool PrintNEW = true; // Print a status line when new units are found;
+  bool PrintNewCovPcs = false;
+  int PrintNewCovFuncs = 0;
+  bool PrintFinalStats = false;
+  bool PrintCorpusStats = false;
+  bool PrintCoverage = false;
+  bool DumpCoverage = false;
+  bool DetectLeaks = true;
+  int PurgeAllocatorIntervalSec = 1;
+  int  TraceMalloc = 0;
+  bool HandleAbrt = false;
+  bool HandleBus = false;
+  bool HandleFpe = false;
+  bool HandleIll = false;
+  bool HandleInt = false;
+  bool HandleSegv = false;
+  bool HandleTerm = false;
+  bool HandleXfsz = false;
+  bool HandleUsr1 = false;
+  bool HandleUsr2 = false;
+};
+
+}  // namespace fuzzer
+
+#endif  // LLVM_FUZZER_OPTIONS_H
diff --git a/libfuzzer/FuzzerPlatform.h b/libfuzzer/FuzzerPlatform.h
new file mode 100644
index 0000000..8befdb8
--- /dev/null
+++ b/libfuzzer/FuzzerPlatform.h
@@ -0,0 +1,163 @@
+//===-- FuzzerPlatform.h --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Common platform macros.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_PLATFORM_H
+#define LLVM_FUZZER_PLATFORM_H
+
+// Platform detection.
+#ifdef __linux__
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 0
+#define LIBFUZZER_LINUX 1
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 0
+#define LIBFUZZER_OPENBSD 0
+#define LIBFUZZER_WINDOWS 0
+#define LIBFUZZER_EMSCRIPTEN 0
+#elif __APPLE__
+#define LIBFUZZER_APPLE 1
+#define LIBFUZZER_FUCHSIA 0
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 0
+#define LIBFUZZER_OPENBSD 0
+#define LIBFUZZER_WINDOWS 0
+#define LIBFUZZER_EMSCRIPTEN 0
+#elif __NetBSD__
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 0
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 1
+#define LIBFUZZER_FREEBSD 0
+#define LIBFUZZER_OPENBSD 0
+#define LIBFUZZER_WINDOWS 0
+#define LIBFUZZER_EMSCRIPTEN 0
+#elif __FreeBSD__
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 0
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 1
+#define LIBFUZZER_OPENBSD 0
+#define LIBFUZZER_WINDOWS 0
+#define LIBFUZZER_EMSCRIPTEN 0
+#elif __OpenBSD__
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 0
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 0
+#define LIBFUZZER_OPENBSD 1
+#define LIBFUZZER_WINDOWS 0
+#define LIBFUZZER_EMSCRIPTEN 0
+#elif _WIN32
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 0
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 0
+#define LIBFUZZER_OPENBSD 0
+#define LIBFUZZER_WINDOWS 1
+#define LIBFUZZER_EMSCRIPTEN 0
+#elif __Fuchsia__
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 1
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 0
+#define LIBFUZZER_OPENBSD 0
+#define LIBFUZZER_WINDOWS 0
+#define LIBFUZZER_EMSCRIPTEN 0
+#elif __EMSCRIPTEN__
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_FUCHSIA 0
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 0
+#define LIBFUZZER_OPENBSD 0
+#define LIBFUZZER_WINDOWS 0
+#define LIBFUZZER_EMSCRIPTEN 1
+#else
+#error "Support for your platform has not been implemented"
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+// MSVC compiler is being used.
+#define LIBFUZZER_MSVC 1
+#else
+#define LIBFUZZER_MSVC 0
+#endif
+
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
+#define LIBFUZZER_POSIX                                                        \
+  (LIBFUZZER_APPLE || LIBFUZZER_LINUX || LIBFUZZER_NETBSD ||                   \
+   LIBFUZZER_FREEBSD || LIBFUZZER_OPENBSD || LIBFUZZER_EMSCRIPTEN)
+
+#ifdef __x86_64
+#if __has_attribute(target)
+#define ATTRIBUTE_TARGET_POPCNT __attribute__((target("popcnt")))
+#else
+#define ATTRIBUTE_TARGET_POPCNT
+#endif
+#else
+#define ATTRIBUTE_TARGET_POPCNT
+#endif
+
+#ifdef __clang__ // avoid gcc warning.
+#if __has_attribute(no_sanitize)
+#define ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory")))
+#else
+#define ATTRIBUTE_NO_SANITIZE_MEMORY
+#endif
+#define ALWAYS_INLINE __attribute__((always_inline))
+#else
+#define ATTRIBUTE_NO_SANITIZE_MEMORY
+#define ALWAYS_INLINE
+#endif // __clang__
+
+#if LIBFUZZER_WINDOWS
+#define ATTRIBUTE_NO_SANITIZE_ADDRESS
+#else
+#define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
+#endif
+
+#if LIBFUZZER_WINDOWS
+#define ATTRIBUTE_ALIGNED(X) __declspec(align(X))
+#define ATTRIBUTE_INTERFACE __declspec(dllexport)
+// This is used for __sancov_lowest_stack which is needed for
+// -fsanitize-coverage=stack-depth. That feature is not yet available on
+// Windows, so make the symbol static to avoid linking errors.
+#define ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC static
+#define ATTRIBUTE_NOINLINE __declspec(noinline)
+#else
+#define ATTRIBUTE_ALIGNED(X) __attribute__((aligned(X)))
+#define ATTRIBUTE_INTERFACE __attribute__((visibility("default")))
+#define ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC                                  \
+  ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec"))) thread_local
+
+#define ATTRIBUTE_NOINLINE __attribute__((noinline))
+#endif
+
+#if defined(__has_feature)
+#if __has_feature(address_sanitizer)
+#define ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_NO_SANITIZE_ADDRESS
+#elif __has_feature(memory_sanitizer)
+#define ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_NO_SANITIZE_MEMORY
+#else
+#define ATTRIBUTE_NO_SANITIZE_ALL
+#endif
+#else
+#define ATTRIBUTE_NO_SANITIZE_ALL
+#endif
+
+#endif // LLVM_FUZZER_PLATFORM_H
diff --git a/libfuzzer/FuzzerRandom.h b/libfuzzer/FuzzerRandom.h
new file mode 100644
index 0000000..659283e
--- /dev/null
+++ b/libfuzzer/FuzzerRandom.h
@@ -0,0 +1,38 @@
+//===- FuzzerRandom.h - Internal header for the Fuzzer ----------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// fuzzer::Random
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_RANDOM_H
+#define LLVM_FUZZER_RANDOM_H
+
+#include <random>
+
+namespace fuzzer {
+class Random : public std::minstd_rand {
+ public:
+  Random(unsigned int seed) : std::minstd_rand(seed) {}
+  result_type operator()() { return this->std::minstd_rand::operator()(); }
+  size_t Rand() { return this->operator()(); }
+  size_t RandBool() { return Rand() % 2; }
+  size_t SkewTowardsLast(size_t n) {
+    size_t T = this->operator()(n * n);
+    size_t Res = sqrt(T);
+    return Res;
+  }
+  size_t operator()(size_t n) { return n ? Rand() % n : 0; }
+  intptr_t operator()(intptr_t From, intptr_t To) {
+    assert(From < To);
+    intptr_t RangeSize = To - From + 1;
+    return operator()(RangeSize) + From;
+  }
+};
+
+}  // namespace fuzzer
+
+#endif  // LLVM_FUZZER_RANDOM_H
diff --git a/libfuzzer/FuzzerSHA1.cpp b/libfuzzer/FuzzerSHA1.cpp
new file mode 100644
index 0000000..2005dc7
--- /dev/null
+++ b/libfuzzer/FuzzerSHA1.cpp
@@ -0,0 +1,223 @@
+//===- FuzzerSHA1.h - Private copy of the SHA1 implementation ---*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// This code is taken from public domain
+// (http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c)
+// and modified by adding anonymous namespace, adding an interface
+// function fuzzer::ComputeSHA1() and removing unnecessary code.
+//
+// lib/Fuzzer can not use SHA1 implementation from openssl because
+// openssl may not be available and because we may be fuzzing openssl itself.
+// For the same reason we do not want to depend on SHA1 from LLVM tree.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerSHA1.h"
+#include "FuzzerDefs.h"
+#include "FuzzerPlatform.h"
+
+/* This code is public-domain - it is based on libcrypt
+ * placed in the public domain by Wei Dai and other contributors.
+ */
+
+#include <iomanip>
+#include <sstream>
+#include <stdint.h>
+#include <string.h>
+
+namespace {  // Added for LibFuzzer
+
+#ifdef __BIG_ENDIAN__
+# define SHA_BIG_ENDIAN
+// Windows is always little endian and MSVC doesn't have <endian.h>
+#elif defined __LITTLE_ENDIAN__ || LIBFUZZER_WINDOWS
+/* 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
+
+namespace fuzzer {
+
+// The rest is added for LibFuzzer
+void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out) {
+  sha1nfo s;
+  sha1_init(&s);
+  sha1_write(&s, (const char*)Data, Len);
+  memcpy(Out, sha1_result(&s), HASH_LENGTH);
+}
+
+std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]) {
+  std::stringstream SS;
+  for (int i = 0; i < kSHA1NumBytes; i++)
+    SS << std::hex << std::setfill('0') << std::setw(2) << (unsigned)Sha1[i];
+  return SS.str();
+}
+
+std::string Hash(const Unit &U) {
+  uint8_t Hash[kSHA1NumBytes];
+  ComputeSHA1(U.data(), U.size(), Hash);
+  return Sha1ToString(Hash);
+}
+
+}
diff --git a/libfuzzer/FuzzerSHA1.h b/libfuzzer/FuzzerSHA1.h
new file mode 100644
index 0000000..05cbacd
--- /dev/null
+++ b/libfuzzer/FuzzerSHA1.h
@@ -0,0 +1,32 @@
+//===- FuzzerSHA1.h - Internal header for the SHA1 utils --------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// SHA1 utils.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_SHA1_H
+#define LLVM_FUZZER_SHA1_H
+
+#include "FuzzerDefs.h"
+#include <cstddef>
+#include <stdint.h>
+
+namespace fuzzer {
+
+// Private copy of SHA1 implementation.
+static const int kSHA1NumBytes = 20;
+
+// Computes SHA1 hash of 'Len' bytes in 'Data', writes kSHA1NumBytes to 'Out'.
+void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out);
+
+std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]);
+
+std::string Hash(const Unit &U);
+
+}  // namespace fuzzer
+
+#endif  // LLVM_FUZZER_SHA1_H
diff --git a/libfuzzer/FuzzerTracePC.cpp b/libfuzzer/FuzzerTracePC.cpp
new file mode 100644
index 0000000..b2ca769
--- /dev/null
+++ b/libfuzzer/FuzzerTracePC.cpp
@@ -0,0 +1,657 @@
+//===- FuzzerTracePC.cpp - PC tracing--------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Trace PCs.
+// This module implements __sanitizer_cov_trace_pc_guard[_init],
+// the callback required for -fsanitize-coverage=trace-pc-guard instrumentation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerTracePC.h"
+#include "FuzzerBuiltins.h"
+#include "FuzzerBuiltinsMsvc.h"
+#include "FuzzerCorpus.h"
+#include "FuzzerDefs.h"
+#include "FuzzerDictionary.h"
+#include "FuzzerExtFunctions.h"
+#include "FuzzerIO.h"
+#include "FuzzerPlatform.h"
+#include "FuzzerUtil.h"
+#include "FuzzerValueBitMap.h"
+#include <set>
+
+// Used by -fsanitize-coverage=stack-depth to track stack depth
+ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC uintptr_t __sancov_lowest_stack;
+
+namespace fuzzer {
+
+TracePC TPC;
+
+size_t TracePC::GetTotalPCCoverage() {
+  return ObservedPCs.size();
+}
+
+
+void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) {
+  if (Start == Stop) return;
+  if (NumModules &&
+      Modules[NumModules - 1].Start() == Start)
+    return;
+  assert(NumModules <
+         sizeof(Modules) / sizeof(Modules[0]));
+  auto &M = Modules[NumModules++];
+  uint8_t *AlignedStart = RoundUpByPage(Start);
+  uint8_t *AlignedStop  = RoundDownByPage(Stop);
+  size_t NumFullPages = AlignedStop > AlignedStart ?
+                        (AlignedStop - AlignedStart) / PageSize() : 0;
+  bool NeedFirst = Start < AlignedStart || !NumFullPages;
+  bool NeedLast  = Stop > AlignedStop && AlignedStop >= AlignedStart;
+  M.NumRegions = NumFullPages + NeedFirst + NeedLast;;
+  assert(M.NumRegions > 0);
+  M.Regions = new Module::Region[M.NumRegions];
+  assert(M.Regions);
+  size_t R = 0;
+  if (NeedFirst)
+    M.Regions[R++] = {Start, std::min(Stop, AlignedStart), true, false};
+  for (uint8_t *P = AlignedStart; P < AlignedStop; P += PageSize())
+    M.Regions[R++] = {P, P + PageSize(), true, true};
+  if (NeedLast)
+    M.Regions[R++] = {AlignedStop, Stop, true, false};
+  assert(R == M.NumRegions);
+  assert(M.Size() == (size_t)(Stop - Start));
+  assert(M.Stop() == Stop);
+  assert(M.Start() == Start);
+  NumInline8bitCounters += M.Size();
+}
+
+void TracePC::HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop) {
+  const PCTableEntry *B = reinterpret_cast<const PCTableEntry *>(Start);
+  const PCTableEntry *E = reinterpret_cast<const PCTableEntry *>(Stop);
+  if (NumPCTables && ModulePCTable[NumPCTables - 1].Start == B) return;
+  assert(NumPCTables < sizeof(ModulePCTable) / sizeof(ModulePCTable[0]));
+  ModulePCTable[NumPCTables++] = {B, E};
+  NumPCsInPCTables += E - B;
+}
+
+void TracePC::PrintModuleInfo() {
+  if (NumModules) {
+    Printf("INFO: Loaded %zd modules   (%zd inline 8-bit counters): ",
+           NumModules, NumInline8bitCounters);
+    for (size_t i = 0; i < NumModules; i++)
+      Printf("%zd [%p, %p), ", Modules[i].Size(), Modules[i].Start(),
+             Modules[i].Stop());
+    Printf("\n");
+  }
+  if (NumPCTables) {
+    Printf("INFO: Loaded %zd PC tables (%zd PCs): ", NumPCTables,
+           NumPCsInPCTables);
+    for (size_t i = 0; i < NumPCTables; i++) {
+      Printf("%zd [%p,%p), ", ModulePCTable[i].Stop - ModulePCTable[i].Start,
+             ModulePCTable[i].Start, ModulePCTable[i].Stop);
+    }
+    Printf("\n");
+
+    if (NumInline8bitCounters && NumInline8bitCounters != NumPCsInPCTables) {
+      Printf("ERROR: The size of coverage PC tables does not match the\n"
+             "number of instrumented PCs. This might be a compiler bug,\n"
+             "please contact the libFuzzer developers.\n"
+             "Also check https://bugs.llvm.org/show_bug.cgi?id=34636\n"
+             "for possible workarounds (tl;dr: don't use the old GNU ld)\n");
+      _Exit(1);
+    }
+  }
+  if (size_t NumExtraCounters = ExtraCountersEnd() - ExtraCountersBegin())
+    Printf("INFO: %zd Extra Counters\n", NumExtraCounters);
+}
+
+ATTRIBUTE_NO_SANITIZE_ALL
+void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
+  const uintptr_t kBits = 12;
+  const uintptr_t kMask = (1 << kBits) - 1;
+  uintptr_t Idx = (Caller & kMask) | ((Callee & kMask) << kBits);
+  ValueProfileMap.AddValueModPrime(Idx);
+}
+
+/// \return the address of the previous instruction.
+/// Note: the logic is copied from `sanitizer_common/sanitizer_stacktrace.h`
+inline ALWAYS_INLINE uintptr_t GetPreviousInstructionPc(uintptr_t PC) {
+#if defined(__arm__)
+  // T32 (Thumb) branch instructions might be 16 or 32 bit long,
+  // so we return (pc-2) in that case in order to be safe.
+  // For A32 mode we return (pc-4) because all instructions are 32 bit long.
+  return (PC - 3) & (~1);
+#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__aarch64__)
+  // PCs are always 4 byte aligned.
+  return PC - 4;
+#elif defined(__sparc__) || defined(__mips__)
+  return PC - 8;
+#else
+  return PC - 1;
+#endif
+}
+
+/// \return the address of the next instruction.
+/// Note: the logic is copied from `sanitizer_common/sanitizer_stacktrace.cpp`
+ALWAYS_INLINE uintptr_t TracePC::GetNextInstructionPc(uintptr_t PC) {
+#if defined(__mips__)
+  return PC + 8;
+#elif defined(__powerpc__) || defined(__sparc__) || defined(__arm__) || \
+    defined(__aarch64__)
+  return PC + 4;
+#else
+  return PC + 1;
+#endif
+}
+
+void TracePC::UpdateObservedPCs() {
+  Vector<uintptr_t> CoveredFuncs;
+  auto ObservePC = [&](const PCTableEntry *TE) {
+    if (ObservedPCs.insert(TE).second && DoPrintNewPCs) {
+      PrintPC("\tNEW_PC: %p %F %L", "\tNEW_PC: %p",
+              GetNextInstructionPc(TE->PC));
+      Printf("\n");
+    }
+  };
+
+  auto Observe = [&](const PCTableEntry *TE) {
+    if (PcIsFuncEntry(TE))
+      if (++ObservedFuncs[TE->PC] == 1 && NumPrintNewFuncs)
+        CoveredFuncs.push_back(TE->PC);
+    ObservePC(TE);
+  };
+
+  if (NumPCsInPCTables) {
+    if (NumInline8bitCounters == NumPCsInPCTables) {
+      for (size_t i = 0; i < NumModules; i++) {
+        auto &M = Modules[i];
+        assert(M.Size() ==
+               (size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
+        for (size_t r = 0; r < M.NumRegions; r++) {
+          auto &R = M.Regions[r];
+          if (!R.Enabled) continue;
+          for (uint8_t *P = R.Start; P < R.Stop; P++)
+            if (*P)
+              Observe(&ModulePCTable[i].Start[M.Idx(P)]);
+        }
+      }
+    }
+  }
+
+  for (size_t i = 0, N = Min(CoveredFuncs.size(), NumPrintNewFuncs); i < N;
+       i++) {
+    Printf("\tNEW_FUNC[%zd/%zd]: ", i + 1, CoveredFuncs.size());
+    PrintPC("%p %F %L", "%p", GetNextInstructionPc(CoveredFuncs[i]));
+    Printf("\n");
+  }
+}
+
+uintptr_t TracePC::PCTableEntryIdx(const PCTableEntry *TE) {
+  size_t TotalTEs = 0;
+  for (size_t i = 0; i < NumPCTables; i++) {
+    auto &M = ModulePCTable[i];
+    if (TE >= M.Start && TE < M.Stop)
+      return TotalTEs + TE - M.Start;
+    TotalTEs += M.Stop - M.Start;
+  }
+  assert(0);
+  return 0;
+}
+
+const TracePC::PCTableEntry *TracePC::PCTableEntryByIdx(uintptr_t Idx) {
+  for (size_t i = 0; i < NumPCTables; i++) {
+    auto &M = ModulePCTable[i];
+    size_t Size = M.Stop - M.Start;
+    if (Idx < Size) return &M.Start[Idx];
+    Idx -= Size;
+  }
+  return nullptr;
+}
+
+static std::string GetModuleName(uintptr_t PC) {
+  char ModulePathRaw[4096] = "";  // What's PATH_MAX in portable C++?
+  void *OffsetRaw = nullptr;
+  if (!EF->__sanitizer_get_module_and_offset_for_pc(
+      reinterpret_cast<void *>(PC), ModulePathRaw,
+      sizeof(ModulePathRaw), &OffsetRaw))
+    return "";
+  return ModulePathRaw;
+}
+
+template<class CallBack>
+void TracePC::IterateCoveredFunctions(CallBack CB) {
+  for (size_t i = 0; i < NumPCTables; i++) {
+    auto &M = ModulePCTable[i];
+    assert(M.Start < M.Stop);
+    auto ModuleName = GetModuleName(M.Start->PC);
+    for (auto NextFE = M.Start; NextFE < M.Stop; ) {
+      auto FE = NextFE;
+      assert(PcIsFuncEntry(FE) && "Not a function entry point");
+      do {
+        NextFE++;
+      } while (NextFE < M.Stop && !(PcIsFuncEntry(NextFE)));
+      CB(FE, NextFE, ObservedFuncs[FE->PC]);
+    }
+  }
+}
+
+void TracePC::SetFocusFunction(const std::string &FuncName) {
+  // This function should be called once.
+  assert(!FocusFunctionCounterPtr);
+  // "auto" is not a valid function name. If this function is called with "auto"
+  // that means the auto focus functionality failed.
+  if (FuncName.empty() || FuncName == "auto")
+    return;
+  for (size_t M = 0; M < NumModules; M++) {
+    auto &PCTE = ModulePCTable[M];
+    size_t N = PCTE.Stop - PCTE.Start;
+    for (size_t I = 0; I < N; I++) {
+      if (!(PcIsFuncEntry(&PCTE.Start[I]))) continue;  // not a function entry.
+      auto Name = DescribePC("%F", GetNextInstructionPc(PCTE.Start[I].PC));
+      if (Name[0] == 'i' && Name[1] == 'n' && Name[2] == ' ')
+        Name = Name.substr(3, std::string::npos);
+      if (FuncName != Name) continue;
+      Printf("INFO: Focus function is set to '%s'\n", Name.c_str());
+      FocusFunctionCounterPtr = Modules[M].Start() + I;
+      return;
+    }
+  }
+
+  Printf("ERROR: Failed to set focus function. Make sure the function name is "
+         "valid (%s) and symbolization is enabled.\n", FuncName.c_str());
+  exit(1);
+}
+
+bool TracePC::ObservedFocusFunction() {
+  return FocusFunctionCounterPtr && *FocusFunctionCounterPtr;
+}
+
+void TracePC::PrintCoverage() {
+  if (!EF->__sanitizer_symbolize_pc ||
+      !EF->__sanitizer_get_module_and_offset_for_pc) {
+    Printf("INFO: __sanitizer_symbolize_pc or "
+           "__sanitizer_get_module_and_offset_for_pc is not available,"
+           " not printing coverage\n");
+    return;
+  }
+  Printf("COVERAGE:\n");
+  auto CoveredFunctionCallback = [&](const PCTableEntry *First,
+                                     const PCTableEntry *Last,
+                                     uintptr_t Counter) {
+    assert(First < Last);
+    auto VisualizePC = GetNextInstructionPc(First->PC);
+    std::string FileStr = DescribePC("%s", VisualizePC);
+    if (!IsInterestingCoverageFile(FileStr))
+      return;
+    std::string FunctionStr = DescribePC("%F", VisualizePC);
+    if (FunctionStr.find("in ") == 0)
+      FunctionStr = FunctionStr.substr(3);
+    std::string LineStr = DescribePC("%l", VisualizePC);
+    size_t NumEdges = Last - First;
+    Vector<uintptr_t> UncoveredPCs;
+    for (auto TE = First; TE < Last; TE++)
+      if (!ObservedPCs.count(TE))
+        UncoveredPCs.push_back(TE->PC);
+    Printf("%sCOVERED_FUNC: hits: %zd", Counter ? "" : "UN", Counter);
+    Printf(" edges: %zd/%zd", NumEdges - UncoveredPCs.size(), NumEdges);
+    Printf(" %s %s:%s\n", FunctionStr.c_str(), FileStr.c_str(),
+           LineStr.c_str());
+    if (Counter)
+      for (auto PC : UncoveredPCs)
+        Printf("  UNCOVERED_PC: %s\n",
+               DescribePC("%s:%l", GetNextInstructionPc(PC)).c_str());
+  };
+
+  IterateCoveredFunctions(CoveredFunctionCallback);
+}
+
+// Value profile.
+// We keep track of various values that affect control flow.
+// These values are inserted into a bit-set-based hash map.
+// Every new bit in the map is treated as a new coverage.
+//
+// For memcmp/strcmp/etc the interesting value is the length of the common
+// prefix of the parameters.
+// For cmp instructions the interesting value is a XOR of the parameters.
+// The interesting value is mixed up with the PC and is then added to the map.
+
+ATTRIBUTE_NO_SANITIZE_ALL
+void TracePC::AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
+                                size_t n, bool StopAtZero) {
+  if (!n) return;
+  size_t Len = std::min(n, Word::GetMaxSize());
+  const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
+  const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
+  uint8_t B1[Word::kMaxSize];
+  uint8_t B2[Word::kMaxSize];
+  // Copy the data into locals in this non-msan-instrumented function
+  // to avoid msan complaining further.
+  size_t Hash = 0;  // Compute some simple hash of both strings.
+  for (size_t i = 0; i < Len; i++) {
+    B1[i] = A1[i];
+    B2[i] = A2[i];
+    size_t T = B1[i];
+    Hash ^= (T << 8) | B2[i];
+  }
+  size_t I = 0;
+  uint8_t HammingDistance = 0;
+  for (; I < Len; I++) {
+    if (B1[I] != B2[I] || (StopAtZero && B1[I] == 0)) {
+      HammingDistance = Popcountll(B1[I] ^ B2[I]);
+      break;
+    }
+  }
+  size_t PC = reinterpret_cast<size_t>(caller_pc);
+  size_t Idx = (PC & 4095) | (I << 12);
+  Idx += HammingDistance;
+  ValueProfileMap.AddValue(Idx);
+  TORCW.Insert(Idx ^ Hash, Word(B1, Len), Word(B2, Len));
+}
+
+template <class T>
+ATTRIBUTE_TARGET_POPCNT ALWAYS_INLINE
+ATTRIBUTE_NO_SANITIZE_ALL
+void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) {
+  uint64_t ArgXor = Arg1 ^ Arg2;
+  if (sizeof(T) == 4)
+      TORC4.Insert(ArgXor, Arg1, Arg2);
+  else if (sizeof(T) == 8)
+      TORC8.Insert(ArgXor, Arg1, Arg2);
+  uint64_t HammingDistance = Popcountll(ArgXor);  // [0,64]
+  uint64_t AbsoluteDistance = (Arg1 == Arg2 ? 0 : Clzll(Arg1 - Arg2) + 1);
+  ValueProfileMap.AddValue(PC * 128 + HammingDistance);
+  ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance);
+}
+
+static size_t InternalStrnlen(const char *S, size_t MaxLen) {
+  size_t Len = 0;
+  for (; Len < MaxLen && S[Len]; Len++) {}
+  return Len;
+}
+
+// Finds min of (strlen(S1), strlen(S2)).
+// Needed bacause one of these strings may actually be non-zero terminated.
+static size_t InternalStrnlen2(const char *S1, const char *S2) {
+  size_t Len = 0;
+  for (; S1[Len] && S2[Len]; Len++)  {}
+  return Len;
+}
+
+void TracePC::ClearInlineCounters() {
+  IterateCounterRegions([](const Module::Region &R){
+    if (R.Enabled)
+      memset(R.Start, 0, R.Stop - R.Start);
+  });
+}
+
+ATTRIBUTE_NO_SANITIZE_ALL
+void TracePC::RecordInitialStack() {
+  int stack;
+  __sancov_lowest_stack = InitialStack = reinterpret_cast<uintptr_t>(&stack);
+}
+
+uintptr_t TracePC::GetMaxStackOffset() const {
+  return InitialStack - __sancov_lowest_stack;  // Stack grows down
+}
+
+void WarnAboutDeprecatedInstrumentation(const char *flag) {
+  // Use RawPrint because Printf cannot be used on Windows before OutputFile is
+  // initialized.
+  RawPrint(flag);
+  RawPrint(
+      " is no longer supported by libFuzzer.\n"
+      "Please either migrate to a compiler that supports -fsanitize=fuzzer\n"
+      "or use an older version of libFuzzer\n");
+  exit(1);
+}
+
+} // namespace fuzzer
+
+extern "C" {
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
+  fuzzer::WarnAboutDeprecatedInstrumentation(
+      "-fsanitize-coverage=trace-pc-guard");
+}
+
+// Best-effort support for -fsanitize-coverage=trace-pc, which is available
+// in both Clang and GCC.
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+void __sanitizer_cov_trace_pc() {
+  fuzzer::WarnAboutDeprecatedInstrumentation("-fsanitize-coverage=trace-pc");
+}
+
+ATTRIBUTE_INTERFACE
+void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) {
+  fuzzer::WarnAboutDeprecatedInstrumentation(
+      "-fsanitize-coverage=trace-pc-guard");
+}
+
+ATTRIBUTE_INTERFACE
+void __sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop) {
+  fuzzer::TPC.HandleInline8bitCountersInit(Start, Stop);
+}
+
+ATTRIBUTE_INTERFACE
+void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
+                              const uintptr_t *pcs_end) {
+  fuzzer::TPC.HandlePCsInit(pcs_beg, pcs_end);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
+  fuzzer::TPC.HandleCallerCallee(PC, Callee);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
+  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+// Now the __sanitizer_cov_trace_const_cmp[1248] callbacks just mimic
+// the behaviour of __sanitizer_cov_trace_cmp[1248] ones. This, however,
+// should be changed later to make full use of instrumentation.
+void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
+  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
+  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
+  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
+  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
+  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
+  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
+  fuzzer::TPC.HandleCmp(PC, Arg1, Arg2);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
+  uint64_t N = Cases[0];
+  uint64_t ValSizeInBits = Cases[1];
+  uint64_t *Vals = Cases + 2;
+  // Skip the most common and the most boring case: all switch values are small.
+  // We may want to skip this at compile-time, but it will make the
+  // instrumentation less general.
+  if (Vals[N - 1]  < 256)
+    return;
+  // Also skip small inputs values, they won't give good signal.
+  if (Val < 256)
+    return;
+  uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
+  size_t i;
+  uint64_t Smaller = 0;
+  uint64_t Larger = ~(uint64_t)0;
+  // Find two switch values such that Smaller < Val < Larger.
+  // Use 0 and 0xfff..f as the defaults.
+  for (i = 0; i < N; i++) {
+    if (Val < Vals[i]) {
+      Larger = Vals[i];
+      break;
+    }
+    if (Val > Vals[i]) Smaller = Vals[i];
+  }
+
+  // Apply HandleCmp to {Val,Smaller} and {Val, Larger},
+  // use i as the PC modifier for HandleCmp.
+  if (ValSizeInBits == 16) {
+    fuzzer::TPC.HandleCmp(PC + 2 * i, static_cast<uint16_t>(Val),
+                          (uint16_t)(Smaller));
+    fuzzer::TPC.HandleCmp(PC + 2 * i + 1, static_cast<uint16_t>(Val),
+                          (uint16_t)(Larger));
+  } else if (ValSizeInBits == 32) {
+    fuzzer::TPC.HandleCmp(PC + 2 * i, static_cast<uint32_t>(Val),
+                          (uint32_t)(Smaller));
+    fuzzer::TPC.HandleCmp(PC + 2 * i + 1, static_cast<uint32_t>(Val),
+                          (uint32_t)(Larger));
+  } else {
+    fuzzer::TPC.HandleCmp(PC + 2*i, Val, Smaller);
+    fuzzer::TPC.HandleCmp(PC + 2*i + 1, Val, Larger);
+  }
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_div4(uint32_t Val) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
+  fuzzer::TPC.HandleCmp(PC, Val, (uint32_t)0);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_div8(uint64_t Val) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
+  fuzzer::TPC.HandleCmp(PC, Val, (uint64_t)0);
+}
+
+ATTRIBUTE_INTERFACE
+ATTRIBUTE_NO_SANITIZE_ALL
+ATTRIBUTE_TARGET_POPCNT
+void __sanitizer_cov_trace_gep(uintptr_t Idx) {
+  uintptr_t PC = reinterpret_cast<uintptr_t>(GET_CALLER_PC());
+  fuzzer::TPC.HandleCmp(PC, Idx, (uintptr_t)0);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
+                                  const void *s2, size_t n, int result) {
+  if (!fuzzer::RunningUserCallback) return;
+  if (result == 0) return;  // No reason to mutate.
+  if (n <= 1) return;  // Not interesting.
+  fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/false);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
+                                   const char *s2, size_t n, int result) {
+  if (!fuzzer::RunningUserCallback) return;
+  if (result == 0) return;  // No reason to mutate.
+  size_t Len1 = fuzzer::InternalStrnlen(s1, n);
+  size_t Len2 = fuzzer::InternalStrnlen(s2, n);
+  n = std::min(n, Len1);
+  n = std::min(n, Len2);
+  if (n <= 1) return;  // Not interesting.
+  fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/true);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
+                                   const char *s2, int result) {
+  if (!fuzzer::RunningUserCallback) return;
+  if (result == 0) return;  // No reason to mutate.
+  size_t N = fuzzer::InternalStrnlen2(s1, s2);
+  if (N <= 1) return;  // Not interesting.
+  fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, N, /*StopAtZero*/true);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
+                                       const char *s2, size_t n, int result) {
+  if (!fuzzer::RunningUserCallback) return;
+  return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
+                                      const char *s2, int result) {
+  if (!fuzzer::RunningUserCallback) return;
+  return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result);
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,
+                                  const char *s2, char *result) {
+  if (!fuzzer::RunningUserCallback) return;
+  fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,
+                                      const char *s2, char *result) {
+  if (!fuzzer::RunningUserCallback) return;
+  fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
+}
+
+ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
+void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,
+                                  const void *s2, size_t len2, void *result) {
+  if (!fuzzer::RunningUserCallback) return;
+  fuzzer::TPC.MMT.Add(reinterpret_cast<const uint8_t *>(s2), len2);
+}
+}  // extern "C"
diff --git a/libfuzzer/FuzzerTracePC.h b/libfuzzer/FuzzerTracePC.h
new file mode 100644
index 0000000..501f3b5
--- /dev/null
+++ b/libfuzzer/FuzzerTracePC.h
@@ -0,0 +1,289 @@
+//===- FuzzerTracePC.h - Internal header for the Fuzzer ---------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// fuzzer::TracePC
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_TRACE_PC
+#define LLVM_FUZZER_TRACE_PC
+
+#include "FuzzerDefs.h"
+#include "FuzzerDictionary.h"
+#include "FuzzerValueBitMap.h"
+
+#include <set>
+#include <unordered_map>
+
+namespace fuzzer {
+
+// TableOfRecentCompares (TORC) remembers the most recently performed
+// comparisons of type T.
+// We record the arguments of CMP instructions in this table unconditionally
+// because it seems cheaper this way than to compute some expensive
+// conditions inside __sanitizer_cov_trace_cmp*.
+// After the unit has been executed we may decide to use the contents of
+// this table to populate a Dictionary.
+template<class T, size_t kSizeT>
+struct TableOfRecentCompares {
+  static const size_t kSize = kSizeT;
+  struct Pair {
+    T A, B;
+  };
+  ATTRIBUTE_NO_SANITIZE_ALL
+  void Insert(size_t Idx, const T &Arg1, const T &Arg2) {
+    Idx = Idx % kSize;
+    Table[Idx].A = Arg1;
+    Table[Idx].B = Arg2;
+  }
+
+  Pair Get(size_t I) { return Table[I % kSize]; }
+
+  Pair Table[kSize];
+};
+
+template <size_t kSizeT>
+struct MemMemTable {
+  static const size_t kSize = kSizeT;
+  Word MemMemWords[kSize];
+  Word EmptyWord;
+
+  void Add(const uint8_t *Data, size_t Size) {
+    if (Size <= 2) return;
+    Size = std::min(Size, Word::GetMaxSize());
+    size_t Idx = SimpleFastHash(Data, Size) % kSize;
+    MemMemWords[Idx].Set(Data, Size);
+  }
+  const Word &Get(size_t Idx) {
+    for (size_t i = 0; i < kSize; i++) {
+      const Word &W = MemMemWords[(Idx + i) % kSize];
+      if (W.size()) return W;
+    }
+    EmptyWord.Set(nullptr, 0);
+    return EmptyWord;
+  }
+};
+
+class TracePC {
+ public:
+  void HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop);
+  void HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop);
+  void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee);
+  template <class T> void HandleCmp(uintptr_t PC, T Arg1, T Arg2);
+  size_t GetTotalPCCoverage();
+  void SetUseCounters(bool UC) { UseCounters = UC; }
+  void SetUseValueProfileMask(uint32_t VPMask) { UseValueProfileMask = VPMask; }
+  void SetPrintNewPCs(bool P) { DoPrintNewPCs = P; }
+  void SetPrintNewFuncs(size_t P) { NumPrintNewFuncs = P; }
+  void UpdateObservedPCs();
+  template <class Callback> void CollectFeatures(Callback CB) const;
+
+  void ResetMaps() {
+    ValueProfileMap.Reset();
+    ClearExtraCounters();
+    ClearInlineCounters();
+  }
+
+  void ClearInlineCounters();
+
+  void UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize);
+  void PrintFeatureSet();
+
+  void PrintModuleInfo();
+
+  void PrintCoverage();
+
+  template<class CallBack>
+  void IterateCoveredFunctions(CallBack CB);
+
+  void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
+                         size_t n, bool StopAtZero);
+
+  TableOfRecentCompares<uint32_t, 32> TORC4;
+  TableOfRecentCompares<uint64_t, 32> TORC8;
+  TableOfRecentCompares<Word, 32> TORCW;
+  MemMemTable<1024> MMT;
+
+  void RecordInitialStack();
+  uintptr_t GetMaxStackOffset() const;
+
+  template<class CallBack>
+  void ForEachObservedPC(CallBack CB) {
+    for (auto PC : ObservedPCs)
+      CB(PC);
+  }
+
+  void SetFocusFunction(const std::string &FuncName);
+  bool ObservedFocusFunction();
+
+  struct PCTableEntry {
+    uintptr_t PC, PCFlags;
+  };
+
+  uintptr_t PCTableEntryIdx(const PCTableEntry *TE);
+  const PCTableEntry *PCTableEntryByIdx(uintptr_t Idx);
+  static uintptr_t GetNextInstructionPc(uintptr_t PC);
+  bool PcIsFuncEntry(const PCTableEntry *TE) { return TE->PCFlags & 1; }
+
+private:
+  bool UseCounters = false;
+  uint32_t UseValueProfileMask = false;
+  bool DoPrintNewPCs = false;
+  size_t NumPrintNewFuncs = 0;
+
+  // Module represents the array of 8-bit counters split into regions
+  // such that every region, except maybe the first and the last one, is one
+  // full page.
+  struct Module {
+    struct Region {
+      uint8_t *Start, *Stop;
+      bool Enabled;
+      bool OneFullPage;
+    };
+    Region *Regions;
+    size_t NumRegions;
+    uint8_t *Start() { return Regions[0].Start; }
+    uint8_t *Stop()  { return Regions[NumRegions - 1].Stop; }
+    size_t Size()   { return Stop() - Start(); }
+    size_t  Idx(uint8_t *P) {
+      assert(P >= Start() && P < Stop());
+      return P - Start();
+    }
+  };
+
+  Module Modules[4096];
+  size_t NumModules;  // linker-initialized.
+  size_t NumInline8bitCounters;
+
+  template <class Callback>
+  void IterateCounterRegions(Callback CB) {
+    for (size_t m = 0; m < NumModules; m++)
+      for (size_t r = 0; r < Modules[m].NumRegions; r++)
+        CB(Modules[m].Regions[r]);
+  }
+
+  struct { const PCTableEntry *Start, *Stop; } ModulePCTable[4096];
+  size_t NumPCTables;
+  size_t NumPCsInPCTables;
+
+  Set<const PCTableEntry*> ObservedPCs;
+  std::unordered_map<uintptr_t, uintptr_t> ObservedFuncs;  // PC => Counter.
+
+  uint8_t *FocusFunctionCounterPtr = nullptr;
+
+  ValueBitMap ValueProfileMap;
+  uintptr_t InitialStack;
+};
+
+template <class Callback>
+// void Callback(size_t FirstFeature, size_t Idx, uint8_t Value);
+ATTRIBUTE_NO_SANITIZE_ALL
+size_t ForEachNonZeroByte(const uint8_t *Begin, const uint8_t *End,
+                        size_t FirstFeature, Callback Handle8bitCounter) {
+  typedef uintptr_t LargeType;
+  const size_t Step = sizeof(LargeType) / sizeof(uint8_t);
+  const size_t StepMask = Step - 1;
+  auto P = Begin;
+  // Iterate by 1 byte until either the alignment boundary or the end.
+  for (; reinterpret_cast<uintptr_t>(P) & StepMask && P < End; P++)
+    if (uint8_t V = *P)
+      Handle8bitCounter(FirstFeature, P - Begin, V);
+
+  // Iterate by Step bytes at a time.
+  for (; P < End; P += Step)
+    if (LargeType Bundle = *reinterpret_cast<const LargeType *>(P))
+      for (size_t I = 0; I < Step; I++, Bundle >>= 8)
+        if (uint8_t V = Bundle & 0xff)
+          Handle8bitCounter(FirstFeature, P - Begin + I, V);
+
+  // Iterate by 1 byte until the end.
+  for (; P < End; P++)
+    if (uint8_t V = *P)
+      Handle8bitCounter(FirstFeature, P - Begin, V);
+  return End - Begin;
+}
+
+// Given a non-zero Counter returns a number in the range [0,7].
+template<class T>
+unsigned CounterToFeature(T Counter) {
+    // Returns a feature number by placing Counters into buckets as illustrated
+    // below.
+    //
+    // Counter bucket: [1] [2] [3] [4-7] [8-15] [16-31] [32-127] [128+]
+    // Feature number:  0   1   2    3     4       5       6       7
+    //
+    // This is a heuristic taken from AFL (see
+    // http://lcamtuf.coredump.cx/afl/technical_details.txt).
+    //
+    // This implementation may change in the future so clients should
+    // not rely on it.
+    assert(Counter);
+    unsigned Bit = 0;
+    /**/ if (Counter >= 128) Bit = 7;
+    else if (Counter >= 32) Bit = 6;
+    else if (Counter >= 16) Bit = 5;
+    else if (Counter >= 8) Bit = 4;
+    else if (Counter >= 4) Bit = 3;
+    else if (Counter >= 3) Bit = 2;
+    else if (Counter >= 2) Bit = 1;
+    return Bit;
+}
+
+template <class Callback>  // void Callback(size_t Feature)
+ATTRIBUTE_NO_SANITIZE_ADDRESS
+ATTRIBUTE_NOINLINE
+void TracePC::CollectFeatures(Callback HandleFeature) const {
+  auto Handle8bitCounter = [&](size_t FirstFeature,
+                               size_t Idx, uint8_t Counter) {
+    if (UseCounters)
+      HandleFeature(FirstFeature + Idx * 8 + CounterToFeature(Counter));
+    else
+      HandleFeature(FirstFeature + Idx);
+  };
+
+  size_t FirstFeature = 0;
+
+  for (size_t i = 0; i < NumModules; i++) {
+    for (size_t r = 0; r < Modules[i].NumRegions; r++) {
+      if (!Modules[i].Regions[r].Enabled) continue;
+      FirstFeature += 8 * ForEachNonZeroByte(Modules[i].Regions[r].Start,
+                                             Modules[i].Regions[r].Stop,
+                                             FirstFeature, Handle8bitCounter);
+    }
+  }
+
+  FirstFeature +=
+      8 * ForEachNonZeroByte(ExtraCountersBegin(), ExtraCountersEnd(),
+                             FirstFeature, Handle8bitCounter);
+
+  if (UseValueProfileMask) {
+    ValueProfileMap.ForEach([&](size_t Idx) {
+      HandleFeature(FirstFeature + Idx);
+    });
+    FirstFeature += ValueProfileMap.SizeInBits();
+  }
+
+  // Step function, grows similar to 8 * Log_2(A).
+  auto StackDepthStepFunction = [](uint32_t A) -> uint32_t {
+    if (!A) return A;
+    uint32_t Log2 = Log(A);
+    if (Log2 < 3) return A;
+    Log2 -= 3;
+    return (Log2 + 1) * 8 + ((A >> Log2) & 7);
+  };
+  assert(StackDepthStepFunction(1024) == 64);
+  assert(StackDepthStepFunction(1024 * 4) == 80);
+  assert(StackDepthStepFunction(1024 * 1024) == 144);
+
+  if (auto MaxStackOffset = GetMaxStackOffset())
+    HandleFeature(FirstFeature + StackDepthStepFunction(MaxStackOffset / 8));
+}
+
+extern TracePC TPC;
+
+}  // namespace fuzzer
+
+#endif  // LLVM_FUZZER_TRACE_PC
diff --git a/libfuzzer/FuzzerUtil.cpp b/libfuzzer/FuzzerUtil.cpp
new file mode 100644
index 0000000..7eecb68
--- /dev/null
+++ b/libfuzzer/FuzzerUtil.cpp
@@ -0,0 +1,236 @@
+//===- FuzzerUtil.cpp - Misc utils ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Misc utils.
+//===----------------------------------------------------------------------===//
+
+#include "FuzzerUtil.h"
+#include "FuzzerIO.h"
+#include "FuzzerInternal.h"
+#include <cassert>
+#include <chrono>
+#include <cstring>
+#include <errno.h>
+#include <mutex>
+#include <signal.h>
+#include <sstream>
+#include <stdio.h>
+#include <sys/types.h>
+#include <thread>
+
+namespace fuzzer {
+
+void PrintHexArray(const uint8_t *Data, size_t Size,
+                   const char *PrintAfter) {
+  for (size_t i = 0; i < Size; i++)
+    Printf("0x%x,", (unsigned)Data[i]);
+  Printf("%s", PrintAfter);
+}
+
+void Print(const Unit &v, const char *PrintAfter) {
+  PrintHexArray(v.data(), v.size(), PrintAfter);
+}
+
+void PrintASCIIByte(uint8_t Byte) {
+  if (Byte == '\\')
+    Printf("\\\\");
+  else if (Byte == '"')
+    Printf("\\\"");
+  else if (Byte >= 32 && Byte < 127)
+    Printf("%c", Byte);
+  else
+    Printf("\\x%02x", Byte);
+}
+
+void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) {
+  for (size_t i = 0; i < Size; i++)
+    PrintASCIIByte(Data[i]);
+  Printf("%s", PrintAfter);
+}
+
+void PrintASCII(const Unit &U, const char *PrintAfter) {
+  PrintASCII(U.data(), U.size(), PrintAfter);
+}
+
+bool ToASCII(uint8_t *Data, size_t Size) {
+  bool Changed = false;
+  for (size_t i = 0; i < Size; i++) {
+    uint8_t &X = Data[i];
+    auto NewX = X;
+    NewX &= 127;
+    if (!isspace(NewX) && !isprint(NewX))
+      NewX = ' ';
+    Changed |= NewX != X;
+    X = NewX;
+  }
+  return Changed;
+}
+
+bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); }
+
+bool IsASCII(const uint8_t *Data, size_t Size) {
+  for (size_t i = 0; i < Size; i++)
+    if (!(isprint(Data[i]) || isspace(Data[i]))) return false;
+  return true;
+}
+
+bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) {
+  U->clear();
+  if (Str.empty()) return false;
+  size_t L = 0, R = Str.size() - 1;  // We are parsing the range [L,R].
+  // Skip spaces from both sides.
+  while (L < R && isspace(Str[L])) L++;
+  while (R > L && isspace(Str[R])) R--;
+  if (R - L < 2) return false;
+  // Check the closing "
+  if (Str[R] != '"') return false;
+  R--;
+  // Find the opening "
+  while (L < R && Str[L] != '"') L++;
+  if (L >= R) return false;
+  assert(Str[L] == '\"');
+  L++;
+  assert(L <= R);
+  for (size_t Pos = L; Pos <= R; Pos++) {
+    uint8_t V = (uint8_t)Str[Pos];
+    if (!isprint(V) && !isspace(V)) return false;
+    if (V =='\\') {
+      // Handle '\\'
+      if (Pos + 1 <= R && (Str[Pos + 1] == '\\' || Str[Pos + 1] == '"')) {
+        U->push_back(Str[Pos + 1]);
+        Pos++;
+        continue;
+      }
+      // Handle '\xAB'
+      if (Pos + 3 <= R && Str[Pos + 1] == 'x'
+           && isxdigit(Str[Pos + 2]) && isxdigit(Str[Pos + 3])) {
+        char Hex[] = "0xAA";
+        Hex[2] = Str[Pos + 2];
+        Hex[3] = Str[Pos + 3];
+        U->push_back(strtol(Hex, nullptr, 16));
+        Pos += 3;
+        continue;
+      }
+      return false;  // Invalid escape.
+    } else {
+      // Any other character.
+      U->push_back(V);
+    }
+  }
+  return true;
+}
+
+bool ParseDictionaryFile(const std::string &Text, 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;
+}
+
+// Code duplicated (and tested) in llvm/include/llvm/Support/Base64.h
+std::string Base64(const Unit &U) {
+  static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                              "abcdefghijklmnopqrstuvwxyz"
+                              "0123456789+/";
+  std::string Buffer;
+  Buffer.resize(((U.size() + 2) / 3) * 4);
+
+  size_t i = 0, j = 0;
+  for (size_t n = U.size() / 3 * 3; i < n; i += 3, j += 4) {
+    uint32_t x = ((unsigned char)U[i] << 16) | ((unsigned char)U[i + 1] << 8) |
+                 (unsigned char)U[i + 2];
+    Buffer[j + 0] = Table[(x >> 18) & 63];
+    Buffer[j + 1] = Table[(x >> 12) & 63];
+    Buffer[j + 2] = Table[(x >> 6) & 63];
+    Buffer[j + 3] = Table[x & 63];
+  }
+  if (i + 1 == U.size()) {
+    uint32_t x = ((unsigned char)U[i] << 16);
+    Buffer[j + 0] = Table[(x >> 18) & 63];
+    Buffer[j + 1] = Table[(x >> 12) & 63];
+    Buffer[j + 2] = '=';
+    Buffer[j + 3] = '=';
+  } else if (i + 2 == U.size()) {
+    uint32_t x = ((unsigned char)U[i] << 16) | ((unsigned char)U[i + 1] << 8);
+    Buffer[j + 0] = Table[(x >> 18) & 63];
+    Buffer[j + 1] = Table[(x >> 12) & 63];
+    Buffer[j + 2] = Table[(x >> 6) & 63];
+    Buffer[j + 3] = '=';
+  }
+  return Buffer;
+}
+
+static std::mutex SymbolizeMutex;
+
+std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) {
+  std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock);
+  if (!EF->__sanitizer_symbolize_pc || !l.owns_lock())
+    return "<can not symbolize>";
+  char PcDescr[1024] = {};
+  EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC),
+                               SymbolizedFMT, PcDescr, sizeof(PcDescr));
+  PcDescr[sizeof(PcDescr) - 1] = 0;  // Just in case.
+  return PcDescr;
+}
+
+void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) {
+  if (EF->__sanitizer_symbolize_pc)
+    Printf("%s", DescribePC(SymbolizedFMT, PC).c_str());
+  else
+    Printf(FallbackFMT, PC);
+}
+
+void PrintStackTrace() {
+  std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock);
+  if (EF->__sanitizer_print_stack_trace && l.owns_lock())
+    EF->__sanitizer_print_stack_trace();
+}
+
+void PrintMemoryProfile() {
+  std::unique_lock<std::mutex> l(SymbolizeMutex, std::try_to_lock);
+  if (EF->__sanitizer_print_memory_profile && l.owns_lock())
+    EF->__sanitizer_print_memory_profile(95, 8);
+}
+
+unsigned NumberOfCpuCores() {
+  unsigned N = std::thread::hardware_concurrency();
+  if (!N) {
+    Printf("WARNING: std::thread::hardware_concurrency not well defined for "
+           "your platform. Assuming CPU count of 1.\n");
+    N = 1;
+  }
+  return N;
+}
+
+size_t SimpleFastHash(const uint8_t *Data, size_t Size) {
+  size_t Res = 0;
+  for (size_t i = 0; i < Size; i++)
+    Res = Res * 11 + Data[i];
+  return Res;
+}
+
+}  // namespace fuzzer
diff --git a/libfuzzer/FuzzerUtil.h b/libfuzzer/FuzzerUtil.h
new file mode 100644
index 0000000..4ae3583
--- /dev/null
+++ b/libfuzzer/FuzzerUtil.h
@@ -0,0 +1,111 @@
+//===- FuzzerUtil.h - Internal header for the Fuzzer Utils ------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Util functions.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_UTIL_H
+#define LLVM_FUZZER_UTIL_H
+
+#include "FuzzerBuiltins.h"
+#include "FuzzerBuiltinsMsvc.h"
+#include "FuzzerCommand.h"
+#include "FuzzerDefs.h"
+
+namespace fuzzer {
+
+void PrintHexArray(const Unit &U, const char *PrintAfter = "");
+
+void PrintHexArray(const uint8_t *Data, size_t Size,
+                   const char *PrintAfter = "");
+
+void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = "");
+
+void PrintASCII(const Unit &U, const char *PrintAfter = "");
+
+// Changes U to contain only ASCII (isprint+isspace) characters.
+// Returns true iff U has been changed.
+bool ToASCII(uint8_t *Data, size_t Size);
+
+bool IsASCII(const Unit &U);
+
+bool IsASCII(const uint8_t *Data, size_t Size);
+
+std::string Base64(const Unit &U);
+
+void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC);
+
+std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC);
+
+void PrintStackTrace();
+
+void PrintMemoryProfile();
+
+unsigned NumberOfCpuCores();
+
+// Platform specific functions.
+void SetSignalHandler(const FuzzingOptions& Options);
+
+void SleepSeconds(int Seconds);
+
+unsigned long GetPid();
+
+size_t GetPeakRSSMb();
+
+int ExecuteCommand(const Command &Cmd);
+bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput);
+
+// Fuchsia does not have popen/pclose.
+FILE *OpenProcessPipe(const char *Command, const char *Mode);
+int CloseProcessPipe(FILE *F);
+
+const void *SearchMemory(const void *haystack, size_t haystacklen,
+                         const void *needle, size_t needlelen);
+
+std::string CloneArgsWithoutX(const Vector<std::string> &Args,
+                              const char *X1, const char *X2);
+
+inline std::string CloneArgsWithoutX(const Vector<std::string> &Args,
+                                     const char *X) {
+  return CloneArgsWithoutX(Args, X, X);
+}
+
+inline std::pair<std::string, std::string> SplitBefore(std::string X,
+                                                       std::string S) {
+  auto Pos = S.find(X);
+  if (Pos == std::string::npos)
+    return std::make_pair(S, "");
+  return std::make_pair(S.substr(0, Pos), S.substr(Pos));
+}
+
+void DiscardOutput(int Fd);
+
+std::string DisassembleCmd(const std::string &FileName);
+
+std::string SearchRegexCmd(const std::string &Regex);
+
+size_t SimpleFastHash(const uint8_t *Data, size_t Size);
+
+inline uint32_t Log(uint32_t X) { return 32 - Clz(X) - 1; }
+
+inline size_t PageSize() { return 4096; }
+inline uint8_t *RoundUpByPage(uint8_t *P) {
+  uintptr_t X = reinterpret_cast<uintptr_t>(P);
+  size_t Mask = PageSize() - 1;
+  X = (X + Mask) & ~Mask;
+  return reinterpret_cast<uint8_t *>(X);
+}
+inline uint8_t *RoundDownByPage(uint8_t *P) {
+  uintptr_t X = reinterpret_cast<uintptr_t>(P);
+  size_t Mask = PageSize() - 1;
+  X = X & ~Mask;
+  return reinterpret_cast<uint8_t *>(X);
+}
+
+}  // namespace fuzzer
+
+#endif  // LLVM_FUZZER_UTIL_H
diff --git a/libfuzzer/FuzzerUtilDarwin.cpp b/libfuzzer/FuzzerUtilDarwin.cpp
new file mode 100644
index 0000000..a5bed65
--- /dev/null
+++ b/libfuzzer/FuzzerUtilDarwin.cpp
@@ -0,0 +1,170 @@
+//===- FuzzerUtilDarwin.cpp - Misc utils ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Misc utils for Darwin.
+//===----------------------------------------------------------------------===//
+#include "FuzzerPlatform.h"
+#if LIBFUZZER_APPLE
+#include "FuzzerCommand.h"
+#include "FuzzerIO.h"
+#include <mutex>
+#include <signal.h>
+#include <spawn.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+// There is no header for this on macOS so declare here
+extern "C" char **environ;
+
+namespace fuzzer {
+
+static std::mutex SignalMutex;
+// Global variables used to keep track of how signal handling should be
+// restored. They should **not** be accessed without holding `SignalMutex`.
+static int ActiveThreadCount = 0;
+static struct sigaction OldSigIntAction;
+static struct sigaction OldSigQuitAction;
+static sigset_t OldBlockedSignalsSet;
+
+// This is a reimplementation of Libc's `system()`. On Darwin the Libc
+// implementation contains a mutex which prevents it from being used
+// concurrently. This implementation **can** be used concurrently. It sets the
+// signal handlers when the first thread enters and restores them when the last
+// thread finishes execution of the function and ensures this is not racey by
+// using a mutex.
+int ExecuteCommand(const Command &Cmd) {
+  std::string CmdLine = Cmd.toString();
+  posix_spawnattr_t SpawnAttributes;
+  if (posix_spawnattr_init(&SpawnAttributes))
+    return -1;
+  // Block and ignore signals of the current process when the first thread
+  // enters.
+  {
+    std::lock_guard<std::mutex> Lock(SignalMutex);
+    if (ActiveThreadCount == 0) {
+      static struct sigaction IgnoreSignalAction;
+      sigset_t BlockedSignalsSet;
+      memset(&IgnoreSignalAction, 0, sizeof(IgnoreSignalAction));
+      IgnoreSignalAction.sa_handler = SIG_IGN;
+
+      if (sigaction(SIGINT, &IgnoreSignalAction, &OldSigIntAction) == -1) {
+        Printf("Failed to ignore SIGINT\n");
+        (void)posix_spawnattr_destroy(&SpawnAttributes);
+        return -1;
+      }
+      if (sigaction(SIGQUIT, &IgnoreSignalAction, &OldSigQuitAction) == -1) {
+        Printf("Failed to ignore SIGQUIT\n");
+        // Try our best to restore the signal handlers.
+        (void)sigaction(SIGINT, &OldSigIntAction, NULL);
+        (void)posix_spawnattr_destroy(&SpawnAttributes);
+        return -1;
+      }
+
+      (void)sigemptyset(&BlockedSignalsSet);
+      (void)sigaddset(&BlockedSignalsSet, SIGCHLD);
+      if (sigprocmask(SIG_BLOCK, &BlockedSignalsSet, &OldBlockedSignalsSet) ==
+          -1) {
+        Printf("Failed to block SIGCHLD\n");
+        // Try our best to restore the signal handlers.
+        (void)sigaction(SIGQUIT, &OldSigQuitAction, NULL);
+        (void)sigaction(SIGINT, &OldSigIntAction, NULL);
+        (void)posix_spawnattr_destroy(&SpawnAttributes);
+        return -1;
+      }
+    }
+    ++ActiveThreadCount;
+  }
+
+  // NOTE: Do not introduce any new `return` statements past this
+  // point. It is important that `ActiveThreadCount` always be decremented
+  // when leaving this function.
+
+  // Make sure the child process uses the default handlers for the
+  // following signals rather than inheriting what the parent has.
+  sigset_t DefaultSigSet;
+  (void)sigemptyset(&DefaultSigSet);
+  (void)sigaddset(&DefaultSigSet, SIGQUIT);
+  (void)sigaddset(&DefaultSigSet, SIGINT);
+  (void)posix_spawnattr_setsigdefault(&SpawnAttributes, &DefaultSigSet);
+  // Make sure the child process doesn't block SIGCHLD
+  (void)posix_spawnattr_setsigmask(&SpawnAttributes, &OldBlockedSignalsSet);
+  short SpawnFlags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
+  (void)posix_spawnattr_setflags(&SpawnAttributes, SpawnFlags);
+
+  pid_t Pid;
+  char **Environ = environ; // Read from global
+  const char *CommandCStr = CmdLine.c_str();
+  char *const Argv[] = {
+    strdup("sh"),
+    strdup("-c"),
+    strdup(CommandCStr),
+    NULL
+  };
+  int ErrorCode = 0, ProcessStatus = 0;
+  // FIXME: We probably shouldn't hardcode the shell path.
+  ErrorCode = posix_spawn(&Pid, "/bin/sh", NULL, &SpawnAttributes,
+                          Argv, Environ);
+  (void)posix_spawnattr_destroy(&SpawnAttributes);
+  if (!ErrorCode) {
+    pid_t SavedPid = Pid;
+    do {
+      // Repeat until call completes uninterrupted.
+      Pid = waitpid(SavedPid, &ProcessStatus, /*options=*/0);
+    } while (Pid == -1 && errno == EINTR);
+    if (Pid == -1) {
+      // Fail for some other reason.
+      ProcessStatus = -1;
+    }
+  } else if (ErrorCode == ENOMEM || ErrorCode == EAGAIN) {
+    // Fork failure.
+    ProcessStatus = -1;
+  } else {
+    // Shell execution failure.
+    ProcessStatus = W_EXITCODE(127, 0);
+  }
+  for (unsigned i = 0, n = sizeof(Argv) / sizeof(Argv[0]); i < n; ++i)
+    free(Argv[i]);
+
+  // Restore the signal handlers of the current process when the last thread
+  // using this function finishes.
+  {
+    std::lock_guard<std::mutex> Lock(SignalMutex);
+    --ActiveThreadCount;
+    if (ActiveThreadCount == 0) {
+      bool FailedRestore = false;
+      if (sigaction(SIGINT, &OldSigIntAction, NULL) == -1) {
+        Printf("Failed to restore SIGINT handling\n");
+        FailedRestore = true;
+      }
+      if (sigaction(SIGQUIT, &OldSigQuitAction, NULL) == -1) {
+        Printf("Failed to restore SIGQUIT handling\n");
+        FailedRestore = true;
+      }
+      if (sigprocmask(SIG_BLOCK, &OldBlockedSignalsSet, NULL) == -1) {
+        Printf("Failed to unblock SIGCHLD\n");
+        FailedRestore = true;
+      }
+      if (FailedRestore)
+        ProcessStatus = -1;
+    }
+  }
+  return ProcessStatus;
+}
+
+void DiscardOutput(int Fd) {
+  FILE* Temp = fopen("/dev/null", "w");
+  if (!Temp)
+    return;
+  dup2(fileno(Temp), Fd);
+  fclose(Temp);
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_APPLE
diff --git a/libfuzzer/FuzzerUtilFuchsia.cpp b/libfuzzer/FuzzerUtilFuchsia.cpp
new file mode 100644
index 0000000..190fb78
--- /dev/null
+++ b/libfuzzer/FuzzerUtilFuchsia.cpp
@@ -0,0 +1,565 @@
+//===- FuzzerUtilFuchsia.cpp - Misc utils for Fuchsia. --------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Misc utils implementation using Fuchsia/Zircon APIs.
+//===----------------------------------------------------------------------===//
+#include "FuzzerPlatform.h"
+
+#if LIBFUZZER_FUCHSIA
+
+#include "FuzzerInternal.h"
+#include "FuzzerUtil.h"
+#include <cassert>
+#include <cerrno>
+#include <cinttypes>
+#include <cstdint>
+#include <fcntl.h>
+#include <lib/fdio/fdio.h>
+#include <lib/fdio/spawn.h>
+#include <string>
+#include <sys/select.h>
+#include <thread>
+#include <unistd.h>
+#include <zircon/errors.h>
+#include <zircon/process.h>
+#include <zircon/sanitizer.h>
+#include <zircon/status.h>
+#include <zircon/syscalls.h>
+#include <zircon/syscalls/debug.h>
+#include <zircon/syscalls/exception.h>
+#include <zircon/syscalls/object.h>
+#include <zircon/types.h>
+
+#include <vector>
+
+namespace fuzzer {
+
+// Given that Fuchsia doesn't have the POSIX signals that libFuzzer was written
+// around, the general approach is to spin up dedicated threads to watch for
+// each requested condition (alarm, interrupt, crash).  Of these, the crash
+// handler is the most involved, as it requires resuming the crashed thread in
+// order to invoke the sanitizers to get the needed state.
+
+// Forward declaration of assembly trampoline needed to resume crashed threads.
+// This appears to have external linkage to  C++, which is why it's not in the
+// anonymous namespace.  The assembly definition inside MakeTrampoline()
+// actually defines the symbol with internal linkage only.
+void CrashTrampolineAsm() __asm__("CrashTrampolineAsm");
+
+namespace {
+
+// Helper function to handle Zircon syscall failures.
+void ExitOnErr(zx_status_t Status, const char *Syscall) {
+  if (Status != ZX_OK) {
+    Printf("libFuzzer: %s failed: %s\n", Syscall,
+           _zx_status_get_string(Status));
+    exit(1);
+  }
+}
+
+void AlarmHandler(int Seconds) {
+  while (true) {
+    SleepSeconds(Seconds);
+    Fuzzer::StaticAlarmCallback();
+  }
+}
+
+void InterruptHandler() {
+  fd_set readfds;
+  // Ctrl-C sends ETX in Zircon.
+  do {
+    FD_ZERO(&readfds);
+    FD_SET(STDIN_FILENO, &readfds);
+    select(STDIN_FILENO + 1, &readfds, nullptr, nullptr, nullptr);
+  } while(!FD_ISSET(STDIN_FILENO, &readfds) || getchar() != 0x03);
+  Fuzzer::StaticInterruptCallback();
+}
+
+// CFAOffset is used to reference the stack pointer before entering the
+// trampoline (Stack Pointer + CFAOffset = prev Stack Pointer). Before jumping
+// to the trampoline we copy all the registers onto the stack. We need to make
+// sure that the new stack has enough space to store all the registers.
+//
+// The trampoline holds CFI information regarding the registers stored in the
+// stack, which is then used by the unwinder to restore them.
+#if defined(__x86_64__)
+// In x86_64 the crashing function might also be using the red zone (128 bytes
+// on top of their rsp).
+constexpr size_t CFAOffset = 128 + sizeof(zx_thread_state_general_regs_t);
+#elif defined(__aarch64__)
+// In aarch64 we need to always have the stack pointer aligned to 16 bytes, so we
+// make sure that we are keeping that same alignment.
+constexpr size_t CFAOffset = (sizeof(zx_thread_state_general_regs_t) + 15) & -(uintptr_t)16;
+#endif
+
+// For the crash handler, we need to call Fuzzer::StaticCrashSignalCallback
+// without POSIX signal handlers.  To achieve this, we use an assembly function
+// to add the necessary CFI unwinding information and a C function to bridge
+// from that back into C++.
+
+// FIXME: This works as a short-term solution, but this code really shouldn't be
+// architecture dependent. A better long term solution is to implement remote
+// unwinding and expose the necessary APIs through sanitizer_common and/or ASAN
+// to allow the exception handling thread to gather the crash state directly.
+//
+// Alternatively, Fuchsia may in future actually implement basic signal
+// handling for the machine trap signals.
+#if defined(__x86_64__)
+#define FOREACH_REGISTER(OP_REG, OP_NUM) \
+  OP_REG(rax)                            \
+  OP_REG(rbx)                            \
+  OP_REG(rcx)                            \
+  OP_REG(rdx)                            \
+  OP_REG(rsi)                            \
+  OP_REG(rdi)                            \
+  OP_REG(rbp)                            \
+  OP_REG(rsp)                            \
+  OP_REG(r8)                             \
+  OP_REG(r9)                             \
+  OP_REG(r10)                            \
+  OP_REG(r11)                            \
+  OP_REG(r12)                            \
+  OP_REG(r13)                            \
+  OP_REG(r14)                            \
+  OP_REG(r15)                            \
+  OP_REG(rip)
+
+#elif defined(__aarch64__)
+#define FOREACH_REGISTER(OP_REG, OP_NUM) \
+  OP_NUM(0)                              \
+  OP_NUM(1)                              \
+  OP_NUM(2)                              \
+  OP_NUM(3)                              \
+  OP_NUM(4)                              \
+  OP_NUM(5)                              \
+  OP_NUM(6)                              \
+  OP_NUM(7)                              \
+  OP_NUM(8)                              \
+  OP_NUM(9)                              \
+  OP_NUM(10)                             \
+  OP_NUM(11)                             \
+  OP_NUM(12)                             \
+  OP_NUM(13)                             \
+  OP_NUM(14)                             \
+  OP_NUM(15)                             \
+  OP_NUM(16)                             \
+  OP_NUM(17)                             \
+  OP_NUM(18)                             \
+  OP_NUM(19)                             \
+  OP_NUM(20)                             \
+  OP_NUM(21)                             \
+  OP_NUM(22)                             \
+  OP_NUM(23)                             \
+  OP_NUM(24)                             \
+  OP_NUM(25)                             \
+  OP_NUM(26)                             \
+  OP_NUM(27)                             \
+  OP_NUM(28)                             \
+  OP_NUM(29)                             \
+  OP_REG(sp)
+
+#else
+#error "Unsupported architecture for fuzzing on Fuchsia"
+#endif
+
+// Produces a CFI directive for the named or numbered register.
+// The value used refers to an assembler immediate operand with the same name
+// as the register (see ASM_OPERAND_REG).
+#define CFI_OFFSET_REG(reg) ".cfi_offset " #reg ", %c[" #reg "]\n"
+#define CFI_OFFSET_NUM(num) CFI_OFFSET_REG(x##num)
+
+// Produces an assembler immediate operand for the named or numbered register.
+// This operand contains the offset of the register relative to the CFA.
+#define ASM_OPERAND_REG(reg) \
+  [reg] "i"(offsetof(zx_thread_state_general_regs_t, reg) - CFAOffset),
+#define ASM_OPERAND_NUM(num)                                 \
+  [x##num] "i"(offsetof(zx_thread_state_general_regs_t, r[num]) - CFAOffset),
+
+// Trampoline to bridge from the assembly below to the static C++ crash
+// callback.
+__attribute__((noreturn))
+static void StaticCrashHandler() {
+  Fuzzer::StaticCrashSignalCallback();
+  for (;;) {
+    _Exit(1);
+  }
+}
+
+// Creates the trampoline with the necessary CFI information to unwind through
+// to the crashing call stack:
+//  * Defining the CFA so that it points to the stack pointer at the point
+//    of crash.
+//  * Storing all registers at the point of crash in the stack and refer to them
+//    via CFI information (relative to the CFA).
+//  * Setting the return column so the unwinder knows how to continue unwinding.
+//  * (x86_64) making sure rsp is aligned before calling StaticCrashHandler.
+//  * Calling StaticCrashHandler that will trigger the unwinder.
+//
+// The __attribute__((used)) is necessary because the function
+// is never called; it's just a container around the assembly to allow it to
+// use operands for compile-time computed constants.
+__attribute__((used))
+void MakeTrampoline() {
+  __asm__(".cfi_endproc\n"
+    ".pushsection .text.CrashTrampolineAsm\n"
+    ".type CrashTrampolineAsm,STT_FUNC\n"
+"CrashTrampolineAsm:\n"
+    ".cfi_startproc simple\n"
+    ".cfi_signal_frame\n"
+#if defined(__x86_64__)
+    ".cfi_return_column rip\n"
+    ".cfi_def_cfa rsp, %c[CFAOffset]\n"
+    FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM)
+    "mov %%rsp, %%rbp\n"
+    ".cfi_def_cfa_register rbp\n"
+    "andq $-16, %%rsp\n"
+    "call %c[StaticCrashHandler]\n"
+    "ud2\n"
+#elif defined(__aarch64__)
+    ".cfi_return_column 33\n"
+    ".cfi_def_cfa sp, %c[CFAOffset]\n"
+    FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM)
+    ".cfi_offset 33, %c[pc]\n"
+    ".cfi_offset 30, %c[lr]\n"
+    "bl %c[StaticCrashHandler]\n"
+    "brk 1\n"
+#else
+#error "Unsupported architecture for fuzzing on Fuchsia"
+#endif
+    ".cfi_endproc\n"
+    ".size CrashTrampolineAsm, . - CrashTrampolineAsm\n"
+    ".popsection\n"
+    ".cfi_startproc\n"
+    : // No outputs
+    : FOREACH_REGISTER(ASM_OPERAND_REG, ASM_OPERAND_NUM)
+#if defined(__aarch64__)
+      ASM_OPERAND_REG(pc)
+      ASM_OPERAND_REG(lr)
+#endif
+      [StaticCrashHandler] "i" (StaticCrashHandler),
+      [CFAOffset] "i" (CFAOffset));
+}
+
+void CrashHandler(zx_handle_t *Event) {
+  // This structure is used to ensure we close handles to objects we create in
+  // this handler.
+  struct ScopedHandle {
+    ~ScopedHandle() { _zx_handle_close(Handle); }
+    zx_handle_t Handle = ZX_HANDLE_INVALID;
+  };
+
+  // Create the exception channel.  We need to claim to be a "debugger" so the
+  // kernel will allow us to modify and resume dying threads (see below). Once
+  // the channel is set, we can signal the main thread to continue and wait
+  // for the exception to arrive.
+  ScopedHandle Channel;
+  zx_handle_t Self = _zx_process_self();
+  ExitOnErr(_zx_task_create_exception_channel(
+                Self, ZX_EXCEPTION_CHANNEL_DEBUGGER, &Channel.Handle),
+            "_zx_task_create_exception_channel");
+
+  ExitOnErr(_zx_object_signal(*Event, 0, ZX_USER_SIGNAL_0),
+            "_zx_object_signal");
+
+  // This thread lives as long as the process in order to keep handling
+  // crashes.  In practice, the first crashed thread to reach the end of the
+  // StaticCrashHandler will end the process.
+  while (true) {
+    ExitOnErr(_zx_object_wait_one(Channel.Handle, ZX_CHANNEL_READABLE,
+                                  ZX_TIME_INFINITE, nullptr),
+              "_zx_object_wait_one");
+
+    zx_exception_info_t ExceptionInfo;
+    ScopedHandle Exception;
+    ExitOnErr(_zx_channel_read(Channel.Handle, 0, &ExceptionInfo,
+                               &Exception.Handle, sizeof(ExceptionInfo), 1,
+                               nullptr, nullptr),
+              "_zx_channel_read");
+
+    // Ignore informational synthetic exceptions.
+    if (ZX_EXCP_THREAD_STARTING == ExceptionInfo.type ||
+        ZX_EXCP_THREAD_EXITING == ExceptionInfo.type ||
+        ZX_EXCP_PROCESS_STARTING == ExceptionInfo.type) {
+      continue;
+    }
+
+    // At this point, we want to get the state of the crashing thread, but
+    // libFuzzer and the sanitizers assume this will happen from that same
+    // thread via a POSIX signal handler. "Resurrecting" the thread in the
+    // middle of the appropriate callback is as simple as forcibly setting the
+    // instruction pointer/program counter, provided we NEVER EVER return from
+    // that function (since otherwise our stack will not be valid).
+    ScopedHandle Thread;
+    ExitOnErr(_zx_exception_get_thread(Exception.Handle, &Thread.Handle),
+              "_zx_exception_get_thread");
+
+    zx_thread_state_general_regs_t GeneralRegisters;
+    ExitOnErr(_zx_thread_read_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS,
+                                    &GeneralRegisters,
+                                    sizeof(GeneralRegisters)),
+              "_zx_thread_read_state");
+
+    // To unwind properly, we need to push the crashing thread's register state
+    // onto the stack and jump into a trampoline with CFI instructions on how
+    // to restore it.
+#if defined(__x86_64__)
+    uintptr_t StackPtr = GeneralRegisters.rsp - CFAOffset;
+    __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters,
+                         sizeof(GeneralRegisters));
+    GeneralRegisters.rsp = StackPtr;
+    GeneralRegisters.rip = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm);
+
+#elif defined(__aarch64__)
+    uintptr_t StackPtr = GeneralRegisters.sp - CFAOffset;
+    __unsanitized_memcpy(reinterpret_cast<void *>(StackPtr), &GeneralRegisters,
+                         sizeof(GeneralRegisters));
+    GeneralRegisters.sp = StackPtr;
+    GeneralRegisters.pc = reinterpret_cast<zx_vaddr_t>(CrashTrampolineAsm);
+
+#else
+#error "Unsupported architecture for fuzzing on Fuchsia"
+#endif
+
+    // Now force the crashing thread's state.
+    ExitOnErr(
+        _zx_thread_write_state(Thread.Handle, ZX_THREAD_STATE_GENERAL_REGS,
+                               &GeneralRegisters, sizeof(GeneralRegisters)),
+        "_zx_thread_write_state");
+
+    // Set the exception to HANDLED so it resumes the thread on close.
+    uint32_t ExceptionState = ZX_EXCEPTION_STATE_HANDLED;
+    ExitOnErr(_zx_object_set_property(Exception.Handle, ZX_PROP_EXCEPTION_STATE,
+                                      &ExceptionState, sizeof(ExceptionState)),
+              "zx_object_set_property");
+  }
+}
+
+} // namespace
+
+// Platform specific functions.
+void SetSignalHandler(const FuzzingOptions &Options) {
+  // Make sure information from libFuzzer and the sanitizers are easy to
+  // reassemble. `__sanitizer_log_write` has the added benefit of ensuring the
+  // DSO map is always available for the symbolizer.
+  // A uint64_t fits in 20 chars, so 64 is plenty.
+  char Buf[64];
+  memset(Buf, 0, sizeof(Buf));
+  snprintf(Buf, sizeof(Buf), "==%lu== INFO: libFuzzer starting.\n", GetPid());
+  if (EF->__sanitizer_log_write)
+    __sanitizer_log_write(Buf, sizeof(Buf));
+  Printf("%s", Buf);
+
+  // Set up alarm handler if needed.
+  if (Options.UnitTimeoutSec > 0) {
+    std::thread T(AlarmHandler, Options.UnitTimeoutSec / 2 + 1);
+    T.detach();
+  }
+
+  // Set up interrupt handler if needed.
+  if (Options.HandleInt || Options.HandleTerm) {
+    std::thread T(InterruptHandler);
+    T.detach();
+  }
+
+  // Early exit if no crash handler needed.
+  if (!Options.HandleSegv && !Options.HandleBus && !Options.HandleIll &&
+      !Options.HandleFpe && !Options.HandleAbrt)
+    return;
+
+  // Set up the crash handler and wait until it is ready before proceeding.
+  zx_handle_t Event;
+  ExitOnErr(_zx_event_create(0, &Event), "_zx_event_create");
+
+  std::thread T(CrashHandler, &Event);
+  zx_status_t Status =
+      _zx_object_wait_one(Event, ZX_USER_SIGNAL_0, ZX_TIME_INFINITE, nullptr);
+  _zx_handle_close(Event);
+  ExitOnErr(Status, "_zx_object_wait_one");
+
+  T.detach();
+}
+
+void SleepSeconds(int Seconds) {
+  _zx_nanosleep(_zx_deadline_after(ZX_SEC(Seconds)));
+}
+
+unsigned long GetPid() {
+  zx_status_t rc;
+  zx_info_handle_basic_t Info;
+  if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info,
+                                sizeof(Info), NULL, NULL)) != ZX_OK) {
+    Printf("libFuzzer: unable to get info about self: %s\n",
+           _zx_status_get_string(rc));
+    exit(1);
+  }
+  return Info.koid;
+}
+
+size_t GetPeakRSSMb() {
+  zx_status_t rc;
+  zx_info_task_stats_t Info;
+  if ((rc = _zx_object_get_info(_zx_process_self(), ZX_INFO_TASK_STATS, &Info,
+                                sizeof(Info), NULL, NULL)) != ZX_OK) {
+    Printf("libFuzzer: unable to get info about self: %s\n",
+           _zx_status_get_string(rc));
+    exit(1);
+  }
+  return (Info.mem_private_bytes + Info.mem_shared_bytes) >> 20;
+}
+
+template <typename Fn>
+class RunOnDestruction {
+ public:
+  explicit RunOnDestruction(Fn fn) : fn_(fn) {}
+  ~RunOnDestruction() { fn_(); }
+
+ private:
+  Fn fn_;
+};
+
+template <typename Fn>
+RunOnDestruction<Fn> at_scope_exit(Fn fn) {
+  return RunOnDestruction<Fn>(fn);
+}
+
+static fdio_spawn_action_t clone_fd_action(int localFd, int targetFd) {
+  return {
+      .action = FDIO_SPAWN_ACTION_CLONE_FD,
+      .fd =
+          {
+              .local_fd = localFd,
+              .target_fd = targetFd,
+          },
+  };
+}
+
+int ExecuteCommand(const Command &Cmd) {
+  zx_status_t rc;
+
+  // Convert arguments to C array
+  auto Args = Cmd.getArguments();
+  size_t Argc = Args.size();
+  assert(Argc != 0);
+  std::unique_ptr<const char *[]> Argv(new const char *[Argc + 1]);
+  for (size_t i = 0; i < Argc; ++i)
+    Argv[i] = Args[i].c_str();
+  Argv[Argc] = nullptr;
+
+  // Determine output.  On Fuchsia, the fuzzer is typically run as a component
+  // that lacks a mutable working directory. Fortunately, when this is the case
+  // a mutable output directory must be specified using "-artifact_prefix=...",
+  // so write the log file(s) there.
+  // However, we don't want to apply this logic for absolute paths.
+  int FdOut = STDOUT_FILENO;
+  bool discardStdout = false;
+  bool discardStderr = false;
+
+  if (Cmd.hasOutputFile()) {
+    std::string Path = Cmd.getOutputFile();
+    if (Path == getDevNull()) {
+      // On Fuchsia, there's no "/dev/null" like-file, so we
+      // just don't copy the FDs into the spawned process.
+      discardStdout = true;
+    } else {
+      bool IsAbsolutePath = Path.length() > 1 && Path[0] == '/';
+      if (!IsAbsolutePath && Cmd.hasFlag("artifact_prefix"))
+        Path = Cmd.getFlagValue("artifact_prefix") + "/" + Path;
+
+      FdOut = open(Path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0);
+      if (FdOut == -1) {
+        Printf("libFuzzer: failed to open %s: %s\n", Path.c_str(),
+               strerror(errno));
+        return ZX_ERR_IO;
+      }
+    }
+  }
+  auto CloseFdOut = at_scope_exit([FdOut]() {
+    if (FdOut != STDOUT_FILENO)
+      close(FdOut);
+  });
+
+  // Determine stderr
+  int FdErr = STDERR_FILENO;
+  if (Cmd.isOutAndErrCombined()) {
+    FdErr = FdOut;
+    if (discardStdout)
+      discardStderr = true;
+  }
+
+  // Clone the file descriptors into the new process
+  std::vector<fdio_spawn_action_t> SpawnActions;
+  SpawnActions.push_back(clone_fd_action(STDIN_FILENO, STDIN_FILENO));
+
+  if (!discardStdout)
+    SpawnActions.push_back(clone_fd_action(FdOut, STDOUT_FILENO));
+  if (!discardStderr)
+    SpawnActions.push_back(clone_fd_action(FdErr, STDERR_FILENO));
+
+  // Start the process.
+  char ErrorMsg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
+  zx_handle_t ProcessHandle = ZX_HANDLE_INVALID;
+  rc = fdio_spawn_etc(ZX_HANDLE_INVALID,
+                      FDIO_SPAWN_CLONE_ALL & (~FDIO_SPAWN_CLONE_STDIO), Argv[0],
+                      Argv.get(), nullptr, SpawnActions.size(),
+                      SpawnActions.data(), &ProcessHandle, ErrorMsg);
+
+  if (rc != ZX_OK) {
+    Printf("libFuzzer: failed to launch '%s': %s, %s\n", Argv[0], ErrorMsg,
+           _zx_status_get_string(rc));
+    return rc;
+  }
+  auto CloseHandle = at_scope_exit([&]() { _zx_handle_close(ProcessHandle); });
+
+  // Now join the process and return the exit status.
+  if ((rc = _zx_object_wait_one(ProcessHandle, ZX_PROCESS_TERMINATED,
+                                ZX_TIME_INFINITE, nullptr)) != ZX_OK) {
+    Printf("libFuzzer: failed to join '%s': %s\n", Argv[0],
+           _zx_status_get_string(rc));
+    return rc;
+  }
+
+  zx_info_process_t Info;
+  if ((rc = _zx_object_get_info(ProcessHandle, ZX_INFO_PROCESS, &Info,
+                                sizeof(Info), nullptr, nullptr)) != ZX_OK) {
+    Printf("libFuzzer: unable to get return code from '%s': %s\n", Argv[0],
+           _zx_status_get_string(rc));
+    return rc;
+  }
+
+  return Info.return_code;
+}
+
+bool ExecuteCommand(const Command &BaseCmd, std::string *CmdOutput) {
+  auto LogFilePath = TempPath("SimPopenOut", ".txt");
+  Command Cmd(BaseCmd);
+  Cmd.setOutputFile(LogFilePath);
+  int Ret = ExecuteCommand(Cmd);
+  *CmdOutput = FileToString(LogFilePath);
+  RemoveFile(LogFilePath);
+  return Ret == 0;
+}
+
+const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
+                         size_t PattLen) {
+  return memmem(Data, DataLen, Patt, PattLen);
+}
+
+// In fuchsia, accessing /dev/null is not supported. There's nothing
+// similar to a file that discards everything that is written to it.
+// The way of doing something similar in fuchsia is by using
+// fdio_null_create and binding that to a file descriptor.
+void DiscardOutput(int Fd) {
+  fdio_t *fdio_null = fdio_null_create();
+  if (fdio_null == nullptr) return;
+  int nullfd = fdio_bind_to_fd(fdio_null, -1, 0);
+  if (nullfd < 0) return;
+  dup2(nullfd, Fd);
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_FUCHSIA
diff --git a/libfuzzer/FuzzerUtilLinux.cpp b/libfuzzer/FuzzerUtilLinux.cpp
new file mode 100644
index 0000000..95490b9
--- /dev/null
+++ b/libfuzzer/FuzzerUtilLinux.cpp
@@ -0,0 +1,41 @@
+//===- FuzzerUtilLinux.cpp - Misc utils for Linux. ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Misc utils for Linux.
+//===----------------------------------------------------------------------===//
+#include "FuzzerPlatform.h"
+#if LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD ||                \
+    LIBFUZZER_OPENBSD || LIBFUZZER_EMSCRIPTEN
+#include "FuzzerCommand.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+
+namespace fuzzer {
+
+int ExecuteCommand(const Command &Cmd) {
+  std::string CmdLine = Cmd.toString();
+  int exit_code = system(CmdLine.c_str());
+  if (WIFEXITED(exit_code))
+    return WEXITSTATUS(exit_code);
+  return exit_code;
+}
+
+void DiscardOutput(int Fd) {
+  FILE* Temp = fopen("/dev/null", "w");
+  if (!Temp)
+    return;
+  dup2(fileno(Temp), Fd);
+  fclose(Temp);
+}
+
+} // namespace fuzzer
+
+#endif
diff --git a/libfuzzer/FuzzerUtilPosix.cpp b/libfuzzer/FuzzerUtilPosix.cpp
new file mode 100644
index 0000000..fc57b72
--- /dev/null
+++ b/libfuzzer/FuzzerUtilPosix.cpp
@@ -0,0 +1,185 @@
+//===- FuzzerUtilPosix.cpp - Misc utils for Posix. ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Misc utils implementation using Posix API.
+//===----------------------------------------------------------------------===//
+#include "FuzzerPlatform.h"
+#if LIBFUZZER_POSIX
+#include "FuzzerIO.h"
+#include "FuzzerInternal.h"
+#include "FuzzerTracePC.h"
+#include <cassert>
+#include <chrono>
+#include <cstring>
+#include <errno.h>
+#include <iomanip>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <thread>
+#include <unistd.h>
+
+namespace fuzzer {
+
+static void AlarmHandler(int, siginfo_t *, void *) {
+  Fuzzer::StaticAlarmCallback();
+}
+
+static void (*upstream_segv_handler)(int, siginfo_t *, void *);
+
+static void SegvHandler(int sig, siginfo_t *si, void *ucontext) {
+  assert(si->si_signo == SIGSEGV);
+  if (upstream_segv_handler)
+    return upstream_segv_handler(sig, si, ucontext);
+  Fuzzer::StaticCrashSignalCallback();
+}
+
+static void CrashHandler(int, siginfo_t *, void *) {
+  Fuzzer::StaticCrashSignalCallback();
+}
+
+static void InterruptHandler(int, siginfo_t *, void *) {
+  Fuzzer::StaticInterruptCallback();
+}
+
+static void GracefulExitHandler(int, siginfo_t *, void *) {
+  Fuzzer::StaticGracefulExitCallback();
+}
+
+static void FileSizeExceedHandler(int, siginfo_t *, void *) {
+  Fuzzer::StaticFileSizeExceedCallback();
+}
+
+static void SetSigaction(int signum,
+                         void (*callback)(int, siginfo_t *, void *)) {
+  struct sigaction sigact = {};
+  if (sigaction(signum, nullptr, &sigact)) {
+    Printf("libFuzzer: sigaction failed with %d\n", errno);
+    exit(1);
+  }
+  if (sigact.sa_flags & SA_SIGINFO) {
+    if (sigact.sa_sigaction) {
+      if (signum != SIGSEGV)
+        return;
+      upstream_segv_handler = sigact.sa_sigaction;
+    }
+  } else {
+    if (sigact.sa_handler != SIG_DFL && sigact.sa_handler != SIG_IGN &&
+        sigact.sa_handler != SIG_ERR)
+      return;
+  }
+
+  sigact = {};
+  sigact.sa_flags = SA_SIGINFO;
+  sigact.sa_sigaction = callback;
+  if (sigaction(signum, &sigact, 0)) {
+    Printf("libFuzzer: sigaction failed with %d\n", errno);
+    exit(1);
+  }
+}
+
+// Return true on success, false otherwise.
+bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) {
+  FILE *Pipe = popen(Cmd.toString().c_str(), "r");
+  if (!Pipe)
+    return false;
+
+  if (CmdOutput) {
+    char TmpBuffer[128];
+    while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe))
+      CmdOutput->append(TmpBuffer);
+  }
+  return pclose(Pipe) == 0;
+}
+
+void SetTimer(int Seconds) {
+  struct itimerval T {
+    {Seconds, 0}, { Seconds, 0 }
+  };
+  if (setitimer(ITIMER_REAL, &T, nullptr)) {
+    Printf("libFuzzer: setitimer failed with %d\n", errno);
+    exit(1);
+  }
+  SetSigaction(SIGALRM, AlarmHandler);
+}
+
+void SetSignalHandler(const FuzzingOptions& Options) {
+  // setitimer is not implemented in emscripten.
+  if (Options.UnitTimeoutSec > 0 && !LIBFUZZER_EMSCRIPTEN)
+    SetTimer(Options.UnitTimeoutSec / 2 + 1);
+  if (Options.HandleInt)
+    SetSigaction(SIGINT, InterruptHandler);
+  if (Options.HandleTerm)
+    SetSigaction(SIGTERM, InterruptHandler);
+  if (Options.HandleSegv)
+    SetSigaction(SIGSEGV, SegvHandler);
+  if (Options.HandleBus)
+    SetSigaction(SIGBUS, CrashHandler);
+  if (Options.HandleAbrt)
+    SetSigaction(SIGABRT, CrashHandler);
+  if (Options.HandleIll)
+    SetSigaction(SIGILL, CrashHandler);
+  if (Options.HandleFpe)
+    SetSigaction(SIGFPE, CrashHandler);
+  if (Options.HandleXfsz)
+    SetSigaction(SIGXFSZ, FileSizeExceedHandler);
+  if (Options.HandleUsr1)
+    SetSigaction(SIGUSR1, GracefulExitHandler);
+  if (Options.HandleUsr2)
+    SetSigaction(SIGUSR2, GracefulExitHandler);
+}
+
+void SleepSeconds(int Seconds) {
+  sleep(Seconds); // Use C API to avoid coverage from instrumented libc++.
+}
+
+unsigned long GetPid() { return (unsigned long)getpid(); }
+
+size_t GetPeakRSSMb() {
+  struct rusage usage;
+  if (getrusage(RUSAGE_SELF, &usage))
+    return 0;
+  if (LIBFUZZER_LINUX || LIBFUZZER_FREEBSD || LIBFUZZER_NETBSD ||
+      LIBFUZZER_OPENBSD || LIBFUZZER_EMSCRIPTEN) {
+    // ru_maxrss is in KiB
+    return usage.ru_maxrss >> 10;
+  } else if (LIBFUZZER_APPLE) {
+    // ru_maxrss is in bytes
+    return usage.ru_maxrss >> 20;
+  }
+  assert(0 && "GetPeakRSSMb() is not implemented for your platform");
+  return 0;
+}
+
+FILE *OpenProcessPipe(const char *Command, const char *Mode) {
+  return popen(Command, Mode);
+}
+
+int CloseProcessPipe(FILE *F) {
+  return pclose(F);
+}
+
+const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
+                         size_t PattLen) {
+  return memmem(Data, DataLen, Patt, PattLen);
+}
+
+std::string DisassembleCmd(const std::string &FileName) {
+  return "objdump -d " + FileName;
+}
+
+std::string SearchRegexCmd(const std::string &Regex) {
+  return "grep '" + Regex + "'";
+}
+
+}  // namespace fuzzer
+
+#endif // LIBFUZZER_POSIX
diff --git a/libfuzzer/FuzzerUtilWindows.cpp b/libfuzzer/FuzzerUtilWindows.cpp
new file mode 100644
index 0000000..6c693e3
--- /dev/null
+++ b/libfuzzer/FuzzerUtilWindows.cpp
@@ -0,0 +1,221 @@
+//===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Misc utils implementation for Windows.
+//===----------------------------------------------------------------------===//
+#include "FuzzerPlatform.h"
+#if LIBFUZZER_WINDOWS
+#include "FuzzerCommand.h"
+#include "FuzzerIO.h"
+#include "FuzzerInternal.h"
+#include <cassert>
+#include <chrono>
+#include <cstring>
+#include <errno.h>
+#include <io.h>
+#include <iomanip>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <windows.h>
+
+// This must be included after windows.h.
+#include <psapi.h>
+
+namespace fuzzer {
+
+static const FuzzingOptions* HandlerOpt = nullptr;
+
+static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
+  switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
+    case EXCEPTION_ACCESS_VIOLATION:
+    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+    case EXCEPTION_STACK_OVERFLOW:
+      if (HandlerOpt->HandleSegv)
+        Fuzzer::StaticCrashSignalCallback();
+      break;
+    case EXCEPTION_DATATYPE_MISALIGNMENT:
+    case EXCEPTION_IN_PAGE_ERROR:
+      if (HandlerOpt->HandleBus)
+        Fuzzer::StaticCrashSignalCallback();
+      break;
+    case EXCEPTION_ILLEGAL_INSTRUCTION:
+    case EXCEPTION_PRIV_INSTRUCTION:
+      if (HandlerOpt->HandleIll)
+        Fuzzer::StaticCrashSignalCallback();
+      break;
+    case EXCEPTION_FLT_DENORMAL_OPERAND:
+    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+    case EXCEPTION_FLT_INEXACT_RESULT:
+    case EXCEPTION_FLT_INVALID_OPERATION:
+    case EXCEPTION_FLT_OVERFLOW:
+    case EXCEPTION_FLT_STACK_CHECK:
+    case EXCEPTION_FLT_UNDERFLOW:
+    case EXCEPTION_INT_DIVIDE_BY_ZERO:
+    case EXCEPTION_INT_OVERFLOW:
+      if (HandlerOpt->HandleFpe)
+        Fuzzer::StaticCrashSignalCallback();
+      break;
+    // TODO: handle (Options.HandleXfsz)
+  }
+  return EXCEPTION_CONTINUE_SEARCH;
+}
+
+BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
+  switch (dwCtrlType) {
+    case CTRL_C_EVENT:
+      if (HandlerOpt->HandleInt)
+        Fuzzer::StaticInterruptCallback();
+      return TRUE;
+    case CTRL_BREAK_EVENT:
+      if (HandlerOpt->HandleTerm)
+        Fuzzer::StaticInterruptCallback();
+      return TRUE;
+  }
+  return FALSE;
+}
+
+void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
+  Fuzzer::StaticAlarmCallback();
+}
+
+class TimerQ {
+  HANDLE TimerQueue;
+ public:
+  TimerQ() : TimerQueue(NULL) {}
+  ~TimerQ() {
+    if (TimerQueue)
+      DeleteTimerQueueEx(TimerQueue, NULL);
+  }
+  void SetTimer(int Seconds) {
+    if (!TimerQueue) {
+      TimerQueue = CreateTimerQueue();
+      if (!TimerQueue) {
+        Printf("libFuzzer: CreateTimerQueue failed.\n");
+        exit(1);
+      }
+    }
+    HANDLE Timer;
+    if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
+        Seconds*1000, Seconds*1000, 0)) {
+      Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
+      exit(1);
+    }
+  }
+};
+
+static TimerQ Timer;
+
+static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
+
+void SetSignalHandler(const FuzzingOptions& Options) {
+  HandlerOpt = &Options;
+
+  if (Options.UnitTimeoutSec > 0)
+    Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
+
+  if (Options.HandleInt || Options.HandleTerm)
+    if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
+      DWORD LastError = GetLastError();
+      Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
+        LastError);
+      exit(1);
+    }
+
+  if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
+      Options.HandleFpe)
+    SetUnhandledExceptionFilter(ExceptionHandler);
+
+  if (Options.HandleAbrt)
+    if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
+      Printf("libFuzzer: signal failed with %d\n", errno);
+      exit(1);
+    }
+}
+
+void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
+
+unsigned long GetPid() { return GetCurrentProcessId(); }
+
+size_t GetPeakRSSMb() {
+  PROCESS_MEMORY_COUNTERS info;
+  if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
+    return 0;
+  return info.PeakWorkingSetSize >> 20;
+}
+
+FILE *OpenProcessPipe(const char *Command, const char *Mode) {
+  return _popen(Command, Mode);
+}
+
+int CloseProcessPipe(FILE *F) {
+  return _pclose(F);
+}
+
+int ExecuteCommand(const Command &Cmd) {
+  std::string CmdLine = Cmd.toString();
+  return system(CmdLine.c_str());
+}
+
+bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) {
+  FILE *Pipe = _popen(Cmd.toString().c_str(), "r");
+  if (!Pipe)
+    return false;
+
+  if (CmdOutput) {
+    char TmpBuffer[128];
+    while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe))
+      CmdOutput->append(TmpBuffer);
+  }
+  return _pclose(Pipe) == 0;
+}
+
+const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
+                         size_t PattLen) {
+  // TODO: make this implementation more efficient.
+  const char *Cdata = (const char *)Data;
+  const char *Cpatt = (const char *)Patt;
+
+  if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
+    return NULL;
+
+  if (PattLen == 1)
+    return memchr(Data, *Cpatt, DataLen);
+
+  const char *End = Cdata + DataLen - PattLen + 1;
+
+  for (const char *It = Cdata; It < End; ++It)
+    if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
+      return It;
+
+  return NULL;
+}
+
+std::string DisassembleCmd(const std::string &FileName) {
+  Vector<std::string> command_vector;
+  command_vector.push_back("dumpbin /summary > nul");
+  if (ExecuteCommand(Command(command_vector)) == 0)
+    return "dumpbin /disasm " + FileName;
+  Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
+  exit(1);
+}
+
+std::string SearchRegexCmd(const std::string &Regex) {
+  return "findstr /r \"" + Regex + "\"";
+}
+
+void DiscardOutput(int Fd) {
+  FILE* Temp = fopen("nul", "w");
+  if (!Temp)
+    return;
+  _dup2(_fileno(Temp), Fd);
+  fclose(Temp);
+}
+
+} // namespace fuzzer
+
+#endif // LIBFUZZER_WINDOWS
diff --git a/libfuzzer/FuzzerValueBitMap.h b/libfuzzer/FuzzerValueBitMap.h
new file mode 100644
index 0000000..ddbfe20
--- /dev/null
+++ b/libfuzzer/FuzzerValueBitMap.h
@@ -0,0 +1,73 @@
+//===- FuzzerValueBitMap.h - INTERNAL - Bit map -----------------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// ValueBitMap.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_VALUE_BIT_MAP_H
+#define LLVM_FUZZER_VALUE_BIT_MAP_H
+
+#include "FuzzerPlatform.h"
+#include <cstdint>
+
+namespace fuzzer {
+
+// A bit map containing kMapSizeInWords bits.
+struct ValueBitMap {
+  static const size_t kMapSizeInBits = 1 << 16;
+  static const size_t kMapPrimeMod = 65371;  // Largest Prime < kMapSizeInBits;
+  static const size_t kBitsInWord = (sizeof(uintptr_t) * 8);
+  static const size_t kMapSizeInWords = kMapSizeInBits / kBitsInWord;
+ public:
+
+  // Clears all bits.
+  void Reset() { memset(Map, 0, sizeof(Map)); }
+
+  // Computes a hash function of Value and sets the corresponding bit.
+  // Returns true if the bit was changed from 0 to 1.
+  ATTRIBUTE_NO_SANITIZE_ALL
+  inline bool AddValue(uintptr_t Value) {
+    uintptr_t Idx = Value % kMapSizeInBits;
+    uintptr_t WordIdx = Idx / kBitsInWord;
+    uintptr_t BitIdx = Idx % kBitsInWord;
+    uintptr_t Old = Map[WordIdx];
+    uintptr_t New = Old | (1ULL << BitIdx);
+    Map[WordIdx] = New;
+    return New != Old;
+  }
+
+  ATTRIBUTE_NO_SANITIZE_ALL
+  inline bool AddValueModPrime(uintptr_t Value) {
+    return AddValue(Value % kMapPrimeMod);
+  }
+
+  inline bool Get(uintptr_t Idx) {
+    assert(Idx < kMapSizeInBits);
+    uintptr_t WordIdx = Idx / kBitsInWord;
+    uintptr_t BitIdx = Idx % kBitsInWord;
+    return Map[WordIdx] & (1ULL << BitIdx);
+  }
+
+  size_t SizeInBits() const { return kMapSizeInBits; }
+
+  template <class Callback>
+  ATTRIBUTE_NO_SANITIZE_ALL
+  void ForEach(Callback CB) const {
+    for (size_t i = 0; i < kMapSizeInWords; i++)
+      if (uintptr_t M = Map[i])
+        for (size_t j = 0; j < sizeof(M) * 8; j++)
+          if (M & ((uintptr_t)1 << j))
+            CB(i * sizeof(M) * 8 + j);
+  }
+
+ private:
+  ATTRIBUTE_ALIGNED(512) uintptr_t Map[kMapSizeInWords];
+};
+
+}  // namespace fuzzer
+
+#endif  // LLVM_FUZZER_VALUE_BIT_MAP_H
diff --git a/libfuzzer/README.txt b/libfuzzer/README.txt
new file mode 100644
index 0000000..3eee01c
--- /dev/null
+++ b/libfuzzer/README.txt
@@ -0,0 +1 @@
+See http://llvm.org/docs/LibFuzzer.html
diff --git a/libfuzzer/afl/afl_driver.cpp b/libfuzzer/afl/afl_driver.cpp
new file mode 100644
index 0000000..457f180
--- /dev/null
+++ b/libfuzzer/afl/afl_driver.cpp
@@ -0,0 +1,277 @@
+//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//===----------------------------------------------------------------------===//
+
+/* 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 <stddef.h>
+#include <stdint.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-guard using fresh clang.
+clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c
+# Build afl-llvm-rt.o.c from the AFL distribution.
+clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c
+# Build this file, link it with afl-llvm-rt.o.o and the target code.
+clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
+# Run AFL:
+rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
+$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
+################################################################################
+AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file
+specified. If the file does not exist, it is created. This is useful for getting
+stack traces (when using ASAN for example) or original error messages on hard
+to reproduce bugs. Note that any content written to stderr will be written to
+this file instead of stderr's usual location.
+
+AFL_DRIVER_CLOSE_FD_MASK: Similar to libFuzzer's -close_fd_mask behavior option.
+If 1, close stdout at startup. If 2 close stderr; if 3 close both.
+
+*/
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+// Platform detection. Copied from FuzzerInternal.h
+#ifdef __linux__
+#define LIBFUZZER_LINUX 1
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 0
+#define LIBFUZZER_OPENBSD 0
+#elif __APPLE__
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_APPLE 1
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 0
+#define LIBFUZZER_OPENBSD 0
+#elif __NetBSD__
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_NETBSD 1
+#define LIBFUZZER_FREEBSD 0
+#define LIBFUZZER_OPENBSD 0
+#elif __FreeBSD__
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 1
+#define LIBFUZZER_OPENBSD 0
+#elif __OpenBSD__
+#define LIBFUZZER_LINUX 0
+#define LIBFUZZER_APPLE 0
+#define LIBFUZZER_NETBSD 0
+#define LIBFUZZER_FREEBSD 0
+#define LIBFUZZER_OPENBSD 1
+#else
+#error "Support for your platform has not been implemented"
+#endif
+
+// 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];
+
+// Use this optionally defined function to output sanitizer messages even if
+// user asks to close stderr.
+extern "C" __attribute__((weak)) void __sanitizer_set_report_fd(void *);
+
+// Keep track of where stderr content is being written to, so that
+// dup_and_close_stderr can use the correct one.
+static FILE *output_file = stderr;
+
+// Experimental feature to use afl_driver without AFL's deferred mode.
+// Needs to run before __afl_auto_init.
+__attribute__((constructor(0))) static void __decide_deferred_forkserver(void) {
+  if (getenv("AFL_DRIVER_DONT_DEFER")) {
+    if (unsetenv("__AFL_DEFER_FORKSRV")) {
+      perror("Failed to unset __AFL_DEFER_FORKSRV");
+      abort();
+    }
+  }
+}
+
+// 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();
+  }
+  output_file = stderr_duplicate_stream;
+}
+
+// Most of these I/O functions were inspired by/copied from libFuzzer's code.
+static void discard_output(int fd) {
+  FILE *temp = fopen("/dev/null", "w");
+  if (!temp)
+    abort();
+  dup2(fileno(temp), fd);
+  fclose(temp);
+}
+
+static void close_stdout() { discard_output(STDOUT_FILENO); }
+
+// Prevent the targeted code from writing to "stderr" but allow sanitizers and
+// this driver to do so.
+static void dup_and_close_stderr() {
+  int output_fileno = fileno(output_file);
+  int output_fd = dup(output_fileno);
+  if (output_fd <= 0)
+    abort();
+  FILE *new_output_file = fdopen(output_fd, "w");
+  if (!new_output_file)
+    abort();
+  if (!__sanitizer_set_report_fd)
+    return;
+  __sanitizer_set_report_fd(reinterpret_cast<void *>(output_fd));
+  discard_output(output_fileno);
+}
+
+static void Printf(const char *Fmt, ...) {
+  va_list ap;
+  va_start(ap, Fmt);
+  vfprintf(output_file, Fmt, ap);
+  va_end(ap);
+  fflush(output_file);
+}
+
+// Close stdout and/or stderr if user asks for it.
+static void maybe_close_fd_mask() {
+  char *fd_mask_str = getenv("AFL_DRIVER_CLOSE_FD_MASK");
+  if (!fd_mask_str)
+    return;
+  int fd_mask = atoi(fd_mask_str);
+  if (fd_mask & 2)
+    dup_and_close_stderr();
+  if (fd_mask & 1)
+    close_stdout();
+}
+
+// Define LLVMFuzzerMutate to avoid link failures for targets that use it
+// with libFuzzer's LLVMFuzzerCustomMutator.
+extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+  assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
+  return 0;
+}
+
+// Execute any files provided as parameters.
+static int ExecuteFilesOnyByOne(int argc, char **argv) {
+  for (int i = 1; i < argc; i++) {
+    std::ifstream in(argv[i], std::ios::binary);
+    in.seekg(0, in.end);
+    size_t length = in.tellg();
+    in.seekg (0, in.beg);
+    std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
+    // Allocate exactly length bytes so that we reliably catch buffer overflows.
+    std::vector<char> bytes(length);
+    in.read(bytes.data(), bytes.size());
+    assert(in);
+    LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
+                           bytes.size());
+    std::cout << "Execution successful" << std::endl;
+  }
+  return 0;
+}
+
+int main(int argc, char **argv) {
+  Printf(
+      "======================= INFO =========================\n"
+      "This binary is built for AFL-fuzz.\n"
+      "To run the target function on individual input(s) execute this:\n"
+      "  %s < INPUT_FILE\n"
+      "or\n"
+      "  %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"
+      "To fuzz with afl-fuzz execute this:\n"
+      "  afl-fuzz [afl-flags] %s [-N]\n"
+      "afl-fuzz will run N iterations before "
+      "re-spawning the process (default: 1000)\n"
+      "======================================================\n",
+          argv[0], argv[0], argv[0]);
+
+  maybe_duplicate_stderr();
+  maybe_close_fd_mask();
+  if (LLVMFuzzerInitialize)
+    LLVMFuzzerInitialize(&argc, &argv);
+  // Do any other expensive one-time initialization here.
+
+  if (!getenv("AFL_DRIVER_DONT_DEFER"))
+    __afl_manual_init();
+
+  int N = 1000;
+  if (argc == 2 && argv[1][0] == '-')
+      N = atoi(argv[1] + 1);
+  else if(argc == 2 && (N = atoi(argv[1])) > 0)
+      Printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N);
+  else if (argc > 1)
+    return ExecuteFilesOnyByOne(argc, argv);
+
+  assert(N > 0);
+
+  // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
+  // on the first execution of LLVMFuzzerTestOneInput is ignored.
+  uint8_t dummy_input[1] = {0};
+  LLVMFuzzerTestOneInput(dummy_input, 1);
+
+  int num_runs = 0;
+  while (__afl_persistent_loop(N)) {
+    ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
+    if (n_read > 0) {
+      // Copy AflInputBuf into a separate buffer to let asan find buffer
+      // overflows. Don't use unique_ptr/etc to avoid extra dependencies.
+      uint8_t *copy = new uint8_t[n_read];
+      memcpy(copy, AflInputBuf, n_read);
+      num_runs++;
+      LLVMFuzzerTestOneInput(copy, n_read);
+      delete[] copy;
+    }
+  }
+  Printf("%s: successfully executed %d input(s)\n", argv[0], num_runs);
+}
diff --git a/libfuzzer/build.sh b/libfuzzer/build.sh
new file mode 100755
index 0000000..504e54e
--- /dev/null
+++ b/libfuzzer/build.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+LIBFUZZER_SRC_DIR=$(dirname $0)
+CXX="${CXX:-clang}"
+for f in $LIBFUZZER_SRC_DIR/*.cpp; do
+  $CXX -g -O2 -fno-omit-frame-pointer -std=c++11 $f -c &
+done
+wait
+rm -f libFuzzer.a
+ar ru libFuzzer.a Fuzzer*.o
+rm -f Fuzzer*.o
+
diff --git a/libfuzzer/dataflow/DataFlow.cpp b/libfuzzer/dataflow/DataFlow.cpp
new file mode 100644
index 0000000..8bf4e25
--- /dev/null
+++ b/libfuzzer/dataflow/DataFlow.cpp
@@ -0,0 +1,205 @@
+/*===- DataFlow.cpp - a standalone DataFlow tracer                  -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// An experimental data-flow tracer for fuzz targets.
+// It is based on DFSan and SanitizerCoverage.
+// https://clang.llvm.org/docs/DataFlowSanitizer.html
+// https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-data-flow
+//
+// It executes the fuzz target on the given input while monitoring the
+// data flow for every instrumented comparison instruction.
+//
+// The output shows which functions depend on which bytes of the input,
+// and also provides basic-block coverage for every input.
+//
+// Build:
+//   1. Compile this file (DataFlow.cpp) with -fsanitize=dataflow and -O2.
+//   2. Compile DataFlowCallbacks.cpp with -O2 -fPIC.
+//   3. Build the fuzz target with -g -fsanitize=dataflow
+//       -fsanitize-coverage=trace-pc-guard,pc-table,bb,trace-cmp
+//   4. Link those together with -fsanitize=dataflow
+//
+//  -fsanitize-coverage=trace-cmp inserts callbacks around every comparison
+//  instruction, DFSan modifies the calls to pass the data flow labels.
+//  The callbacks update the data flow label for the current function.
+//  See e.g. __dfsw___sanitizer_cov_trace_cmp1 below.
+//
+//  -fsanitize-coverage=trace-pc-guard,pc-table,bb instruments function
+//  entries so that the comparison callback knows that current function.
+//  -fsanitize-coverage=...,bb also allows to collect basic block coverage.
+//
+//
+// Run:
+//   # Collect data flow and coverage for INPUT_FILE
+//   # write to OUTPUT_FILE (default: stdout)
+//   export DFSAN_OPTIONS=fast16labels=1:warn_unimplemented=0
+//   ./a.out INPUT_FILE [OUTPUT_FILE]
+//
+//   # Print all instrumented functions. llvm-symbolizer must be present in PATH
+//   ./a.out
+//
+// Example output:
+// ===============
+//  F0 11111111111111
+//  F1 10000000000000
+//  C0 1 2 3 4 5
+//  C1 8
+//  ===============
+// "FN xxxxxxxxxx": tells what bytes of the input does the function N depend on.
+// "CN X Y Z T": tells that a function N has basic blocks X, Y, and Z covered
+//    in addition to the function's entry block, out of T total instrumented
+//    blocks.
+//
+//===----------------------------------------------------------------------===*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <execinfo.h>  // backtrace_symbols_fd
+
+#include "DataFlow.h"
+
+extern "C" {
+extern int LLVMFuzzerTestOneInput(const unsigned char *Data, size_t Size);
+__attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv);
+} // extern "C"
+
+CallbackData __dft;
+static size_t InputLen;
+static size_t NumIterations;
+static dfsan_label **FuncLabelsPerIter;  // NumIterations x NumFuncs;
+
+static inline bool BlockIsEntry(size_t BlockIdx) {
+  return __dft.PCsBeg[BlockIdx * 2 + 1] & PCFLAG_FUNC_ENTRY;
+}
+
+const int kNumLabels = 16;
+
+// Prints all instrumented functions.
+static int PrintFunctions() {
+  // We don't have the symbolizer integrated with dfsan yet.
+  // So use backtrace_symbols_fd and pipe it through llvm-symbolizer.
+  // TODO(kcc): this is pretty ugly and may break in lots of ways.
+  //      We'll need to make a proper in-process symbolizer work with DFSan.
+  FILE *Pipe = popen("sed 's/(+/ /g; s/).*//g' "
+                     "| llvm-symbolizer "
+                     "| grep 'dfs\\$' "
+                     "| sed 's/dfs\\$//g' "
+                     "| c++filt",
+                     "w");
+  for (size_t I = 0; I < __dft.NumGuards; I++) {
+    uintptr_t PC = __dft.PCsBeg[I * 2];
+    if (!BlockIsEntry(I)) continue;
+    void *const Buf[1] = {(void*)PC};
+    backtrace_symbols_fd(Buf, 1, fileno(Pipe));
+  }
+  pclose(Pipe);
+  return 0;
+}
+
+static void PrintBinary(FILE *Out, dfsan_label L, size_t Len) {
+  char buf[kNumLabels + 1];
+  assert(Len <= kNumLabels);
+  for (int i = 0; i < kNumLabels; i++)
+    buf[i] = (L & (1 << i)) ? '1' : '0';
+  buf[Len] = 0;
+  fprintf(Out, "%s", buf);
+}
+
+static void PrintDataFlow(FILE *Out) {
+  for (size_t Func = 0; Func < __dft.NumFuncs; Func++) {
+    bool HasAny = false;
+    for (size_t Iter = 0; Iter < NumIterations; Iter++)
+      if (FuncLabelsPerIter[Iter][Func])
+        HasAny = true;
+    if (!HasAny)
+      continue;
+    fprintf(Out, "F%zd ", Func);
+    size_t LenOfLastIteration = kNumLabels;
+    if (auto Tail = InputLen % kNumLabels)
+        LenOfLastIteration = Tail;
+    for (size_t Iter = 0; Iter < NumIterations; Iter++)
+      PrintBinary(Out, FuncLabelsPerIter[Iter][Func],
+                  Iter == NumIterations - 1 ? LenOfLastIteration : kNumLabels);
+    fprintf(Out, "\n");
+  }
+}
+
+static void PrintCoverage(FILE *Out) {
+  ssize_t CurrentFuncGuard = -1;
+  ssize_t CurrentFuncNum = -1;
+  ssize_t NumBlocksInCurrentFunc = -1;
+  for (size_t FuncBeg = 0; FuncBeg < __dft.NumGuards;) {
+    CurrentFuncNum++;
+    assert(BlockIsEntry(FuncBeg));
+    size_t FuncEnd = FuncBeg + 1;
+    for (; FuncEnd < __dft.NumGuards && !BlockIsEntry(FuncEnd); FuncEnd++)
+      ;
+    if (__dft.BBExecuted[FuncBeg]) {
+      fprintf(Out, "C%zd", CurrentFuncNum);
+      for (size_t I = FuncBeg + 1; I < FuncEnd; I++)
+        if (__dft.BBExecuted[I])
+          fprintf(Out, " %zd", I - FuncBeg);
+      fprintf(Out, " %zd\n", FuncEnd - FuncBeg);
+    }
+    FuncBeg = FuncEnd;
+  }
+}
+
+int main(int argc, char **argv) {
+  if (LLVMFuzzerInitialize)
+    LLVMFuzzerInitialize(&argc, &argv);
+  if (argc == 1)
+    return PrintFunctions();
+  assert(argc == 2 || argc == 3);
+
+  const char *Input = argv[1];
+  fprintf(stderr, "INFO: reading '%s'\n", Input);
+  FILE *In = fopen(Input, "r");
+  assert(In);
+  fseek(In, 0, SEEK_END);
+  InputLen = ftell(In);
+  fseek(In, 0, SEEK_SET);
+  unsigned char *Buf = (unsigned char*)malloc(InputLen);
+  size_t NumBytesRead = fread(Buf, 1, InputLen, In);
+  assert(NumBytesRead == InputLen);
+  fclose(In);
+
+  NumIterations = (NumBytesRead + kNumLabels - 1) / kNumLabels;
+  FuncLabelsPerIter =
+      (dfsan_label **)calloc(NumIterations, sizeof(dfsan_label *));
+  for (size_t Iter = 0; Iter < NumIterations; Iter++)
+    FuncLabelsPerIter[Iter] =
+        (dfsan_label *)calloc(__dft.NumFuncs, sizeof(dfsan_label));
+
+  for (size_t Iter = 0; Iter < NumIterations; Iter++) {
+    fprintf(stderr, "INFO: running '%s' %zd/%zd\n", Input, Iter, NumIterations);
+    dfsan_flush();
+    dfsan_set_label(0, Buf, InputLen);
+    __dft.FuncLabels = FuncLabelsPerIter[Iter];
+
+    size_t BaseIdx = Iter * kNumLabels;
+    size_t LastIdx = BaseIdx + kNumLabels < NumBytesRead ? BaseIdx + kNumLabels
+                                                         : NumBytesRead;
+    assert(BaseIdx < LastIdx);
+    for (size_t Idx = BaseIdx; Idx < LastIdx; Idx++)
+      dfsan_set_label(1 << (Idx - BaseIdx), Buf + Idx, 1);
+    LLVMFuzzerTestOneInput(Buf, InputLen);
+  }
+  free(Buf);
+
+  bool OutIsStdout = argc == 2;
+  fprintf(stderr, "INFO: writing dataflow to %s\n",
+          OutIsStdout ? "<stdout>" : argv[2]);
+  FILE *Out = OutIsStdout ? stdout : fopen(argv[2], "w");
+  PrintDataFlow(Out);
+  PrintCoverage(Out);
+  if (!OutIsStdout) fclose(Out);
+}
diff --git a/libfuzzer/dataflow/DataFlow.h b/libfuzzer/dataflow/DataFlow.h
new file mode 100644
index 0000000..35849fd
--- /dev/null
+++ b/libfuzzer/dataflow/DataFlow.h
@@ -0,0 +1,32 @@
+/*===- DataFlow.h - a standalone DataFlow trace                     -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Internal header file to connect DataFlow.cpp and DataFlowCallbacks.cpp.
+//===----------------------------------------------------------------------===*/
+
+#ifndef __LIBFUZZER_DATAFLOW_H
+#define __LIBFUZZER_DATAFLOW_H
+
+#include <cstddef>
+#include <cstdint>
+#include <sanitizer/dfsan_interface.h>
+
+// This data is shared between DataFlowCallbacks.cpp and DataFlow.cpp.
+struct CallbackData {
+  size_t NumFuncs, NumGuards;
+  const uintptr_t *PCsBeg, *PCsEnd;
+  dfsan_label *FuncLabels;  // Array of NumFuncs elements.
+  bool *BBExecuted;         // Array of NumGuards elements.
+};
+
+extern CallbackData __dft;
+
+enum {
+  PCFLAG_FUNC_ENTRY = 1,
+};
+
+#endif  // __LIBFUZZER_DATAFLOW_H
diff --git a/libfuzzer/dataflow/DataFlowCallbacks.cpp b/libfuzzer/dataflow/DataFlowCallbacks.cpp
new file mode 100644
index 0000000..170b4d8
--- /dev/null
+++ b/libfuzzer/dataflow/DataFlowCallbacks.cpp
@@ -0,0 +1,86 @@
+/*===- DataFlowCallbacks.cpp - a standalone DataFlow trace          -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Instrumentation callbacks for DataFlow.cpp.
+// These functions should not be instrumented by DFSan, so we
+// keep them in a separate file and compile it w/o DFSan.
+//===----------------------------------------------------------------------===*/
+#include "DataFlow.h"
+
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+
+static __thread size_t CurrentFunc;
+static uint32_t *GuardsBeg, *GuardsEnd;
+static inline bool BlockIsEntry(size_t BlockIdx) {
+  return __dft.PCsBeg[BlockIdx * 2 + 1] & PCFLAG_FUNC_ENTRY;
+}
+
+extern "C" {
+
+void __sanitizer_cov_trace_pc_guard_init(uint32_t *start,
+                                         uint32_t *stop) {
+  assert(__dft.NumFuncs == 0 && "This tool does not support DSOs");
+  assert(start < stop && "The code is not instrumented for coverage");
+  if (start == stop || *start) return;  // Initialize only once.
+  GuardsBeg = start;
+  GuardsEnd = stop;
+}
+
+void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
+                              const uintptr_t *pcs_end) {
+  if (__dft.NumGuards) return;  // Initialize only once.
+  __dft.NumGuards = GuardsEnd - GuardsBeg;
+  __dft.PCsBeg = pcs_beg;
+  __dft.PCsEnd = pcs_end;
+  assert(__dft.NumGuards == (__dft.PCsEnd - __dft.PCsBeg) / 2);
+  for (size_t i = 0; i < __dft.NumGuards; i++) {
+    if (BlockIsEntry(i)) {
+      __dft.NumFuncs++;
+      GuardsBeg[i] = __dft.NumFuncs;
+    }
+  }
+  __dft.BBExecuted = (bool*)calloc(__dft.NumGuards, sizeof(bool));
+  fprintf(stderr, "INFO: %zd instrumented function(s) observed "
+          "and %zd basic blocks\n", __dft.NumFuncs, __dft.NumGuards);
+}
+
+void __sanitizer_cov_trace_pc_indir(uint64_t x){}  // unused.
+
+void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
+  size_t GuardIdx = guard - GuardsBeg;
+  // assert(GuardIdx < __dft.NumGuards);
+  __dft.BBExecuted[GuardIdx] = true;
+  if (!*guard) return;  // not a function entry.
+  uint32_t FuncNum = *guard - 1;  // Guards start from 1.
+  // assert(FuncNum < __dft.NumFuncs);
+  CurrentFunc = FuncNum;
+}
+
+void __dfsw___sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases,
+                                         dfsan_label L1, dfsan_label UnusedL) {
+  assert(CurrentFunc < __dft.NumFuncs);
+  __dft.FuncLabels[CurrentFunc] |= L1;
+}
+
+#define HOOK(Name, Type)                                                       \
+  void Name(Type Arg1, Type Arg2, dfsan_label L1, dfsan_label L2) {            \
+    __dft.FuncLabels[CurrentFunc] |= L1 | L2;                                  \
+  }
+    //assert(CurrentFunc < __dft.NumFuncs);
+
+HOOK(__dfsw___sanitizer_cov_trace_const_cmp1, uint8_t)
+HOOK(__dfsw___sanitizer_cov_trace_const_cmp2, uint16_t)
+HOOK(__dfsw___sanitizer_cov_trace_const_cmp4, uint32_t)
+HOOK(__dfsw___sanitizer_cov_trace_const_cmp8, uint64_t)
+HOOK(__dfsw___sanitizer_cov_trace_cmp1, uint8_t)
+HOOK(__dfsw___sanitizer_cov_trace_cmp2, uint16_t)
+HOOK(__dfsw___sanitizer_cov_trace_cmp4, uint32_t)
+HOOK(__dfsw___sanitizer_cov_trace_cmp8, uint64_t)
+
+} // extern "C"
diff --git a/libfuzzer/scripts/unbalanced_allocs.py b/libfuzzer/scripts/unbalanced_allocs.py
new file mode 100755
index 0000000..579e481
--- /dev/null
+++ b/libfuzzer/scripts/unbalanced_allocs.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+#===- lib/fuzzer/scripts/unbalanced_allocs.py ------------------------------===#
+#
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#
+#===------------------------------------------------------------------------===#
+#
+# Post-process -trace_malloc=2 output and printout only allocations and frees
+# unbalanced inside of fuzzer runs.
+# Usage:
+#   my_fuzzer -trace_malloc=2 -runs=10 2>&1 | unbalanced_allocs.py -skip=5
+#
+#===------------------------------------------------------------------------===#
+
+import argparse
+import sys
+
+_skip = 0
+
+def PrintStack(line, stack):
+  global _skip
+  if _skip > 0:
+    return
+  print('Unbalanced ' + line.rstrip());
+  for l in stack:
+    print(l.rstrip())
+
+def ProcessStack(line, f):
+  stack = []
+  while line and line.startswith('    #'):
+    stack += [line]
+    line = f.readline()
+  return line, stack
+
+def ProcessFree(line, f, allocs):
+  if not line.startswith('FREE['):
+    return f.readline()
+
+  addr = int(line.split()[1], 16)
+  next_line, stack = ProcessStack(f.readline(), f)
+  if addr in allocs:
+    del allocs[addr]
+  else:
+    PrintStack(line, stack)
+  return next_line
+
+def ProcessMalloc(line, f, allocs):
+  if not line.startswith('MALLOC['):
+    return ProcessFree(line, f, allocs)
+
+  addr = int(line.split()[1], 16)
+  assert not addr in allocs
+
+  next_line, stack = ProcessStack(f.readline(), f)
+  allocs[addr] = (line, stack)
+  return next_line
+
+def ProcessRun(line, f):
+  if not line.startswith('MallocFreeTracer: START'):
+    return ProcessMalloc(line, f, {})
+
+  allocs = {}
+  print(line.rstrip())
+  line = f.readline()
+  while line:
+    if line.startswith('MallocFreeTracer: STOP'):
+      global _skip
+      _skip = _skip - 1
+      for _, (l, s) in allocs.items():
+        PrintStack(l, s)
+      print(line.rstrip())
+      return f.readline()
+    line = ProcessMalloc(line, f, allocs)
+  return line
+
+def ProcessFile(f):
+  line = f.readline()
+  while line:
+    line = ProcessRun(line, f);
+
+def main(argv):
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--skip', default=0, help='number of runs to ignore')
+  args = parser.parse_args()
+  global _skip
+  _skip = int(args.skip) + 1
+  ProcessFile(sys.stdin)
+
+if __name__ == '__main__':
+  main(sys.argv)
diff --git a/libfuzzer/standalone/StandaloneFuzzTargetMain.c b/libfuzzer/standalone/StandaloneFuzzTargetMain.c
new file mode 100644
index 0000000..efe512c
--- /dev/null
+++ b/libfuzzer/standalone/StandaloneFuzzTargetMain.c
@@ -0,0 +1,41 @@
+/*===- StandaloneFuzzTargetMain.c - standalone main() for fuzz targets. ---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// This main() function can be linked to a fuzz target (i.e. a library
+// that exports LLVMFuzzerTestOneInput() and possibly LLVMFuzzerInitialize())
+// instead of libFuzzer. This main() function will not perform any fuzzing
+// but will simply feed all input files one by one to the fuzz target.
+//
+// Use this file to provide reproducers for bugs when linking against libFuzzer
+// or other fuzzing engine is undesirable.
+//===----------------------------------------------------------------------===*/
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
+__attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv);
+int main(int argc, char **argv) {
+  fprintf(stderr, "StandaloneFuzzTargetMain: running %d inputs\n", argc - 1);
+  if (LLVMFuzzerInitialize)
+    LLVMFuzzerInitialize(&argc, &argv);
+  for (int i = 1; i < argc; i++) {
+    fprintf(stderr, "Running: %s\n", argv[i]);
+    FILE *f = fopen(argv[i], "r");
+    assert(f);
+    fseek(f, 0, SEEK_END);
+    size_t len = ftell(f);
+    fseek(f, 0, SEEK_SET);
+    unsigned char *buf = (unsigned char*)malloc(len);
+    size_t n_read = fread(buf, 1, len, f);
+    fclose(f);
+    assert(n_read == len);
+    LLVMFuzzerTestOneInput(buf, len);
+    free(buf);
+    fprintf(stderr, "Done:    %s: (%zd bytes)\n", argv[i], n_read);
+  }
+}
diff --git a/libfuzzer/tests/CMakeLists.txt b/libfuzzer/tests/CMakeLists.txt
new file mode 100644
index 0000000..cfb039c
--- /dev/null
+++ b/libfuzzer/tests/CMakeLists.txt
@@ -0,0 +1,87 @@
+include(CompilerRTCompile)
+
+set(LIBFUZZER_UNITTEST_CFLAGS
+  ${COMPILER_RT_UNITTEST_CFLAGS}
+  ${COMPILER_RT_GTEST_CFLAGS}
+  -I${COMPILER_RT_SOURCE_DIR}/lib/fuzzer
+  -fno-rtti
+  -O2)
+
+if (APPLE)
+  set(FUZZER_SUPPORTED_OS osx)
+endif()
+
+add_custom_target(FuzzerUnitTests)
+set_target_properties(FuzzerUnitTests PROPERTIES FOLDER "Compiler-RT Tests")
+
+add_custom_target(FuzzedDataProviderUnitTests)
+set_target_properties(FuzzedDataProviderUnitTests PROPERTIES FOLDER "Compiler-RT Tests")
+
+set(LIBFUZZER_UNITTEST_LINK_FLAGS ${COMPILER_RT_UNITTEST_LINK_FLAGS})
+list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS --driver-mode=g++)
+
+if(WIN32)
+  list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -Wl,-defaultlib:libcmt,-defaultlib:oldnames)
+else()
+  list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lpthread)
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND
+   COMPILER_RT_LIBCXX_PATH AND
+   COMPILER_RT_LIBCXXABI_PATH)
+  list(APPEND LIBFUZZER_UNITTEST_CFLAGS -nostdinc++)
+endif()
+
+if ("-fvisibility=hidden" IN_LIST LIBFUZZER_CFLAGS)
+  # Match visibility settings.
+  list(APPEND LIBFUZZER_UNITTEST_CFLAGS "-fvisibility=hidden")
+endif()
+
+if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST FUZZER_SUPPORTED_ARCH)
+  # libFuzzer unit tests are only run on the host machine.
+  set(arch ${COMPILER_RT_DEFAULT_TARGET_ARCH})
+
+  set(LIBFUZZER_TEST_RUNTIME RTFuzzerTest.${arch})
+  if(APPLE)
+    set(LIBFUZZER_TEST_RUNTIME_OBJECTS
+      $<TARGET_OBJECTS:RTfuzzer.osx>)
+  else()
+    set(LIBFUZZER_TEST_RUNTIME_OBJECTS
+      $<TARGET_OBJECTS:RTfuzzer.${arch}>)
+  endif()
+  add_library(${LIBFUZZER_TEST_RUNTIME} STATIC
+    ${LIBFUZZER_TEST_RUNTIME_OBJECTS})
+  set_target_properties(${LIBFUZZER_TEST_RUNTIME} PROPERTIES
+    ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+    FOLDER "Compiler-RT Runtime tests")
+
+  if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND
+     COMPILER_RT_LIBCXX_PATH AND
+     COMPILER_RT_LIBCXXABI_PATH)
+    file(GLOB libfuzzer_headers ../*.h)
+    set(LIBFUZZER_TEST_RUNTIME_DEPS libcxx_fuzzer_${arch}-build ${libfuzzer_headers})
+    set(LIBFUZZER_TEST_RUNTIME_CFLAGS -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
+    set(LIBFUZZER_TEST_RUNTIME_LINK_FLAGS ${LIBCXX_${arch}_PREFIX}/lib/libc++.a)
+  endif()
+
+  set(FuzzerTestObjects)
+  generate_compiler_rt_tests(FuzzerTestObjects
+    FuzzerUnitTests "Fuzzer-${arch}-Test" ${arch}
+    SOURCES FuzzerUnittest.cpp ${COMPILER_RT_GTEST_SOURCE}
+    RUNTIME ${LIBFUZZER_TEST_RUNTIME}
+    DEPS gtest ${LIBFUZZER_TEST_RUNTIME_DEPS} 
+    CFLAGS ${LIBFUZZER_UNITTEST_CFLAGS} ${LIBFUZZER_TEST_RUNTIME_CFLAGS}
+    LINK_FLAGS ${LIBFUZZER_UNITTEST_LINK_FLAGS} ${LIBFUZZER_TEST_RUNTIME_LINK_FLAGS})
+  set_target_properties(FuzzerUnitTests PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+  set(FuzzedDataProviderTestObjects)
+  generate_compiler_rt_tests(FuzzedDataProviderTestObjects
+    FuzzedDataProviderUnitTests "FuzzerUtils-${arch}-Test" ${arch}
+    SOURCES FuzzedDataProviderUnittest.cpp ${COMPILER_RT_GTEST_SOURCE}
+    DEPS gtest ${LIBFUZZER_TEST_RUNTIME_DEPS} ${COMPILER_RT_SOURCE_DIR}/include/fuzzer/FuzzedDataProvider.h
+    CFLAGS ${LIBFUZZER_UNITTEST_CFLAGS} ${LIBFUZZER_TEST_RUNTIME_CFLAGS}
+    LINK_FLAGS ${LIBFUZZER_UNITTEST_LINK_FLAGS} ${LIBFUZZER_TEST_RUNTIME_LINK_FLAGS})
+  set_target_properties(FuzzedDataProviderUnitTests PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+endif()
diff --git a/libfuzzer/tests/FuzzedDataProviderUnittest.cpp b/libfuzzer/tests/FuzzedDataProviderUnittest.cpp
new file mode 100644
index 0000000..99d9d8e
--- /dev/null
+++ b/libfuzzer/tests/FuzzedDataProviderUnittest.cpp
@@ -0,0 +1,436 @@
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "gtest/gtest.h"
+#include <cstdint>
+#include <cstdlib>
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+// The test is intentionally extensive, as behavior of |FuzzedDataProvider| must
+// not be broken, given than many fuzz targets depend on it. Changing the
+// behavior might invalidate existing corpora and make the fuzz targets using
+// |FuzzedDataProvider| to lose code coverage accumulated over time.
+
+/* A random 1KB buffer generated by:
+$ python -c "import os; print ',\n'.join([', '.join(['0x%02X' % ord(i) for i \
+      in list(os.urandom(8))]) for _ in xrange(128)])"
+*/
+const uint8_t Data[] = {
+    0x8A, 0x19, 0x0D, 0x44, 0x37, 0x0D, 0x38, 0x5E, 0x9B, 0xAA, 0xF3, 0xDA,
+    0xAA, 0x88, 0xF2, 0x9B, 0x6C, 0xBA, 0xBE, 0xB1, 0xF2, 0xCF, 0x13, 0xB8,
+    0xAC, 0x1A, 0x7F, 0x1C, 0xC9, 0x90, 0xD0, 0xD9, 0x5C, 0x42, 0xB3, 0xFD,
+    0xE3, 0x05, 0xA4, 0x03, 0x37, 0x49, 0x50, 0x4B, 0xBC, 0x39, 0xA2, 0x09,
+    0x6C, 0x2F, 0xAF, 0xD1, 0xB5, 0x47, 0xBF, 0x92, 0xBD, 0x79, 0xE5, 0xC5,
+    0x6E, 0x51, 0xA4, 0xED, 0xE9, 0xBD, 0x40, 0x4A, 0xFC, 0x25, 0x7A, 0x27,
+    0xC8, 0x92, 0xF7, 0x30, 0xDE, 0x40, 0x66, 0x66, 0xE8, 0x5F, 0x65, 0x39,
+    0x7E, 0x9E, 0x80, 0x2B, 0x01, 0x71, 0x2A, 0xFF, 0xD3, 0x0A, 0xAC, 0x6E,
+    0x49, 0x32, 0x79, 0x10, 0x6A, 0x6F, 0x97, 0x96, 0x70, 0x7E, 0x50, 0x65,
+    0xC9, 0x1D, 0xBD, 0x4E, 0x17, 0x04, 0x1E, 0xBA, 0x26, 0xAC, 0x1F, 0xE3,
+    0x37, 0x1C, 0x15, 0x43, 0x60, 0x41, 0x2A, 0x7C, 0xCA, 0x70, 0xCE, 0xAB,
+    0x20, 0x24, 0xF8, 0xD9, 0x1F, 0x14, 0x7C, 0x5C, 0xDD, 0x6F, 0xB3, 0xD7,
+    0x8B, 0x63, 0x10, 0xB7, 0xDA, 0x99, 0xAF, 0x99, 0x01, 0x21, 0xE6, 0xE1,
+    0x86, 0x27, 0xBE, 0x8D, 0xDF, 0x1E, 0xEA, 0x80, 0x0B, 0x8A, 0x60, 0xC3,
+    0x3A, 0x85, 0x33, 0x53, 0x59, 0xE1, 0xB5, 0xF1, 0x62, 0xA6, 0x7B, 0x24,
+    0x94, 0xE3, 0x8C, 0x10, 0x93, 0xF8, 0x6E, 0xC2, 0x00, 0x91, 0x90, 0x0B,
+    0x5D, 0x52, 0x4F, 0x21, 0xE3, 0x40, 0x3A, 0x6E, 0xB6, 0x32, 0x15, 0xDB,
+    0x5D, 0x01, 0x86, 0x63, 0x83, 0x24, 0xC5, 0xDE, 0xAB, 0x31, 0x84, 0xAA,
+    0xE5, 0x64, 0x02, 0x8D, 0x23, 0x82, 0x86, 0x14, 0x16, 0x18, 0x9F, 0x3D,
+    0x31, 0xBE, 0x3B, 0xF0, 0x6C, 0x26, 0x42, 0x9A, 0x67, 0xFE, 0x28, 0xEC,
+    0x28, 0xDB, 0x01, 0xB4, 0x52, 0x41, 0x81, 0x7C, 0x54, 0xD3, 0xC8, 0x00,
+    0x01, 0x66, 0xB0, 0x2C, 0x3F, 0xBC, 0xAF, 0xAC, 0x87, 0xCD, 0x83, 0xCF,
+    0x23, 0xFC, 0xC8, 0x97, 0x8C, 0x71, 0x32, 0x8B, 0xBF, 0x70, 0xC0, 0x48,
+    0x31, 0x92, 0x18, 0xFE, 0xE5, 0x33, 0x48, 0x82, 0x98, 0x1E, 0x30, 0xCC,
+    0xAD, 0x5D, 0x97, 0xC4, 0xB4, 0x39, 0x7C, 0xCD, 0x39, 0x44, 0xF1, 0xA9,
+    0xD0, 0xF4, 0x27, 0xB7, 0x78, 0x85, 0x9E, 0x72, 0xFC, 0xCC, 0xEE, 0x98,
+    0x25, 0x3B, 0x69, 0x6B, 0x0C, 0x11, 0xEA, 0x22, 0xB6, 0xD0, 0xCD, 0xBF,
+    0x6D, 0xBE, 0x12, 0xDE, 0xFE, 0x78, 0x2E, 0x54, 0xCB, 0xBA, 0xD7, 0x2E,
+    0x54, 0x25, 0x14, 0x84, 0xFE, 0x1A, 0x10, 0xCE, 0xCC, 0x20, 0xE6, 0xE2,
+    0x7F, 0xE0, 0x5F, 0xDB, 0xA7, 0xF3, 0xE2, 0x4C, 0x52, 0x82, 0xFC, 0x0B,
+    0xA0, 0xBD, 0x34, 0x21, 0xF7, 0xEB, 0x1C, 0x5B, 0x67, 0xD0, 0xAF, 0x22,
+    0x15, 0xA1, 0xFF, 0xC2, 0x68, 0x25, 0x5B, 0xB2, 0x13, 0x3F, 0xFF, 0x98,
+    0x53, 0x25, 0xC5, 0x58, 0x39, 0xD0, 0x43, 0x86, 0x6C, 0x5B, 0x57, 0x8E,
+    0x83, 0xBA, 0xB9, 0x09, 0x09, 0x14, 0x0C, 0x9E, 0x99, 0x83, 0x88, 0x53,
+    0x79, 0xFD, 0xF7, 0x49, 0xE9, 0x2C, 0xCE, 0xE6, 0x7B, 0xF5, 0xC2, 0x27,
+    0x5E, 0x56, 0xB5, 0xB4, 0x46, 0x90, 0x91, 0x7F, 0x99, 0x88, 0xA7, 0x23,
+    0xC1, 0x80, 0xB8, 0x2D, 0xCD, 0xF7, 0x6F, 0x9A, 0xEC, 0xBD, 0x16, 0x9F,
+    0x7D, 0x87, 0x1E, 0x15, 0x51, 0xC4, 0x96, 0xE2, 0xBF, 0x61, 0x66, 0xB5,
+    0xFD, 0x01, 0x67, 0xD6, 0xFF, 0xD2, 0x14, 0x20, 0x98, 0x8E, 0xEF, 0xF3,
+    0x22, 0xDB, 0x7E, 0xCE, 0x70, 0x2D, 0x4C, 0x06, 0x5A, 0xA0, 0x4F, 0xC8,
+    0xB0, 0x4D, 0xA6, 0x52, 0xB2, 0xD6, 0x2F, 0xD8, 0x57, 0xE5, 0xEF, 0xF9,
+    0xEE, 0x52, 0x0F, 0xEC, 0xC4, 0x90, 0x33, 0xAD, 0x25, 0xDA, 0xCD, 0x12,
+    0x44, 0x5F, 0x32, 0xF6, 0x6F, 0xEF, 0x85, 0xB8, 0xDC, 0x3C, 0x01, 0x48,
+    0x28, 0x5D, 0x2D, 0x9C, 0x9B, 0xC0, 0x49, 0x36, 0x1E, 0x6A, 0x0A, 0x0C,
+    0xB0, 0x6E, 0x81, 0x89, 0xCB, 0x0A, 0x89, 0xCF, 0x73, 0xC6, 0x63, 0x3D,
+    0x8E, 0x13, 0x57, 0x91, 0x4E, 0xA3, 0x93, 0x8C, 0x61, 0x67, 0xFD, 0x13,
+    0xE0, 0x14, 0x72, 0xB3, 0xE4, 0x23, 0x45, 0x08, 0x4E, 0x4E, 0xF5, 0xA7,
+    0xA8, 0xEE, 0x30, 0xFD, 0x81, 0x80, 0x1F, 0xF3, 0x4F, 0xD7, 0xE7, 0xF2,
+    0x16, 0xC0, 0xD6, 0x15, 0x6A, 0x0F, 0x89, 0x15, 0xA9, 0xCF, 0x35, 0x50,
+    0x6B, 0x49, 0x3E, 0x12, 0x4A, 0x72, 0xE4, 0x59, 0x9D, 0xD7, 0xDB, 0xD2,
+    0xD1, 0x61, 0x7D, 0x52, 0x4A, 0x36, 0xF6, 0xBA, 0x0E, 0xFA, 0x88, 0x6F,
+    0x3C, 0x82, 0x16, 0xF0, 0xD5, 0xED, 0x4D, 0x78, 0xEF, 0x38, 0x17, 0x90,
+    0xEA, 0x28, 0x32, 0xA9, 0x79, 0x40, 0xFF, 0xAA, 0xE6, 0xF5, 0xC7, 0x96,
+    0x56, 0x65, 0x61, 0x83, 0x3D, 0xBD, 0xD7, 0xED, 0xD6, 0xB6, 0xC0, 0xED,
+    0x34, 0xAA, 0x60, 0xA9, 0xE8, 0x82, 0x78, 0xEA, 0x69, 0xF6, 0x47, 0xAF,
+    0x39, 0xAB, 0x11, 0xDB, 0xE9, 0xFB, 0x68, 0x0C, 0xFE, 0xDF, 0x97, 0x9F,
+    0x3A, 0xF4, 0xF3, 0x32, 0x27, 0x30, 0x57, 0x0E, 0xF7, 0xB2, 0xEE, 0xFB,
+    0x1E, 0x98, 0xA8, 0xA3, 0x25, 0x45, 0xE4, 0x6D, 0x2D, 0xAE, 0xFE, 0xDA,
+    0xB3, 0x32, 0x9B, 0x5D, 0xF5, 0x32, 0x74, 0xEA, 0xE5, 0x02, 0x30, 0x53,
+    0x95, 0x13, 0x7A, 0x23, 0x1F, 0x10, 0x30, 0xEA, 0x78, 0xE4, 0x36, 0x1D,
+    0x92, 0x96, 0xB9, 0x91, 0x2D, 0xFA, 0x43, 0xAB, 0xE6, 0xEF, 0x14, 0x14,
+    0xC9, 0xBC, 0x46, 0xC6, 0x05, 0x7C, 0xC6, 0x11, 0x23, 0xCF, 0x3D, 0xC8,
+    0xBE, 0xEC, 0xA3, 0x58, 0x31, 0x55, 0x65, 0x14, 0xA7, 0x94, 0x93, 0xDD,
+    0x2D, 0x76, 0xC9, 0x66, 0x06, 0xBD, 0xF5, 0xE7, 0x30, 0x65, 0x42, 0x52,
+    0xA2, 0x50, 0x9B, 0xE6, 0x40, 0xA2, 0x4B, 0xEC, 0xA6, 0xB7, 0x39, 0xAA,
+    0xD7, 0x61, 0x2C, 0xBF, 0x37, 0x5A, 0xDA, 0xB3, 0x5D, 0x2F, 0x5D, 0x11,
+    0x82, 0x97, 0x32, 0x8A, 0xC1, 0xA1, 0x13, 0x20, 0x17, 0xBD, 0xA2, 0x91,
+    0x94, 0x2A, 0x4E, 0xBE, 0x3E, 0x77, 0x63, 0x67, 0x5C, 0x0A, 0xE1, 0x22,
+    0x0A, 0x4F, 0x63, 0xE2, 0x84, 0xE9, 0x9F, 0x14, 0x86, 0xE2, 0x4B, 0x20,
+    0x9F, 0x50, 0xB3, 0x56, 0xED, 0xDE, 0x39, 0xD8, 0x75, 0x64, 0x45, 0x54,
+    0xE5, 0x34, 0x57, 0x8C, 0x3B, 0xF2, 0x0E, 0x94, 0x1B, 0x10, 0xA2, 0xA2,
+    0x38, 0x76, 0x21, 0x8E, 0x2A, 0x57, 0x64, 0x58, 0x0A, 0x27, 0x6D, 0x4C,
+    0xD0, 0xB5, 0xC1, 0xFC, 0x75, 0xD0, 0x01, 0x86, 0x66, 0xA8, 0xF1, 0x98,
+    0x58, 0xFB, 0xFC, 0x64, 0xD2, 0x31, 0x77, 0xAD, 0x0E, 0x46, 0x87, 0xCC,
+    0x9B, 0x86, 0x90, 0xFF, 0xB6, 0x64, 0x35, 0xA5, 0x5D, 0x9E, 0x44, 0x51,
+    0x87, 0x9E, 0x1E, 0xEE, 0xF3, 0x3B, 0x5C, 0xDD, 0x94, 0x03, 0xAA, 0x18,
+    0x2C, 0xB7, 0xC4, 0x37, 0xD5, 0x53, 0x28, 0x60, 0xEF, 0x77, 0xEF, 0x3B,
+    0x9E, 0xD2, 0xCE, 0xE9, 0x53, 0x2D, 0xF5, 0x19, 0x7E, 0xBB, 0xB5, 0x46,
+    0xE2, 0xF7, 0xD6, 0x4D, 0x6D, 0x5B, 0x81, 0x56, 0x6B, 0x12, 0x55, 0x63,
+    0xC3, 0xAB, 0x08, 0xBB, 0x2E, 0xD5, 0x11, 0xBC, 0x18, 0xCB, 0x8B, 0x12,
+    0x2E, 0x3E, 0x75, 0x32, 0x98, 0x8A, 0xDE, 0x3C, 0xEA, 0x33, 0x46, 0xE7,
+    0x7A, 0xA5, 0x12, 0x09, 0x26, 0x7E, 0x7E, 0x03, 0x4F, 0xFD, 0xC0, 0xFD,
+    0xEA, 0x4F, 0x83, 0x85, 0x39, 0x62, 0xFB, 0xA2, 0x33, 0xD9, 0x2D, 0xB1,
+    0x30, 0x6F, 0x88, 0xAB, 0x61, 0xCB, 0x32, 0xEB, 0x30, 0xF9, 0x51, 0xF6,
+    0x1F, 0x3A, 0x11, 0x4D, 0xFD, 0x54, 0xD6, 0x3D, 0x43, 0x73, 0x39, 0x16,
+    0xCF, 0x3D, 0x29, 0x4A};
+
+TEST(FuzzedDataProvider, ConsumeBytes) {
+  FuzzedDataProvider DataProv(Data, sizeof(Data));
+  EXPECT_EQ(std::vector<unsigned char>(1, 0x8A),
+            DataProv.ConsumeBytes<unsigned char>(1));
+  EXPECT_EQ(std::vector<uint8_t>(
+                {0x19, 0x0D, 0x44, 0x37, 0x0D, 0x38, 0x5E, 0x9B, 0xAA, 0xF3}),
+            DataProv.ConsumeBytes<uint8_t>(10));
+
+  std::vector<unsigned char> UChars = DataProv.ConsumeBytes<unsigned char>(24);
+  EXPECT_EQ(std::vector<unsigned char>({0xDA, 0xAA, 0x88, 0xF2, 0x9B, 0x6C,
+                                        0xBA, 0xBE, 0xB1, 0xF2, 0xCF, 0x13,
+                                        0xB8, 0xAC, 0x1A, 0x7F, 0x1C, 0xC9,
+                                        0x90, 0xD0, 0xD9, 0x5C, 0x42, 0xB3}),
+            UChars);
+
+  EXPECT_EQ(std::vector<signed char>(Data + 1 + 10 + 24, Data + sizeof(Data)),
+            DataProv.ConsumeBytes<signed char>(31337));
+}
+
+TEST(FuzzedDataProvider, ConsumeBytesWithTerminator) {
+  FuzzedDataProvider DataProv(Data, sizeof(Data));
+  EXPECT_EQ(std::vector<unsigned char>({0x8A, 0x00}),
+            DataProv.ConsumeBytesWithTerminator<unsigned char>(1));
+  EXPECT_EQ(std::vector<uint8_t>({0x19, 0x0D, 0x44, 0x37, 0x0D, 0x38, 0x5E,
+                                  0x9B, 0xAA, 0xF3, 111}),
+            DataProv.ConsumeBytesWithTerminator<uint8_t>(10, 111));
+
+  std::vector<unsigned char> UChars =
+      DataProv.ConsumeBytesWithTerminator<unsigned char>(24);
+  EXPECT_EQ(std::vector<unsigned char>(
+                {0xDA, 0xAA, 0x88, 0xF2, 0x9B, 0x6C, 0xBA, 0xBE, 0xB1,
+                 0xF2, 0xCF, 0x13, 0xB8, 0xAC, 0x1A, 0x7F, 0x1C, 0xC9,
+                 0x90, 0xD0, 0xD9, 0x5C, 0x42, 0xB3, 0x00}),
+            UChars);
+
+  std::vector<signed char> Expected(Data + 1 + 10 + 24, Data + sizeof(Data));
+  Expected.push_back(65);
+  EXPECT_EQ(Expected,
+            DataProv.ConsumeBytesWithTerminator<signed char>(31337, 65));
+}
+
+TEST(FuzzedDataProvider, ConsumeBytesAsString) {
+  FuzzedDataProvider DataProv(Data, sizeof(Data));
+  EXPECT_EQ(std::string("\x8A\x19\x0D\x44\x37\x0D\x38\x5E\x9B\xAA\xF3\xDA"),
+            DataProv.ConsumeBytesAsString(12));
+  EXPECT_EQ(std::string(Data + 12, Data + sizeof(Data)),
+            DataProv.ConsumeBytesAsString(31337));
+}
+
+TEST(FuzzedDataProvider, ConsumeIntegralInRange) {
+  FuzzedDataProvider DataProv(Data, sizeof(Data));
+  EXPECT_EQ(int32_t(21), DataProv.ConsumeIntegralInRange<int32_t>(10, 30));
+  EXPECT_EQ(int32_t(1337),
+            DataProv.ConsumeIntegralInRange<int32_t>(1337, 1337));
+  EXPECT_EQ(int8_t(-59), DataProv.ConsumeIntegralInRange<int8_t>(-100, 100));
+  EXPECT_EQ(uint16_t(15823),
+            DataProv.ConsumeIntegralInRange<uint16_t>(0, 65535));
+  EXPECT_EQ((signed char)(-101),
+            DataProv.ConsumeIntegralInRange<signed char>(-123, 123));
+  EXPECT_EQ(int64_t(-53253077544), DataProv.ConsumeIntegralInRange<int64_t>(
+                                       -99999999999, 99999999999));
+
+  // Exhaust the buffer.
+  auto String = DataProv.ConsumeBytesAsString(31337);
+  EXPECT_EQ(size_t(1014), String.length());
+  EXPECT_EQ(uint64_t(123456789),
+            DataProv.ConsumeIntegralInRange<uint64_t>(123456789, 987654321));
+}
+
+TEST(FuzzedDataProvider, ConsumeRandomLengthString) {
+  FuzzedDataProvider DataProv(Data, sizeof(Data));
+  EXPECT_EQ(
+      std::string(
+          "\x8A\x19\x0D\x44\x37\x0D\x38\x5E\x9B\xAA\xF3\xDA\xAA\x88\xF2\x9B\x6C"
+          "\xBA\xBE\xB1\xF2\xCF\x13\xB8\xAC\x1A\x7F\x1C\xC9\x90\xD0\xD9"),
+      DataProv.ConsumeRandomLengthString(1337));
+  EXPECT_EQ(std::string(
+                "\xB3\xFD\xE3\x05\xA4\x03\x37\x49\x50\x4B\xBC\x39\xA2\x09\x6C"
+                "\x2F\xAF\xD1\xB5\x47\xBF\x92\xBD\x79\xE5\xC5\x6E\x51\xA4\xED"
+                "\xE9\xBD\x40\x4A\xFC\x25\x7A\x27\xC8\x92\xF7\x30\xDE\x40\x66"
+                "\x66\xE8\x5F\x65\x39\x7E\x9E\x80\x2B\x01\x71\x2A\xFF\xD3\x0A"
+                "\xAC\x6E\x49\x32\x79\x10\x6A\x6F\x97\x96\x70\x7E\x50\x65\xC9"
+                "\x1D\xBD\x4E\x17\x04\x1E\xBA\x26\xAC\x1F\xE3\x37\x1C\x15\x43"
+                "\x60\x41\x2A\x7C\xCA\x70\xCE\xAB\x20\x24\xF8\xD9\x1F\x14\x7C"),
+            DataProv.ConsumeRandomLengthString(31337));
+  size_t Offset = 141;
+  EXPECT_EQ(std::string(Data + Offset, Data + Offset + 5),
+            DataProv.ConsumeRandomLengthString(5));
+  Offset += 5;
+  EXPECT_EQ(std::string(Data + Offset, Data + Offset + 2),
+            DataProv.ConsumeRandomLengthString(2));
+  Offset += 2;
+
+  // Call the overloaded method without arguments (uses max length available).
+  EXPECT_EQ(std::string(Data + Offset, Data + Offset + 664),
+            DataProv.ConsumeRandomLengthString());
+  Offset += 664 + 2; // +2 because of '\' character followed by any other byte.
+
+  EXPECT_EQ(std::string(Data + Offset, Data + Offset + 92),
+            DataProv.ConsumeRandomLengthString());
+  Offset += 92 + 2;
+
+  // Exhaust the buffer.
+  auto String = DataProv.ConsumeBytesAsString(31337);
+  EXPECT_EQ(size_t(116), String.length());
+  EXPECT_EQ(std::string(), DataProv.ConsumeRandomLengthString(1));
+}
+
+TEST(FuzzedDataProvider, ConsumeRemainingBytes) {
+  {
+    FuzzedDataProvider DataProv(Data, sizeof(Data));
+    EXPECT_EQ(std::vector<uint8_t>(Data, Data + sizeof(Data)),
+              DataProv.ConsumeRemainingBytes<uint8_t>());
+    EXPECT_EQ(std::vector<uint8_t>(),
+              DataProv.ConsumeRemainingBytes<uint8_t>());
+  }
+
+  {
+    FuzzedDataProvider DataProv(Data, sizeof(Data));
+    EXPECT_EQ(std::vector<uint8_t>(Data, Data + 123),
+              DataProv.ConsumeBytes<uint8_t>(123));
+    EXPECT_EQ(std::vector<char>(Data + 123, Data + sizeof(Data)),
+              DataProv.ConsumeRemainingBytes<char>());
+  }
+}
+
+TEST(FuzzedDataProvider, ConsumeRemainingBytesAsString) {
+  {
+    FuzzedDataProvider DataProv(Data, sizeof(Data));
+    EXPECT_EQ(std::string(Data, Data + sizeof(Data)),
+              DataProv.ConsumeRemainingBytesAsString());
+    EXPECT_EQ(std::string(""), DataProv.ConsumeRemainingBytesAsString());
+  }
+
+  {
+    FuzzedDataProvider DataProv(Data, sizeof(Data));
+    EXPECT_EQ(std::vector<uint8_t>(Data, Data + 123),
+              DataProv.ConsumeBytes<uint8_t>(123));
+    EXPECT_EQ(std::string(Data + 123, Data + sizeof(Data)),
+              DataProv.ConsumeRemainingBytesAsString());
+  }
+}
+
+TEST(FuzzedDataProvider, ConsumeIntegral) {
+  FuzzedDataProvider DataProv(Data, sizeof(Data));
+  EXPECT_EQ(int32_t(-903266865), DataProv.ConsumeIntegral<int32_t>());
+  EXPECT_EQ(uint32_t(372863811), DataProv.ConsumeIntegral<uint32_t>());
+  EXPECT_EQ(uint8_t(61), DataProv.ConsumeIntegral<uint8_t>());
+  EXPECT_EQ(int16_t(22100), DataProv.ConsumeIntegral<int16_t>());
+  EXPECT_EQ(uint64_t(18252263806144500217u),
+            DataProv.ConsumeIntegral<uint64_t>());
+
+  // Exhaust the buffer.
+  auto String = DataProv.ConsumeBytesAsString(31337);
+  EXPECT_EQ(size_t(1005), String.length());
+  EXPECT_EQ(std::numeric_limits<int64_t>::min(),
+            DataProv.ConsumeIntegral<int64_t>());
+}
+
+TEST(FuzzedDataProvider, ConsumeBool) {
+  FuzzedDataProvider DataProv(Data, sizeof(Data));
+  EXPECT_EQ(false, DataProv.ConsumeBool());
+  EXPECT_EQ(true, DataProv.ConsumeBool());
+  EXPECT_EQ(true, DataProv.ConsumeBool());
+  EXPECT_EQ(true, DataProv.ConsumeBool());
+  EXPECT_EQ(false, DataProv.ConsumeBool());
+  EXPECT_EQ(true, DataProv.ConsumeBool());
+  EXPECT_EQ(true, DataProv.ConsumeBool());
+  EXPECT_EQ(true, DataProv.ConsumeBool());
+  EXPECT_EQ(true, DataProv.ConsumeBool());
+  EXPECT_EQ(false, DataProv.ConsumeBool());
+
+  // Exhaust the buffer.
+  auto String = DataProv.ConsumeBytesAsString(31337);
+  EXPECT_EQ(size_t(1014), String.length());
+  EXPECT_EQ(false, DataProv.ConsumeBool());
+}
+
+TEST(FuzzedDataProvider, PickValueInArray) {
+  FuzzedDataProvider DataProv(Data, sizeof(Data));
+  const int Array[] = {1, 2, 3, 4, 5};
+  EXPECT_EQ(5, DataProv.PickValueInArray(Array));
+  EXPECT_EQ(2, DataProv.PickValueInArray(Array));
+  EXPECT_EQ(2, DataProv.PickValueInArray(Array));
+  EXPECT_EQ(3, DataProv.PickValueInArray(Array));
+  EXPECT_EQ(3, DataProv.PickValueInArray(Array));
+  EXPECT_EQ(3, DataProv.PickValueInArray(Array));
+  EXPECT_EQ(1, DataProv.PickValueInArray(Array));
+  EXPECT_EQ(3, DataProv.PickValueInArray(Array));
+  EXPECT_EQ(2, DataProv.PickValueInArray(Array));
+
+  EXPECT_EQ(uint8_t(0x9D), DataProv.PickValueInArray(Data));
+  EXPECT_EQ(uint8_t(0xBA), DataProv.PickValueInArray(Data));
+  EXPECT_EQ(uint8_t(0x69), DataProv.PickValueInArray(Data));
+  EXPECT_EQ(uint8_t(0xD6), DataProv.PickValueInArray(Data));
+
+  EXPECT_EQ(uint32_t(777), DataProv.PickValueInArray<uint32_t>({1337, 777}));
+  EXPECT_EQ(uint32_t(777), DataProv.PickValueInArray<uint32_t>({1337, 777}));
+  EXPECT_EQ(uint64_t(1337), DataProv.PickValueInArray<uint64_t>({1337, 777}));
+  EXPECT_EQ(size_t(777), DataProv.PickValueInArray<size_t>({1337, 777}));
+  EXPECT_EQ(int16_t(1337), DataProv.PickValueInArray<int16_t>({1337, 777}));
+  EXPECT_EQ(int32_t(777), DataProv.PickValueInArray<int32_t>({1337, 777}));
+  EXPECT_EQ(int64_t(777), DataProv.PickValueInArray<int64_t>({1337, 777}));
+
+  // Exhaust the buffer.
+  auto String = DataProv.ConsumeBytesAsString(31337);
+  EXPECT_EQ(size_t(1000), String.length());
+  EXPECT_EQ(uint8_t(0x8A), DataProv.PickValueInArray(Data));
+}
+
+TEST(FuzzedDataProvider, ConsumeEnum) {
+  FuzzedDataProvider DataProv(Data, sizeof(Data));
+  enum class Enum {
+    Zero,
+    One,
+    Two,
+    Three,
+    Four,
+    Five,
+    Six,
+    Seven,
+    kMaxValue = Seven
+  };
+  EXPECT_EQ(Enum::Two, DataProv.ConsumeEnum<Enum>());
+  EXPECT_EQ(Enum::One, DataProv.ConsumeEnum<Enum>());
+  EXPECT_EQ(Enum::Five, DataProv.ConsumeEnum<Enum>());
+  EXPECT_EQ(Enum::Seven, DataProv.ConsumeEnum<Enum>());
+  EXPECT_EQ(Enum::Six, DataProv.ConsumeEnum<Enum>());
+  EXPECT_EQ(Enum::One, DataProv.ConsumeEnum<Enum>());
+  EXPECT_EQ(Enum::Three, DataProv.ConsumeEnum<Enum>());
+  EXPECT_EQ(Enum::Three, DataProv.ConsumeEnum<Enum>());
+  EXPECT_EQ(Enum::Five, DataProv.ConsumeEnum<Enum>());
+  EXPECT_EQ(Enum::Six, DataProv.ConsumeEnum<Enum>());
+
+  // Exhaust the buffer.
+  auto String = DataProv.ConsumeBytesAsString(31337);
+  EXPECT_EQ(size_t(1014), String.length());
+  EXPECT_EQ(Enum::Zero, DataProv.ConsumeEnum<Enum>());
+}
+
+TEST(FuzzedDataProvider, remaining_bytes) {
+  FuzzedDataProvider DataProv(Data, sizeof(Data));
+  EXPECT_EQ(size_t(1024), DataProv.remaining_bytes());
+  EXPECT_EQ(false, DataProv.ConsumeBool());
+  EXPECT_EQ(size_t(1024 - 1), DataProv.remaining_bytes());
+  EXPECT_EQ(std::vector<uint8_t>(Data, Data + 8),
+            DataProv.ConsumeBytes<uint8_t>(8));
+  EXPECT_EQ(size_t(1024 - 1 - 8), DataProv.remaining_bytes());
+
+  // Exhaust the buffer.
+  EXPECT_EQ(std::vector<uint8_t>(Data + 8, Data + sizeof(Data) - 1),
+            DataProv.ConsumeRemainingBytes<uint8_t>());
+  EXPECT_EQ(size_t(0), DataProv.remaining_bytes());
+}
+
+TEST(FuzzedDataProvider, ConsumeProbability) {
+  FuzzedDataProvider DataProv(Data, sizeof(Data));
+  ASSERT_FLOAT_EQ(float(0.28969181), DataProv.ConsumeProbability<float>());
+  ASSERT_DOUBLE_EQ(double(0.086814121166605432),
+                   DataProv.ConsumeProbability<double>());
+  ASSERT_FLOAT_EQ(float(0.30104411), DataProv.ConsumeProbability<float>());
+  ASSERT_DOUBLE_EQ(double(0.96218831486039413),
+                   DataProv.ConsumeProbability<double>());
+  ASSERT_FLOAT_EQ(float(0.67005056), DataProv.ConsumeProbability<float>());
+  ASSERT_DOUBLE_EQ(double(0.69210584173832279),
+                   DataProv.ConsumeProbability<double>());
+
+  // Exhaust the buffer.
+  EXPECT_EQ(std::vector<uint8_t>(Data, Data + sizeof(Data) - 36),
+            DataProv.ConsumeRemainingBytes<uint8_t>());
+  ASSERT_FLOAT_EQ(float(0.0), DataProv.ConsumeProbability<float>());
+}
+
+TEST(FuzzedDataProvider, ConsumeFloatingPoint) {
+  FuzzedDataProvider DataProv(Data, sizeof(Data));
+  ASSERT_FLOAT_EQ(float(-2.8546307e+38),
+                  DataProv.ConsumeFloatingPoint<float>());
+  ASSERT_DOUBLE_EQ(double(8.0940194040236032e+307),
+                   DataProv.ConsumeFloatingPoint<double>());
+  ASSERT_FLOAT_EQ(float(271.49084),
+                  DataProv.ConsumeFloatingPointInRange<float>(123.0, 777.0));
+  ASSERT_DOUBLE_EQ(double(30.859126145478349),
+                   DataProv.ConsumeFloatingPointInRange<double>(13.37, 31.337));
+  ASSERT_FLOAT_EQ(
+      float(-903.47729),
+      DataProv.ConsumeFloatingPointInRange<float>(-999.9999, -777.77));
+  ASSERT_DOUBLE_EQ(
+      double(24.561393182922771),
+      DataProv.ConsumeFloatingPointInRange<double>(-13.37, 31.337));
+  ASSERT_FLOAT_EQ(float(1.0),
+                  DataProv.ConsumeFloatingPointInRange<float>(1.0, 1.0));
+  ASSERT_DOUBLE_EQ(double(-1.0),
+                   DataProv.ConsumeFloatingPointInRange<double>(-1.0, -1.0));
+
+  // Exhaust the buffer.
+  EXPECT_EQ((std::vector<uint8_t>(Data, Data + sizeof(Data) - 50)).size(),
+            DataProv.ConsumeRemainingBytes<uint8_t>().size());
+  ASSERT_FLOAT_EQ(float(0.0), DataProv.ConsumeProbability<float>());
+  ASSERT_NEAR(std::numeric_limits<double>::lowest(),
+              DataProv.ConsumeFloatingPoint<double>(), 1e-10);
+  ASSERT_FLOAT_EQ(float(123.0),
+                  DataProv.ConsumeFloatingPointInRange<float>(123.0, 777.0));
+  ASSERT_DOUBLE_EQ(double(-13.37), DataProv.ConsumeFloatingPointInRange<double>(
+                                       -13.37, 31.337));
+}
+
+TEST(FuzzedDataProvider, ConsumeData) {
+  FuzzedDataProvider DataProv(Data, sizeof(Data));
+  uint8_t Buffer[10] = {};
+  EXPECT_EQ(sizeof(Buffer), DataProv.ConsumeData(Buffer, sizeof(Buffer)));
+  std::vector<uint8_t> Expected(Data, Data + sizeof(Buffer));
+  EXPECT_EQ(Expected, std::vector<uint8_t>(Buffer, Buffer + sizeof(Buffer)));
+
+  EXPECT_EQ(size_t(2), DataProv.ConsumeData(Buffer, 2));
+  Expected[0] = Data[sizeof(Buffer)];
+  Expected[1] = Data[sizeof(Buffer) + 1];
+  EXPECT_EQ(Expected, std::vector<uint8_t>(Buffer, Buffer + sizeof(Buffer)));
+
+  // Exhaust the buffer.
+  EXPECT_EQ(std::vector<uint8_t>(Data + 12, Data + sizeof(Data)),
+            DataProv.ConsumeRemainingBytes<uint8_t>());
+  EXPECT_EQ(size_t(0), DataProv.ConsumeData(Buffer, sizeof(Buffer)));
+  EXPECT_EQ(Expected, std::vector<uint8_t>(Buffer, Buffer + sizeof(Buffer)));
+}
+
+int main(int argc, char **argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/libfuzzer/tests/FuzzerUnittest.cpp b/libfuzzer/tests/FuzzerUnittest.cpp
new file mode 100644
index 0000000..0e9435a
--- /dev/null
+++ b/libfuzzer/tests/FuzzerUnittest.cpp
@@ -0,0 +1,1119 @@
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+// Avoid ODR violations (LibFuzzer is built without ASan and this test is built
+// with ASan) involving C++ standard library types when using libcxx.
+#define _LIBCPP_HAS_NO_ASAN
+
+// Do not attempt to use LLVM ostream etc from gtest.
+#define GTEST_NO_LLVM_SUPPORT 1
+
+#include "FuzzerCorpus.h"
+#include "FuzzerDictionary.h"
+#include "FuzzerInternal.h"
+#include "FuzzerMerge.h"
+#include "FuzzerMutate.h"
+#include "FuzzerRandom.h"
+#include "FuzzerTracePC.h"
+#include "gtest/gtest.h"
+#include <memory>
+#include <set>
+#include <sstream>
+
+using namespace fuzzer;
+
+// For now, have LLVMFuzzerTestOneInput just to make it link.
+// Later we may want to make unittests that actually call LLVMFuzzerTestOneInput.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+  abort();
+}
+
+TEST(Fuzzer, Basename) {
+  EXPECT_EQ(Basename("foo/bar"), "bar");
+  EXPECT_EQ(Basename("bar"), "bar");
+  EXPECT_EQ(Basename("/bar"), "bar");
+  EXPECT_EQ(Basename("foo/x"), "x");
+  EXPECT_EQ(Basename("foo/"), "");
+#if LIBFUZZER_WINDOWS
+  EXPECT_EQ(Basename("foo\\bar"), "bar");
+  EXPECT_EQ(Basename("foo\\bar/baz"), "baz");
+  EXPECT_EQ(Basename("\\bar"), "bar");
+  EXPECT_EQ(Basename("foo\\x"), "x");
+  EXPECT_EQ(Basename("foo\\"), "");
+#endif
+}
+
+TEST(Fuzzer, CrossOver) {
+  std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+  fuzzer::EF = t.get();
+  Random Rand(0);
+  std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(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++) {
+    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 TestEraseBytes(Mutator M, int NumIter) {
+  std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+  fuzzer::EF = t.get();
+  uint8_t REM0[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+  uint8_t REM1[8] = {0x00, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+  uint8_t REM2[8] = {0x00, 0x11, 0x33, 0x44, 0x55, 0x66, 0x77};
+  uint8_t REM3[8] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x77};
+  uint8_t REM4[8] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x66, 0x77};
+  uint8_t REM5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x66, 0x77};
+  uint8_t REM6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x77};
+  uint8_t REM7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+
+  uint8_t REM8[6] = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+  uint8_t REM9[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
+  uint8_t REM10[6] = {0x00, 0x11, 0x22, 0x55, 0x66, 0x77};
+
+  uint8_t REM11[5] = {0x33, 0x44, 0x55, 0x66, 0x77};
+  uint8_t REM12[5] = {0x00, 0x11, 0x22, 0x33, 0x44};
+  uint8_t REM13[5] = {0x00, 0x44, 0x55, 0x66, 0x77};
+
+
+  Random Rand(0);
+  std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+  int FoundMask = 0;
+  for (int i = 0; i < NumIter; i++) {
+    uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+    size_t NewSize = (*MD.*M)(T, sizeof(T), sizeof(T));
+    if (NewSize == 7 && !memcmp(REM0, T, 7)) FoundMask |= 1 << 0;
+    if (NewSize == 7 && !memcmp(REM1, T, 7)) FoundMask |= 1 << 1;
+    if (NewSize == 7 && !memcmp(REM2, T, 7)) FoundMask |= 1 << 2;
+    if (NewSize == 7 && !memcmp(REM3, T, 7)) FoundMask |= 1 << 3;
+    if (NewSize == 7 && !memcmp(REM4, T, 7)) FoundMask |= 1 << 4;
+    if (NewSize == 7 && !memcmp(REM5, T, 7)) FoundMask |= 1 << 5;
+    if (NewSize == 7 && !memcmp(REM6, T, 7)) FoundMask |= 1 << 6;
+    if (NewSize == 7 && !memcmp(REM7, T, 7)) FoundMask |= 1 << 7;
+
+    if (NewSize == 6 && !memcmp(REM8, T, 6)) FoundMask |= 1 << 8;
+    if (NewSize == 6 && !memcmp(REM9, T, 6)) FoundMask |= 1 << 9;
+    if (NewSize == 6 && !memcmp(REM10, T, 6)) FoundMask |= 1 << 10;
+
+    if (NewSize == 5 && !memcmp(REM11, T, 5)) FoundMask |= 1 << 11;
+    if (NewSize == 5 && !memcmp(REM12, T, 5)) FoundMask |= 1 << 12;
+    if (NewSize == 5 && !memcmp(REM13, T, 5)) FoundMask |= 1 << 13;
+  }
+  EXPECT_EQ(FoundMask, (1 << 14) - 1);
+}
+
+TEST(FuzzerMutate, EraseBytes1) {
+  TestEraseBytes(&MutationDispatcher::Mutate_EraseBytes, 200);
+}
+TEST(FuzzerMutate, EraseBytes2) {
+  TestEraseBytes(&MutationDispatcher::Mutate, 2000);
+}
+
+void TestInsertByte(Mutator M, int NumIter) {
+  std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+  fuzzer::EF = t.get();
+  Random Rand(0);
+  std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+  int FoundMask = 0;
+  uint8_t INS0[8] = {0xF1, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+  uint8_t INS1[8] = {0x00, 0xF2, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+  uint8_t INS2[8] = {0x00, 0x11, 0xF3, 0x22, 0x33, 0x44, 0x55, 0x66};
+  uint8_t INS3[8] = {0x00, 0x11, 0x22, 0xF4, 0x33, 0x44, 0x55, 0x66};
+  uint8_t INS4[8] = {0x00, 0x11, 0x22, 0x33, 0xF5, 0x44, 0x55, 0x66};
+  uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF6, 0x55, 0x66};
+  uint8_t INS6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF7, 0x66};
+  uint8_t INS7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF8};
+  for (int i = 0; i < NumIter; i++) {
+    uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+    size_t NewSize = (*MD.*M)(T, 7, 8);
+    if (NewSize == 8 && !memcmp(INS0, T, 8)) FoundMask |= 1 << 0;
+    if (NewSize == 8 && !memcmp(INS1, T, 8)) FoundMask |= 1 << 1;
+    if (NewSize == 8 && !memcmp(INS2, T, 8)) FoundMask |= 1 << 2;
+    if (NewSize == 8 && !memcmp(INS3, T, 8)) FoundMask |= 1 << 3;
+    if (NewSize == 8 && !memcmp(INS4, T, 8)) FoundMask |= 1 << 4;
+    if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5;
+    if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6;
+    if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7;
+  }
+  EXPECT_EQ(FoundMask, 255);
+}
+
+TEST(FuzzerMutate, InsertByte1) {
+  TestInsertByte(&MutationDispatcher::Mutate_InsertByte, 1 << 15);
+}
+TEST(FuzzerMutate, InsertByte2) {
+  TestInsertByte(&MutationDispatcher::Mutate, 1 << 17);
+}
+
+void TestInsertRepeatedBytes(Mutator M, int NumIter) {
+  std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+  fuzzer::EF = t.get();
+  Random Rand(0);
+  std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+  int FoundMask = 0;
+  uint8_t INS0[7] = {0x00, 0x11, 0x22, 0x33, 'a', 'a', 'a'};
+  uint8_t INS1[7] = {0x00, 0x11, 0x22, 'a', 'a', 'a', 0x33};
+  uint8_t INS2[7] = {0x00, 0x11, 'a', 'a', 'a', 0x22, 0x33};
+  uint8_t INS3[7] = {0x00, 'a', 'a', 'a', 0x11, 0x22, 0x33};
+  uint8_t INS4[7] = {'a', 'a', 'a', 0x00, 0x11, 0x22, 0x33};
+
+  uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 'b', 'b', 'b', 'b'};
+  uint8_t INS6[8] = {0x00, 0x11, 0x22, 'b', 'b', 'b', 'b', 0x33};
+  uint8_t INS7[8] = {0x00, 0x11, 'b', 'b', 'b', 'b', 0x22, 0x33};
+  uint8_t INS8[8] = {0x00, 'b', 'b', 'b', 'b', 0x11, 0x22, 0x33};
+  uint8_t INS9[8] = {'b', 'b', 'b', 'b', 0x00, 0x11, 0x22, 0x33};
+
+  for (int i = 0; i < NumIter; i++) {
+    uint8_t T[8] = {0x00, 0x11, 0x22, 0x33};
+    size_t NewSize = (*MD.*M)(T, 4, 8);
+    if (NewSize == 7 && !memcmp(INS0, T, 7)) FoundMask |= 1 << 0;
+    if (NewSize == 7 && !memcmp(INS1, T, 7)) FoundMask |= 1 << 1;
+    if (NewSize == 7 && !memcmp(INS2, T, 7)) FoundMask |= 1 << 2;
+    if (NewSize == 7 && !memcmp(INS3, T, 7)) FoundMask |= 1 << 3;
+    if (NewSize == 7 && !memcmp(INS4, T, 7)) FoundMask |= 1 << 4;
+
+    if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5;
+    if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6;
+    if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7;
+    if (NewSize == 8 && !memcmp(INS8, T, 8)) FoundMask |= 1 << 8;
+    if (NewSize == 8 && !memcmp(INS9, T, 8)) FoundMask |= 1 << 9;
+
+  }
+  EXPECT_EQ(FoundMask, (1 << 10) - 1);
+}
+
+TEST(FuzzerMutate, InsertRepeatedBytes1) {
+  TestInsertRepeatedBytes(&MutationDispatcher::Mutate_InsertRepeatedBytes, 10000);
+}
+TEST(FuzzerMutate, InsertRepeatedBytes2) {
+  TestInsertRepeatedBytes(&MutationDispatcher::Mutate, 300000);
+}
+
+void TestChangeByte(Mutator M, int NumIter) {
+  std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+  fuzzer::EF = t.get();
+  Random Rand(0);
+  std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+  int FoundMask = 0;
+  uint8_t CH0[8] = {0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+  uint8_t CH1[8] = {0x00, 0xF1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+  uint8_t CH2[8] = {0x00, 0x11, 0xF2, 0x33, 0x44, 0x55, 0x66, 0x77};
+  uint8_t CH3[8] = {0x00, 0x11, 0x22, 0xF3, 0x44, 0x55, 0x66, 0x77};
+  uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0xF4, 0x55, 0x66, 0x77};
+  uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF5, 0x66, 0x77};
+  uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF5, 0x77};
+  uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7};
+  for (int i = 0; i < NumIter; i++) {
+    uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+    size_t NewSize = (*MD.*M)(T, 8, 9);
+    if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
+    if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
+    if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
+    if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
+    if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4;
+    if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
+    if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
+    if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
+  }
+  EXPECT_EQ(FoundMask, 255);
+}
+
+TEST(FuzzerMutate, ChangeByte1) {
+  TestChangeByte(&MutationDispatcher::Mutate_ChangeByte, 1 << 15);
+}
+TEST(FuzzerMutate, ChangeByte2) {
+  TestChangeByte(&MutationDispatcher::Mutate, 1 << 17);
+}
+
+void TestChangeBit(Mutator M, int NumIter) {
+  std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+  fuzzer::EF = t.get();
+  Random Rand(0);
+  std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+  int FoundMask = 0;
+  uint8_t CH0[8] = {0x01, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+  uint8_t CH1[8] = {0x00, 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+  uint8_t CH2[8] = {0x00, 0x11, 0x02, 0x33, 0x44, 0x55, 0x66, 0x77};
+  uint8_t CH3[8] = {0x00, 0x11, 0x22, 0x37, 0x44, 0x55, 0x66, 0x77};
+  uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x54, 0x55, 0x66, 0x77};
+  uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x54, 0x66, 0x77};
+  uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x76, 0x77};
+  uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7};
+  for (int i = 0; i < NumIter; i++) {
+    uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+    size_t NewSize = (*MD.*M)(T, 8, 9);
+    if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
+    if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
+    if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
+    if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
+    if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4;
+    if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
+    if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
+    if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
+  }
+  EXPECT_EQ(FoundMask, 255);
+}
+
+TEST(FuzzerMutate, ChangeBit1) {
+  TestChangeBit(&MutationDispatcher::Mutate_ChangeBit, 1 << 16);
+}
+TEST(FuzzerMutate, ChangeBit2) {
+  TestChangeBit(&MutationDispatcher::Mutate, 1 << 18);
+}
+
+void TestShuffleBytes(Mutator M, int NumIter) {
+  std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+  fuzzer::EF = t.get();
+  Random Rand(0);
+  std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(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 << 17);
+}
+TEST(FuzzerMutate, ShuffleBytes2) {
+  TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 20);
+}
+
+void TestCopyPart(Mutator M, int NumIter) {
+  std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+  fuzzer::EF = t.get();
+  Random Rand(0);
+  std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+  int FoundMask = 0;
+  uint8_t CH0[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11};
+  uint8_t CH1[7] = {0x55, 0x66, 0x22, 0x33, 0x44, 0x55, 0x66};
+  uint8_t CH2[7] = {0x00, 0x55, 0x66, 0x33, 0x44, 0x55, 0x66};
+  uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x66};
+  uint8_t CH4[7] = {0x00, 0x11, 0x11, 0x22, 0x33, 0x55, 0x66};
+
+  for (int i = 0; i < NumIter; i++) {
+    uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+    size_t NewSize = (*MD.*M)(T, 7, 7);
+    if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0;
+    if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1;
+    if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2;
+    if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3;
+    if (NewSize == 7 && !memcmp(CH4, T, 7)) FoundMask |= 1 << 4;
+  }
+
+  uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11, 0x22};
+  uint8_t CH6[8] = {0x22, 0x33, 0x44, 0x00, 0x11, 0x22, 0x33, 0x44};
+  uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x33, 0x44};
+  uint8_t CH8[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x22, 0x33, 0x44};
+  uint8_t CH9[8] = {0x00, 0x11, 0x22, 0x22, 0x33, 0x44, 0x33, 0x44};
+
+  for (int i = 0; i < NumIter; i++) {
+    uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+    size_t NewSize = (*MD.*M)(T, 5, 8);
+    if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
+    if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
+    if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
+    if (NewSize == 8 && !memcmp(CH8, T, 8)) FoundMask |= 1 << 8;
+    if (NewSize == 8 && !memcmp(CH9, T, 8)) FoundMask |= 1 << 9;
+  }
+
+  EXPECT_EQ(FoundMask, 1023);
+}
+
+TEST(FuzzerMutate, CopyPart1) {
+  TestCopyPart(&MutationDispatcher::Mutate_CopyPart, 1 << 10);
+}
+TEST(FuzzerMutate, CopyPart2) {
+  TestCopyPart(&MutationDispatcher::Mutate, 1 << 13);
+}
+TEST(FuzzerMutate, CopyPartNoInsertAtMaxSize) {
+  // This (non exhaustively) tests if `Mutate_CopyPart` tries to perform an
+  // insert on an input of size `MaxSize`.  Performing an insert in this case
+  // will lead to the mutation failing.
+  std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+  fuzzer::EF = t.get();
+  Random Rand(0);
+  std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+  uint8_t Data[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11, 0x22};
+  size_t MaxSize = sizeof(Data);
+  for (int count = 0; count < (1 << 18); ++count) {
+    size_t NewSize = MD->Mutate_CopyPart(Data, MaxSize, MaxSize);
+    ASSERT_EQ(NewSize, MaxSize);
+  }
+}
+
+void TestAddWordFromDictionary(Mutator M, int NumIter) {
+  std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+  fuzzer::EF = t.get();
+  Random Rand(0);
+  std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+  uint8_t Word1[4] = {0xAA, 0xBB, 0xCC, 0xDD};
+  uint8_t Word2[3] = {0xFF, 0xEE, 0xEF};
+  MD->AddWordToManualDictionary(Word(Word1, sizeof(Word1)));
+  MD->AddWordToManualDictionary(Word(Word2, sizeof(Word2)));
+  int FoundMask = 0;
+  uint8_t CH0[7] = {0x00, 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD};
+  uint8_t CH1[7] = {0x00, 0x11, 0xAA, 0xBB, 0xCC, 0xDD, 0x22};
+  uint8_t CH2[7] = {0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22};
+  uint8_t CH3[7] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x11, 0x22};
+  uint8_t CH4[6] = {0x00, 0x11, 0x22, 0xFF, 0xEE, 0xEF};
+  uint8_t CH5[6] = {0x00, 0x11, 0xFF, 0xEE, 0xEF, 0x22};
+  uint8_t CH6[6] = {0x00, 0xFF, 0xEE, 0xEF, 0x11, 0x22};
+  uint8_t CH7[6] = {0xFF, 0xEE, 0xEF, 0x00, 0x11, 0x22};
+  for (int i = 0; i < NumIter; i++) {
+    uint8_t T[7] = {0x00, 0x11, 0x22};
+    size_t NewSize = (*MD.*M)(T, 3, 7);
+    if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0;
+    if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1;
+    if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2;
+    if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3;
+    if (NewSize == 6 && !memcmp(CH4, T, 6)) FoundMask |= 1 << 4;
+    if (NewSize == 6 && !memcmp(CH5, T, 6)) FoundMask |= 1 << 5;
+    if (NewSize == 6 && !memcmp(CH6, T, 6)) FoundMask |= 1 << 6;
+    if (NewSize == 6 && !memcmp(CH7, T, 6)) FoundMask |= 1 << 7;
+  }
+  EXPECT_EQ(FoundMask, 255);
+}
+
+TEST(FuzzerMutate, AddWordFromDictionary1) {
+  TestAddWordFromDictionary(
+      &MutationDispatcher::Mutate_AddWordFromManualDictionary, 1 << 15);
+}
+
+TEST(FuzzerMutate, AddWordFromDictionary2) {
+  TestAddWordFromDictionary(&MutationDispatcher::Mutate, 1 << 15);
+}
+
+void TestChangeASCIIInteger(Mutator M, int NumIter) {
+  std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+  fuzzer::EF = t.get();
+  Random Rand(0);
+  std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+
+  uint8_t CH0[8] = {'1', '2', '3', '4', '5', '6', '7', '7'};
+  uint8_t CH1[8] = {'1', '2', '3', '4', '5', '6', '7', '9'};
+  uint8_t CH2[8] = {'2', '4', '6', '9', '1', '3', '5', '6'};
+  uint8_t CH3[8] = {'0', '6', '1', '7', '2', '8', '3', '9'};
+  int FoundMask = 0;
+  for (int i = 0; i < NumIter; i++) {
+    uint8_t T[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};
+    size_t NewSize = (*MD.*M)(T, 8, 8);
+    /**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
+    else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
+    else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
+    else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
+    else if (NewSize == 8)                       FoundMask |= 1 << 4;
+  }
+  EXPECT_EQ(FoundMask, 31);
+}
+
+TEST(FuzzerMutate, ChangeASCIIInteger1) {
+  TestChangeASCIIInteger(&MutationDispatcher::Mutate_ChangeASCIIInteger,
+                         1 << 15);
+}
+
+TEST(FuzzerMutate, ChangeASCIIInteger2) {
+  TestChangeASCIIInteger(&MutationDispatcher::Mutate, 1 << 15);
+}
+
+void TestChangeBinaryInteger(Mutator M, int NumIter) {
+  std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+  fuzzer::EF = t.get();
+  Random Rand(0);
+  std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+
+  uint8_t CH0[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x79};
+  uint8_t CH1[8] = {0x00, 0x11, 0x22, 0x31, 0x44, 0x55, 0x66, 0x77};
+  uint8_t CH2[8] = {0xff, 0x10, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+  uint8_t CH3[8] = {0x00, 0x11, 0x2a, 0x33, 0x44, 0x55, 0x66, 0x77};
+  uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x4f, 0x66, 0x77};
+  uint8_t CH5[8] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88};
+  uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x00, 0x00, 0x00, 0x08, 0x77}; // Size
+  uint8_t CH7[8] = {0x00, 0x08, 0x00, 0x33, 0x44, 0x55, 0x66, 0x77}; // Sw(Size)
+
+  int FoundMask = 0;
+  for (int i = 0; i < NumIter; i++) {
+    uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+    size_t NewSize = (*MD.*M)(T, 8, 8);
+    /**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
+    else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
+    else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
+    else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
+    else if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4;
+    else if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
+    else if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
+    else if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
+  }
+  EXPECT_EQ(FoundMask, 255);
+}
+
+TEST(FuzzerMutate, ChangeBinaryInteger1) {
+  TestChangeBinaryInteger(&MutationDispatcher::Mutate_ChangeBinaryInteger,
+                         1 << 12);
+}
+
+TEST(FuzzerMutate, ChangeBinaryInteger2) {
+  TestChangeBinaryInteger(&MutationDispatcher::Mutate, 1 << 15);
+}
+
+
+TEST(FuzzerDictionary, ParseOneDictionaryEntry) {
+  Unit U;
+  EXPECT_FALSE(ParseOneDictionaryEntry("", &U));
+  EXPECT_FALSE(ParseOneDictionaryEntry(" ", &U));
+  EXPECT_FALSE(ParseOneDictionaryEntry("\t  ", &U));
+  EXPECT_FALSE(ParseOneDictionaryEntry("  \" ", &U));
+  EXPECT_FALSE(ParseOneDictionaryEntry("  zz\" ", &U));
+  EXPECT_FALSE(ParseOneDictionaryEntry("  \"zz ", &U));
+  EXPECT_FALSE(ParseOneDictionaryEntry("  \"\" ", &U));
+  EXPECT_TRUE(ParseOneDictionaryEntry("\"a\"", &U));
+  EXPECT_EQ(U, Unit({'a'}));
+  EXPECT_TRUE(ParseOneDictionaryEntry("\"abc\"", &U));
+  EXPECT_EQ(U, Unit({'a', 'b', 'c'}));
+  EXPECT_TRUE(ParseOneDictionaryEntry("abc=\"abc\"", &U));
+  EXPECT_EQ(U, Unit({'a', 'b', 'c'}));
+  EXPECT_FALSE(ParseOneDictionaryEntry("\"\\\"", &U));
+  EXPECT_TRUE(ParseOneDictionaryEntry("\"\\\\\"", &U));
+  EXPECT_EQ(U, Unit({'\\'}));
+  EXPECT_TRUE(ParseOneDictionaryEntry("\"\\xAB\"", &U));
+  EXPECT_EQ(U, Unit({0xAB}));
+  EXPECT_TRUE(ParseOneDictionaryEntry("\"\\xABz\\xDE\"", &U));
+  EXPECT_EQ(U, Unit({0xAB, 'z', 0xDE}));
+  EXPECT_TRUE(ParseOneDictionaryEntry("\"#\"", &U));
+  EXPECT_EQ(U, Unit({'#'}));
+  EXPECT_TRUE(ParseOneDictionaryEntry("\"\\\"\"", &U));
+  EXPECT_EQ(U, Unit({'"'}));
+}
+
+TEST(FuzzerDictionary, ParseDictionaryFile) {
+  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, Vector<Unit>({Unit({'a', 'a'})}));
+  EXPECT_TRUE(
+      ParseDictionaryFile("  #zzzz\naaa=\"aa\"\n\nabc=\"abc\"", &Units));
+  EXPECT_EQ(Units,
+            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'}));
+}
+
+TEST(Corpus, Distribution) {
+  DataFlowTrace DFT;
+  Random Rand(0);
+  struct EntropicOptions Entropic = {false, 0xFF, 100};
+  std::unique_ptr<InputCorpus> C(new InputCorpus("", Entropic));
+  size_t N = 10;
+  size_t TriesPerUnit = 1<<16;
+  for (size_t i = 0; i < N; i++)
+    C->AddToCorpus(Unit{static_cast<uint8_t>(i)}, 1, false, false, {}, DFT,
+                   nullptr);
+
+  Vector<size_t> Hist(N);
+  for (size_t i = 0; i < N * TriesPerUnit; i++) {
+    Hist[C->ChooseUnitIdxToMutate(Rand)]++;
+  }
+  for (size_t i = 0; i < N; i++) {
+    // A weak sanity check that every unit gets invoked.
+    EXPECT_GT(Hist[i], TriesPerUnit / N / 3);
+  }
+}
+
+TEST(Merge, Bad) {
+  const char *kInvalidInputs[] = {
+    "",
+    "x",
+    "3\nx",
+    "2\n3",
+    "2\n2",
+    "2\n2\nA\n",
+    "2\n2\nA\nB\nC\n",
+    "0\n0\n",
+    "1\n1\nA\nFT 0",
+    "1\n1\nA\nSTARTED 1",
+  };
+  Merger M;
+  for (auto S : kInvalidInputs) {
+    // fprintf(stderr, "TESTING:\n%s\n", S);
+    EXPECT_FALSE(M.Parse(S, false));
+  }
+}
+
+void EQ(const Vector<uint32_t> &A, const Vector<uint32_t> &B) {
+  EXPECT_EQ(A, B);
+}
+
+void EQ(const Vector<std::string> &A, const Vector<std::string> &B) {
+  Set<std::string> a(A.begin(), A.end());
+  Set<std::string> b(B.begin(), B.end());
+  EXPECT_EQ(a, b);
+}
+
+static void Merge(const std::string &Input,
+                  const Vector<std::string> Result,
+                  size_t NumNewFeatures) {
+  Merger M;
+  Vector<std::string> NewFiles;
+  Set<uint32_t> NewFeatures, NewCov;
+  EXPECT_TRUE(M.Parse(Input, true));
+  EXPECT_EQ(NumNewFeatures, M.Merge({}, &NewFeatures, {}, &NewCov, &NewFiles));
+  EQ(NewFiles, Result);
+}
+
+TEST(Merge, Good) {
+  Merger M;
+
+  EXPECT_TRUE(M.Parse("1\n0\nAA\n", false));
+  EXPECT_EQ(M.Files.size(), 1U);
+  EXPECT_EQ(M.NumFilesInFirstCorpus, 0U);
+  EXPECT_EQ(M.Files[0].Name, "AA");
+  EXPECT_TRUE(M.LastFailure.empty());
+  EXPECT_EQ(M.FirstNotProcessedFile, 0U);
+
+  EXPECT_TRUE(M.Parse("2\n1\nAA\nBB\nSTARTED 0 42\n", false));
+  EXPECT_EQ(M.Files.size(), 2U);
+  EXPECT_EQ(M.NumFilesInFirstCorpus, 1U);
+  EXPECT_EQ(M.Files[0].Name, "AA");
+  EXPECT_EQ(M.Files[1].Name, "BB");
+  EXPECT_EQ(M.LastFailure, "AA");
+  EXPECT_EQ(M.FirstNotProcessedFile, 1U);
+
+  EXPECT_TRUE(M.Parse("3\n1\nAA\nBB\nC\n"
+                        "STARTED 0 1000\n"
+                        "FT 0 1 2 3\n"
+                        "STARTED 1 1001\n"
+                        "FT 1 4 5 6 \n"
+                        "STARTED 2 1002\n"
+                        "", true));
+  EXPECT_EQ(M.Files.size(), 3U);
+  EXPECT_EQ(M.NumFilesInFirstCorpus, 1U);
+  EXPECT_EQ(M.Files[0].Name, "AA");
+  EXPECT_EQ(M.Files[0].Size, 1000U);
+  EXPECT_EQ(M.Files[1].Name, "BB");
+  EXPECT_EQ(M.Files[1].Size, 1001U);
+  EXPECT_EQ(M.Files[2].Name, "C");
+  EXPECT_EQ(M.Files[2].Size, 1002U);
+  EXPECT_EQ(M.LastFailure, "C");
+  EXPECT_EQ(M.FirstNotProcessedFile, 3U);
+  EQ(M.Files[0].Features, {1, 2, 3});
+  EQ(M.Files[1].Features, {4, 5, 6});
+
+
+  Vector<std::string> NewFiles;
+  Set<uint32_t> NewFeatures, NewCov;
+
+  EXPECT_TRUE(M.Parse("3\n2\nAA\nBB\nC\n"
+                        "STARTED 0 1000\nFT 0 1 2 3\n"
+                        "STARTED 1 1001\nFT 1 4 5 6 \n"
+                        "STARTED 2 1002\nFT 2 6 1 3 \n"
+                        "", true));
+  EXPECT_EQ(M.Files.size(), 3U);
+  EXPECT_EQ(M.NumFilesInFirstCorpus, 2U);
+  EXPECT_TRUE(M.LastFailure.empty());
+  EXPECT_EQ(M.FirstNotProcessedFile, 3U);
+  EQ(M.Files[0].Features, {1, 2, 3});
+  EQ(M.Files[1].Features, {4, 5, 6});
+  EQ(M.Files[2].Features, {1, 3, 6});
+  EXPECT_EQ(0U, M.Merge({}, &NewFeatures, {}, &NewCov, &NewFiles));
+  EQ(NewFiles, {});
+
+  EXPECT_TRUE(M.Parse("3\n1\nA\nB\nC\n"
+                        "STARTED 0 1000\nFT 0 1 2 3\n"
+                        "STARTED 1 1001\nFT 1 4 5 6 \n"
+                        "STARTED 2 1002\nFT 2 6 1 3\n"
+                        "", true));
+  EQ(M.Files[0].Features, {1, 2, 3});
+  EQ(M.Files[1].Features, {4, 5, 6});
+  EQ(M.Files[2].Features, {1, 3, 6});
+  EXPECT_EQ(3U, M.Merge({}, &NewFeatures, {}, &NewCov, &NewFiles));
+  EQ(NewFiles, {"B"});
+
+  // Same as the above, but with InitialFeatures.
+  EXPECT_TRUE(M.Parse("2\n0\nB\nC\n"
+                        "STARTED 0 1001\nFT 0 4 5 6 \n"
+                        "STARTED 1 1002\nFT 1 6 1 3\n"
+                        "", true));
+  EQ(M.Files[0].Features, {4, 5, 6});
+  EQ(M.Files[1].Features, {1, 3, 6});
+  Set<uint32_t> InitialFeatures;
+  InitialFeatures.insert(1);
+  InitialFeatures.insert(2);
+  InitialFeatures.insert(3);
+  EXPECT_EQ(3U, M.Merge(InitialFeatures, &NewFeatures, {}, &NewCov, &NewFiles));
+  EQ(NewFiles, {"B"});
+}
+
+TEST(Merge, Merge) {
+
+  Merge("3\n1\nA\nB\nC\n"
+        "STARTED 0 1000\nFT 0 1 2 3\n"
+        "STARTED 1 1001\nFT 1 4 5 6 \n"
+        "STARTED 2 1002\nFT 2 6 1 3 \n",
+        {"B"}, 3);
+
+  Merge("3\n0\nA\nB\nC\n"
+        "STARTED 0 2000\nFT 0 1 2 3\n"
+        "STARTED 1 1001\nFT 1 4 5 6 \n"
+        "STARTED 2 1002\nFT 2 6 1 3 \n",
+        {"A", "B", "C"}, 6);
+
+  Merge("4\n0\nA\nB\nC\nD\n"
+        "STARTED 0 2000\nFT 0 1 2 3\n"
+        "STARTED 1 1101\nFT 1 4 5 6 \n"
+        "STARTED 2 1102\nFT 2 6 1 3 100 \n"
+        "STARTED 3 1000\nFT 3 1  \n",
+        {"A", "B", "C", "D"}, 7);
+
+  Merge("4\n1\nA\nB\nC\nD\n"
+        "STARTED 0 2000\nFT 0 4 5 6 7 8\n"
+        "STARTED 1 1100\nFT 1 1 2 3 \n"
+        "STARTED 2 1100\nFT 2 2 3 \n"
+        "STARTED 3 1000\nFT 3 1  \n",
+        {"B", "D"}, 3);
+}
+
+TEST(DFT, BlockCoverage) {
+  BlockCoverage Cov;
+  // Assuming C0 has 5 instrumented blocks,
+  // C1: 7 blocks, C2: 4, C3: 9, C4 never covered, C5: 15,
+
+  // Add C0
+  EXPECT_TRUE(Cov.AppendCoverage("C0 5\n"));
+  EXPECT_EQ(Cov.GetCounter(0, 0), 1U);
+  EXPECT_EQ(Cov.GetCounter(0, 1), 0U);  // not seen this BB yet.
+  EXPECT_EQ(Cov.GetCounter(0, 5), 0U);  // BB ID out of bounds.
+  EXPECT_EQ(Cov.GetCounter(1, 0), 0U);  // not seen this function yet.
+
+  EXPECT_EQ(Cov.GetNumberOfBlocks(0), 5U);
+  EXPECT_EQ(Cov.GetNumberOfCoveredBlocks(0), 1U);
+  EXPECT_EQ(Cov.GetNumberOfBlocks(1), 0U);
+
+  // Various errors.
+  EXPECT_FALSE(Cov.AppendCoverage("C0\n"));  // No total number.
+  EXPECT_FALSE(Cov.AppendCoverage("C0 7\n"));  // No total number.
+  EXPECT_FALSE(Cov.AppendCoverage("CZ\n"));  // Wrong function number.
+  EXPECT_FALSE(Cov.AppendCoverage("C1 7 7"));  // BB ID is too big.
+  EXPECT_FALSE(Cov.AppendCoverage("C1 100 7")); // BB ID is too big.
+
+  // Add C0 more times.
+  EXPECT_TRUE(Cov.AppendCoverage("C0 5\n"));
+  EXPECT_EQ(Cov.GetCounter(0, 0), 2U);
+  EXPECT_TRUE(Cov.AppendCoverage("C0 1 2 5\n"));
+  EXPECT_EQ(Cov.GetCounter(0, 0), 3U);
+  EXPECT_EQ(Cov.GetCounter(0, 1), 1U);
+  EXPECT_EQ(Cov.GetCounter(0, 2), 1U);
+  EXPECT_EQ(Cov.GetCounter(0, 3), 0U);
+  EXPECT_EQ(Cov.GetCounter(0, 4), 0U);
+  EXPECT_EQ(Cov.GetNumberOfCoveredBlocks(0), 3U);
+  EXPECT_TRUE(Cov.AppendCoverage("C0 1 3 4 5\n"));
+  EXPECT_EQ(Cov.GetCounter(0, 0), 4U);
+  EXPECT_EQ(Cov.GetCounter(0, 1), 2U);
+  EXPECT_EQ(Cov.GetCounter(0, 2), 1U);
+  EXPECT_EQ(Cov.GetCounter(0, 3), 1U);
+  EXPECT_EQ(Cov.GetCounter(0, 4), 1U);
+  EXPECT_EQ(Cov.GetNumberOfCoveredBlocks(0), 5U);
+
+  EXPECT_TRUE(Cov.AppendCoverage("C1 7\nC2 4\nC3 9\nC5 15\nC0 5\n"));
+  EXPECT_EQ(Cov.GetCounter(0, 0), 5U);
+  EXPECT_EQ(Cov.GetCounter(1, 0), 1U);
+  EXPECT_EQ(Cov.GetCounter(2, 0), 1U);
+  EXPECT_EQ(Cov.GetCounter(3, 0), 1U);
+  EXPECT_EQ(Cov.GetCounter(4, 0), 0U);
+  EXPECT_EQ(Cov.GetCounter(5, 0), 1U);
+
+  EXPECT_TRUE(Cov.AppendCoverage("C3 4 5 9\nC5 11 12 15"));
+  EXPECT_EQ(Cov.GetCounter(0, 0), 5U);
+  EXPECT_EQ(Cov.GetCounter(1, 0), 1U);
+  EXPECT_EQ(Cov.GetCounter(2, 0), 1U);
+  EXPECT_EQ(Cov.GetCounter(3, 0), 2U);
+  EXPECT_EQ(Cov.GetCounter(3, 4), 1U);
+  EXPECT_EQ(Cov.GetCounter(3, 5), 1U);
+  EXPECT_EQ(Cov.GetCounter(3, 6), 0U);
+  EXPECT_EQ(Cov.GetCounter(4, 0), 0U);
+  EXPECT_EQ(Cov.GetCounter(5, 0), 2U);
+  EXPECT_EQ(Cov.GetCounter(5, 10), 0U);
+  EXPECT_EQ(Cov.GetCounter(5, 11), 1U);
+  EXPECT_EQ(Cov.GetCounter(5, 12), 1U);
+}
+
+TEST(DFT, FunctionWeights) {
+  BlockCoverage Cov;
+  // unused function gets zero weight.
+  EXPECT_TRUE(Cov.AppendCoverage("C0 5\n"));
+  auto Weights = Cov.FunctionWeights(2);
+  EXPECT_GT(Weights[0], 0.);
+  EXPECT_EQ(Weights[1], 0.);
+
+  // Less frequently used function gets less weight.
+  Cov.clear();
+  EXPECT_TRUE(Cov.AppendCoverage("C0 5\nC1 5\nC1 5\n"));
+  Weights = Cov.FunctionWeights(2);
+  EXPECT_GT(Weights[0], Weights[1]);
+
+  // A function with more uncovered blocks gets more weight.
+  Cov.clear();
+  EXPECT_TRUE(Cov.AppendCoverage("C0 1 2 3 5\nC1 2 4\n"));
+  Weights = Cov.FunctionWeights(2);
+  EXPECT_GT(Weights[1], Weights[0]);
+
+  // A function with DFT gets more weight than the function w/o DFT.
+  Cov.clear();
+  EXPECT_TRUE(Cov.AppendCoverage("F1 111\nC0 3\nC1 1 2 3\n"));
+  Weights = Cov.FunctionWeights(2);
+  EXPECT_GT(Weights[1], Weights[0]);
+}
+
+
+TEST(Fuzzer, ForEachNonZeroByte) {
+  const size_t N = 64;
+  alignas(64) uint8_t Ar[N + 8] = {
+    0, 0, 0, 0, 0, 0, 0, 0,
+    1, 2, 0, 0, 0, 0, 0, 0,
+    0, 0, 3, 0, 4, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 5, 0, 6, 0, 0,
+    0, 0, 0, 0, 0, 0, 7, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 8,
+    9, 9, 9, 9, 9, 9, 9, 9,
+  };
+  typedef Vector<std::pair<size_t, uint8_t> > Vec;
+  Vec Res, Expected;
+  auto CB = [&](size_t FirstFeature, size_t Idx, uint8_t V) {
+    Res.push_back({FirstFeature + Idx, V});
+  };
+  ForEachNonZeroByte(Ar, Ar + N, 100, CB);
+  Expected = {{108, 1}, {109, 2}, {118, 3}, {120, 4},
+              {135, 5}, {137, 6}, {146, 7}, {163, 8}};
+  EXPECT_EQ(Res, Expected);
+
+  Res.clear();
+  ForEachNonZeroByte(Ar + 9, Ar + N, 109, CB);
+  Expected = {          {109, 2}, {118, 3}, {120, 4},
+              {135, 5}, {137, 6}, {146, 7}, {163, 8}};
+  EXPECT_EQ(Res, Expected);
+
+  Res.clear();
+  ForEachNonZeroByte(Ar + 9, Ar + N - 9, 109, CB);
+  Expected = {          {109, 2}, {118, 3}, {120, 4},
+              {135, 5}, {137, 6}, {146, 7}};
+  EXPECT_EQ(Res, Expected);
+}
+
+// FuzzerCommand unit tests. The arguments in the two helper methods below must
+// match.
+static void makeCommandArgs(Vector<std::string> *ArgsToAdd) {
+  assert(ArgsToAdd);
+  ArgsToAdd->clear();
+  ArgsToAdd->push_back("foo");
+  ArgsToAdd->push_back("-bar=baz");
+  ArgsToAdd->push_back("qux");
+  ArgsToAdd->push_back(Command::ignoreRemainingArgs());
+  ArgsToAdd->push_back("quux");
+  ArgsToAdd->push_back("-grault=garply");
+}
+
+static std::string makeCmdLine(const char *separator, const char *suffix) {
+  std::string CmdLine("foo -bar=baz qux ");
+  if (strlen(separator) != 0) {
+    CmdLine += separator;
+    CmdLine += " ";
+  }
+  CmdLine += Command::ignoreRemainingArgs();
+  CmdLine += " quux -grault=garply";
+  if (strlen(suffix) != 0) {
+    CmdLine += " ";
+    CmdLine += suffix;
+  }
+  return CmdLine;
+}
+
+TEST(FuzzerCommand, Create) {
+  std::string CmdLine;
+
+  // Default constructor
+  Command DefaultCmd;
+
+  CmdLine = DefaultCmd.toString();
+  EXPECT_EQ(CmdLine, "");
+
+  // Explicit constructor
+  Vector<std::string> ArgsToAdd;
+  makeCommandArgs(&ArgsToAdd);
+  Command InitializedCmd(ArgsToAdd);
+
+  CmdLine = InitializedCmd.toString();
+  EXPECT_EQ(CmdLine, makeCmdLine("", ""));
+
+  // Compare each argument
+  auto InitializedArgs = InitializedCmd.getArguments();
+  auto i = ArgsToAdd.begin();
+  auto j = InitializedArgs.begin();
+  while (i != ArgsToAdd.end() && j != InitializedArgs.end()) {
+    EXPECT_EQ(*i++, *j++);
+  }
+  EXPECT_EQ(i, ArgsToAdd.end());
+  EXPECT_EQ(j, InitializedArgs.end());
+
+  // Copy constructor
+  Command CopiedCmd(InitializedCmd);
+
+  CmdLine = CopiedCmd.toString();
+  EXPECT_EQ(CmdLine, makeCmdLine("", ""));
+
+  // Assignment operator
+  Command AssignedCmd;
+  AssignedCmd = CopiedCmd;
+
+  CmdLine = AssignedCmd.toString();
+  EXPECT_EQ(CmdLine, makeCmdLine("", ""));
+}
+
+TEST(FuzzerCommand, ModifyArguments) {
+  Vector<std::string> ArgsToAdd;
+  makeCommandArgs(&ArgsToAdd);
+  Command Cmd;
+  std::string CmdLine;
+
+  Cmd.addArguments(ArgsToAdd);
+  CmdLine = Cmd.toString();
+  EXPECT_EQ(CmdLine, makeCmdLine("", ""));
+
+  Cmd.addArgument("waldo");
+  EXPECT_TRUE(Cmd.hasArgument("waldo"));
+
+  CmdLine = Cmd.toString();
+  EXPECT_EQ(CmdLine, makeCmdLine("waldo", ""));
+
+  Cmd.removeArgument("waldo");
+  EXPECT_FALSE(Cmd.hasArgument("waldo"));
+
+  CmdLine = Cmd.toString();
+  EXPECT_EQ(CmdLine, makeCmdLine("", ""));
+}
+
+TEST(FuzzerCommand, ModifyFlags) {
+  Vector<std::string> ArgsToAdd;
+  makeCommandArgs(&ArgsToAdd);
+  Command Cmd(ArgsToAdd);
+  std::string Value, CmdLine;
+  ASSERT_FALSE(Cmd.hasFlag("fred"));
+
+  Value = Cmd.getFlagValue("fred");
+  EXPECT_EQ(Value, "");
+
+  CmdLine = Cmd.toString();
+  EXPECT_EQ(CmdLine, makeCmdLine("", ""));
+
+  Cmd.addFlag("fred", "plugh");
+  EXPECT_TRUE(Cmd.hasFlag("fred"));
+
+  Value = Cmd.getFlagValue("fred");
+  EXPECT_EQ(Value, "plugh");
+
+  CmdLine = Cmd.toString();
+  EXPECT_EQ(CmdLine, makeCmdLine("-fred=plugh", ""));
+
+  Cmd.removeFlag("fred");
+  EXPECT_FALSE(Cmd.hasFlag("fred"));
+
+  Value = Cmd.getFlagValue("fred");
+  EXPECT_EQ(Value, "");
+
+  CmdLine = Cmd.toString();
+  EXPECT_EQ(CmdLine, makeCmdLine("", ""));
+}
+
+TEST(FuzzerCommand, SetOutput) {
+  Vector<std::string> ArgsToAdd;
+  makeCommandArgs(&ArgsToAdd);
+  Command Cmd(ArgsToAdd);
+  std::string CmdLine;
+  ASSERT_FALSE(Cmd.hasOutputFile());
+  ASSERT_FALSE(Cmd.isOutAndErrCombined());
+
+  Cmd.combineOutAndErr(true);
+  EXPECT_TRUE(Cmd.isOutAndErrCombined());
+
+  CmdLine = Cmd.toString();
+  EXPECT_EQ(CmdLine, makeCmdLine("", "2>&1"));
+
+  Cmd.combineOutAndErr(false);
+  EXPECT_FALSE(Cmd.isOutAndErrCombined());
+
+  Cmd.setOutputFile("xyzzy");
+  EXPECT_TRUE(Cmd.hasOutputFile());
+
+  CmdLine = Cmd.toString();
+  EXPECT_EQ(CmdLine, makeCmdLine("", ">xyzzy"));
+
+  Cmd.setOutputFile("thud");
+  EXPECT_TRUE(Cmd.hasOutputFile());
+
+  CmdLine = Cmd.toString();
+  EXPECT_EQ(CmdLine, makeCmdLine("", ">thud"));
+
+  Cmd.combineOutAndErr();
+  EXPECT_TRUE(Cmd.isOutAndErrCombined());
+
+  CmdLine = Cmd.toString();
+  EXPECT_EQ(CmdLine, makeCmdLine("", ">thud 2>&1"));
+}
+
+TEST(Entropic, UpdateFrequency) {
+  const size_t One = 1, Two = 2;
+  const size_t FeatIdx1 = 0, FeatIdx2 = 42, FeatIdx3 = 12, FeatIdx4 = 26;
+  size_t Index;
+  // Create input corpus with default entropic configuration
+  struct EntropicOptions Entropic = {true, 0xFF, 100};
+  std::unique_ptr<InputCorpus> C(new InputCorpus("", Entropic));
+  std::unique_ptr<InputInfo> II(new InputInfo());
+
+  C->AddRareFeature(FeatIdx1);
+  C->UpdateFeatureFrequency(II.get(), FeatIdx1);
+  EXPECT_EQ(II->FeatureFreqs.size(), One);
+  C->AddRareFeature(FeatIdx2);
+  C->UpdateFeatureFrequency(II.get(), FeatIdx1);
+  C->UpdateFeatureFrequency(II.get(), FeatIdx2);
+  EXPECT_EQ(II->FeatureFreqs.size(), Two);
+  EXPECT_EQ(II->FeatureFreqs[0].second, 2);
+  EXPECT_EQ(II->FeatureFreqs[1].second, 1);
+
+  C->AddRareFeature(FeatIdx3);
+  C->AddRareFeature(FeatIdx4);
+  C->UpdateFeatureFrequency(II.get(), FeatIdx3);
+  C->UpdateFeatureFrequency(II.get(), FeatIdx3);
+  C->UpdateFeatureFrequency(II.get(), FeatIdx3);
+  C->UpdateFeatureFrequency(II.get(), FeatIdx4);
+
+  for (Index = 1; Index < II->FeatureFreqs.size(); Index++)
+    EXPECT_LT(II->FeatureFreqs[Index - 1].first, II->FeatureFreqs[Index].first);
+
+  II->DeleteFeatureFreq(FeatIdx3);
+  for (Index = 1; Index < II->FeatureFreqs.size(); Index++)
+    EXPECT_LT(II->FeatureFreqs[Index - 1].first, II->FeatureFreqs[Index].first);
+}
+
+double SubAndSquare(double X, double Y) {
+  double R = X - Y;
+  R = R * R;
+  return R;
+}
+
+TEST(Entropic, ComputeEnergy) {
+  const double Precision = 0.01;
+  struct EntropicOptions Entropic = {true, 0xFF, 100};
+  std::unique_ptr<InputCorpus> C(new InputCorpus("", Entropic));
+  std::unique_ptr<InputInfo> II(new InputInfo());
+  Vector<std::pair<uint32_t, uint16_t>> FeatureFreqs = {{1, 3}, {2, 3}, {3, 3}};
+  II->FeatureFreqs = FeatureFreqs;
+  II->NumExecutedMutations = 0;
+  II->UpdateEnergy(4);
+  EXPECT_LT(SubAndSquare(II->Energy, 1.450805), Precision);
+
+  II->NumExecutedMutations = 9;
+  II->UpdateEnergy(5);
+  EXPECT_LT(SubAndSquare(II->Energy, 1.525496), Precision);
+
+  II->FeatureFreqs[0].second++;
+  II->FeatureFreqs.push_back(std::pair<uint32_t, uint16_t>(42, 6));
+  II->NumExecutedMutations = 20;
+  II->UpdateEnergy(10);
+  EXPECT_LT(SubAndSquare(II->Energy, 1.792831), Precision);
+}
+
+int main(int argc, char **argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/rust-toolchain b/rust-toolchain
new file mode 100644
index 0000000..bf867e0
--- /dev/null
+++ b/rust-toolchain
@@ -0,0 +1 @@
+nightly
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..59dfc47
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,182 @@
+//! Bindings to [libFuzzer](http://llvm.org/docs/LibFuzzer.html): a runtime for
+//! coverage-guided fuzzing.
+//!
+//! See [the `cargo-fuzz`
+//! guide](https://rust-fuzz.github.io/book/cargo-fuzz.html) for a usage
+//! tutorial.
+//!
+//! The main export of this crate is [the `fuzz_target!`
+//! macro](./macro.fuzz_target.html), which allows you to define targets for
+//! libFuzzer to exercise.
+
+#![deny(missing_docs, missing_debug_implementations)]
+
+pub use arbitrary;
+
+extern "C" {
+    // We do not actually cross the FFI bound here.
+    #[allow(improper_ctypes)]
+    fn rust_fuzzer_test_input(input: &[u8]);
+}
+
+#[doc(hidden)]
+#[export_name = "LLVMFuzzerTestOneInput"]
+pub fn test_input_wrap(data: *const u8, size: usize) -> i32 {
+    let test_input = ::std::panic::catch_unwind(|| unsafe {
+        let data_slice = ::std::slice::from_raw_parts(data, size);
+        rust_fuzzer_test_input(data_slice);
+    });
+    if test_input.err().is_some() {
+        // hopefully the custom panic hook will be called before and abort the
+        // process before the stack frames are unwinded.
+        ::std::process::abort();
+    }
+    0
+}
+
+#[doc(hidden)]
+#[export_name = "LLVMFuzzerInitialize"]
+pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
+    // Registers a panic hook that aborts the process before unwinding.
+    // It is useful to abort before unwinding so that the fuzzer will then be
+    // able to analyse the process stack frames to tell different bugs appart.
+    //
+    // HACK / FIXME: it would be better to use `-C panic=abort` but it's currently
+    // impossible to build code using compiler plugins with this flag.
+    // We will be able to remove this code when
+    // https://github.com/rust-lang/cargo/issues/5423 is fixed.
+    let default_hook = ::std::panic::take_hook();
+    ::std::panic::set_hook(Box::new(move |panic_info| {
+        default_hook(panic_info);
+        ::std::process::abort();
+    }));
+    0
+}
+
+/// Define a fuzz target.
+///
+/// ## Example
+///
+/// This example takes a `&[u8]` slice and attempts to parse it. The parsing
+/// might fail and return an `Err`, but it shouldn't ever panic or segfault.
+///
+/// ```no_run
+/// #![no_main]
+///
+/// use libfuzzer_sys::fuzz_target;
+///
+/// // Note: `|input|` is short for `|input: &[u8]|`.
+/// fuzz_target!(|input| {
+///     let _result: Result<_, _> = my_crate::parse(input);
+/// });
+/// # mod my_crate { pub fn parse(_: &[u8]) -> Result<(), ()> { unimplemented!() } }
+/// ```
+///
+/// ## Arbitrary Input Types
+///
+/// The input is a `&[u8]` slice by default, but you can take arbitrary input
+/// types, as long as the type implements [the `arbitrary` crate's `Arbitrary`
+/// trait](https://docs.rs/arbitrary/*/arbitrary/trait.Arbitrary.html) (which is
+/// also re-exported as `libfuzzer_sys::arbitrary::Arbitrary` for convenience).
+///
+/// For example, if you wanted to take an arbitrary RGB color, you could do the
+/// following:
+///
+/// ```no_run
+/// #![no_main]
+///
+/// use libfuzzer_sys::{arbitrary::{Arbitrary, Unstructured}, fuzz_target};
+///
+/// #[derive(Debug)]
+/// pub struct Rgb {
+///     r: u8,
+///     g: u8,
+///     b: u8,
+/// }
+///
+/// impl Arbitrary for Rgb {
+///     fn arbitrary<U>(raw: &mut U) -> Result<Self, U::Error>
+///     where
+///         U: Unstructured + ?Sized
+///     {
+///         let mut buf = [0; 3];
+///         raw.fill_buffer(&mut buf)?;
+///         let r = buf[0];
+///         let g = buf[1];
+///         let b = buf[2];
+///         Ok(Rgb { r, g, b })
+///     }
+/// }
+///
+/// // Write a fuzz target that works with RGB colors instead of raw bytes.
+/// fuzz_target!(|color: Rgb| {
+///     my_crate::convert_color(color);
+/// });
+/// # mod my_crate { fn convert_color(_: super::Rgb) {} }
+#[macro_export]
+macro_rules! fuzz_target {
+    (|$bytes:ident| $body:block) => {
+        #[no_mangle]
+        pub extern "C" fn rust_fuzzer_test_input($bytes: &[u8]) {
+            // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
+            // formatting of the input to that file. This is only intended for
+            // `cargo fuzz`'s use!
+            if let Ok(path) = std::env::var("RUST_LIBFUZZER_DEBUG_PATH") {
+                use std::io::Write;
+                let mut file = std::fs::File::create(path)
+                    .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file");
+                writeln!(&mut file, "{:?}", $bytes)
+                    .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file");
+                return;
+            }
+
+            $body
+        }
+    };
+
+    (|$data:ident: &[u8]| $body:block) => {
+        fuzz_target!(|$data| $body);
+    };
+
+    (|$data:ident: $dty: ty| $body:block) => {
+        #[no_mangle]
+        pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) {
+            use libfuzzer_sys::arbitrary::{Arbitrary, Unstructured};
+
+            // Early exit if we don't have enough bytes for the `Arbitrary`
+            // implementation. This helps the fuzzer avoid exploring all the
+            // different not-enough-input-bytes paths inside the `Arbitrary`
+            // implementation. Additionally, it exits faster, letting the fuzzer
+            // get to longer inputs that actually lead to interesting executions
+            // quicker.
+            if bytes.len() < <$dty as Arbitrary>::size_hint(0).0 {
+                return;
+            }
+
+            let mut u = Unstructured::new(bytes);
+            let data = <$dty as Arbitrary>::arbitrary_take_rest(u);
+
+            // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
+            // formatting of the input to that file. This is only intended for
+            // `cargo fuzz`'s use!
+            if let Ok(path) = std::env::var("RUST_LIBFUZZER_DEBUG_PATH") {
+                use std::io::Write;
+                let mut file = std::fs::File::create(path)
+                    .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file");
+                (match data {
+                    Ok(data) => writeln!(&mut file, "{:#?}", data),
+                    Err(err) => writeln!(&mut file, "Arbitrary Error: {}", err),
+                })
+                .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file");
+                return;
+            }
+
+            let $data = match data {
+                Ok(d) => d,
+                Err(_) => return,
+            };
+
+            $body
+        }
+    };
+}
diff --git a/update-libfuzzer.sh b/update-libfuzzer.sh
new file mode 100755
index 0000000..088b8cf
--- /dev/null
+++ b/update-libfuzzer.sh
@@ -0,0 +1,21 @@
+#!/bin/bash -ex
+
+# Usage:
+#
+#     ./update-libfuzzer $commit_hash
+#
+# Where `$commit_hash` is a commit hash from
+# https://github.com/llvm-mirror/llvm-project
+
+set -ex
+
+cd "$(dirname $0)"
+project_dir="$(pwd)"
+
+tmp_dir="$(mktemp -d)"
+
+git clone https://github.com/llvm/llvm-project.git "$tmp_dir"
+cd "$tmp_dir"
+git checkout "$1"
+rm -rf "$project_dir/libfuzzer/"
+mv "$tmp_dir/compiler-rt/lib/fuzzer/" "$project_dir/libfuzzer/"