about summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-x.custom-format.py3
-rw-r--r--.gitignore14
-rw-r--r--.travis.yml2
-rw-r--r--Dockerfile20
-rw-r--r--GNUmakefile14
-rw-r--r--README.md630
-rw-r--r--TODO.md9
-rwxr-xr-xafl-plot14
-rwxr-xr-xafl-system-config2
-rwxr-xr-xafl-whatsup9
-rw-r--r--custom_mutators/README.md19
-rw-r--r--custom_mutators/honggfuzz/Makefile15
-rw-r--r--custom_mutators/honggfuzz/README.md12
-rw-r--r--custom_mutators/honggfuzz/common.h0
-rw-r--r--custom_mutators/honggfuzz/custom_mutator_helpers.h22
-rw-r--r--custom_mutators/honggfuzz/honggfuzz.c143
-rw-r--r--custom_mutators/honggfuzz/honggfuzz.h460
-rw-r--r--custom_mutators/honggfuzz/input.h106
l---------custom_mutators/honggfuzz/libhfcommon1
l---------custom_mutators/honggfuzz/log.h1
-rw-r--r--custom_mutators/honggfuzz/mangle.c1039
-rw-r--r--custom_mutators/honggfuzz/mangle.h32
l---------custom_mutators/honggfuzz/util.h1
-rw-r--r--dictionaries/rtf.dict57
-rw-r--r--docs/Changelog.md18
-rw-r--r--docs/custom_mutators.md2
-rw-r--r--docs/parallel_fuzzing.md14
-rw-r--r--docs/screenshot.pngbin0 -> 117199 bytes
-rw-r--r--examples/afl_frida/Makefile23
-rw-r--r--examples/afl_frida/README.md34
-rw-r--r--examples/afl_frida/afl-frida.c541
-rw-r--r--examples/afl_frida/afl-frida.h53
-rw-r--r--examples/afl_frida/libtestinstr.c35
-rw-r--r--examples/afl_network_proxy/afl-network-client.c4
-rw-r--r--examples/afl_untracer/README.md3
-rw-r--r--examples/afl_untracer/TODO2
-rw-r--r--examples/afl_untracer/afl-untracer.c24
-rw-r--r--examples/custom_mutators/post_library_gif.so.c2
-rw-r--r--examples/defork/Makefile64
-rw-r--r--examples/defork/README.md11
-rw-r--r--examples/defork/defork.c50
-rwxr-xr-xexamples/defork/forking_targetbin0 -> 19520 bytes
-rw-r--r--examples/defork/forking_target.c48
-rw-r--r--gcc_plugin/GNUmakefile9
-rw-r--r--gcc_plugin/afl-gcc-fast.c2
-rw-r--r--include/afl-fuzz.h17
-rw-r--r--include/config.h6
-rw-r--r--libdislocator/libdislocator.so.c15
-rw-r--r--libtokencap/Makefile13
-rw-r--r--libtokencap/libtokencap.so.c40
-rw-r--r--llvm_mode/GNUmakefile11
-rw-r--r--llvm_mode/README.lto.md54
-rw-r--r--llvm_mode/README.md4
-rw-r--r--llvm_mode/afl-clang-fast.c42
-rw-r--r--llvm_mode/afl-llvm-lto-instrim.so.cc6
-rw-r--r--llvm_mode/afl-llvm-lto-instrumentation.so.cc6
-rw-r--r--llvm_mode/afl-llvm-rt.o.c10
-rw-r--r--llvm_mode/compare-transform-pass.so.cc4
-rw-r--r--llvm_mode/split-compares-pass.so.cc391
-rw-r--r--qemu_mode/patches/afl-qemu-cpu-inl.h8
-rw-r--r--src/afl-analyze.c29
-rw-r--r--src/afl-forkserver.c29
-rw-r--r--src/afl-fuzz-init.c258
-rw-r--r--src/afl-fuzz-mutators.c34
-rw-r--r--src/afl-fuzz-redqueen.c24
-rw-r--r--src/afl-fuzz-run.c2
-rw-r--r--src/afl-fuzz-stats.c154
-rw-r--r--src/afl-fuzz.c58
-rw-r--r--src/afl-gcc.c5
-rw-r--r--src/afl-showmap.c29
-rw-r--r--src/afl-tmin.c29
-rw-r--r--test/test-floatingpoint.c26
-rw-r--r--test/test-fp_cases.c213
-rwxr-xr-xtest/test.sh22
74 files changed, 4594 insertions, 509 deletions
diff --git a/.custom-format.py b/.custom-format.py
index 6f1b0bfa..60f6d9c3 100755
--- a/.custom-format.py
+++ b/.custom-format.py
@@ -32,7 +32,8 @@ if CLANG_FORMAT_BIN is None:
         p = subprocess.Popen(["clang-format-10", "--version"], stdout=subprocess.PIPE)
         o, _ = p.communicate()
         o = str(o, "utf-8")
-        o = o[len("clang-format version "):].strip()
+        o = re.sub(r".*ersion ", "", o)
+        #o = o[len("clang-format version "):].strip()
         o = o[:o.find(".")]
         o = int(o)
     except:
diff --git a/.gitignore b/.gitignore
index 1000cc6f..b2c2fc62 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,15 @@
 .test
 .test2
+.sync_tmp
 *.o
 *.so
 *.pyc
+*.dSYM
+as
+ld
+in
+out
+core*
 afl-analyze
 afl-as
 afl-clang
@@ -41,13 +48,10 @@ afl-system-config.8
 afl-tmin.8
 afl-whatsup.8
 qemu_mode/libcompcov/compcovtest
-as
-ld
 qemu_mode/qemu-*
 unicorn_mode/samples/*/\.test-*
 unicorn_mode/samples/*/output/
 unicorn_mode/unicornafl
-core\.*
 test/unittests/unit_maybe_alloc
 test/unittests/unit_preallocable
 test/unittests/unit_list
@@ -55,3 +59,7 @@ test/unittests/unit_rand
 test/unittests/unit_hash
 examples/afl_network_proxy/afl-network-server
 examples/afl_network_proxy/afl-network-client
+examples/afl_frida/afl-frida
+examples/afl_frida/libtestinstr.so
+examples/afl_frida/frida-gum-example.c
+examples/afl_frida/frida-gum.h
diff --git a/.travis.yml b/.travis.yml
index 4271b821..dda57bbb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -51,6 +51,8 @@ script:
   - gcc -v
   - clang -v
   - sudo -E ./afl-system-config
+  - sudo sysctl -w kernel.shmmax=10000000000
+  - free ; sudo sysctl -a|grep -i shm ; ipcs -m -l ; ipcs -m
   - if [ "$TRAVIS_OS_NAME" = "osx" ]; then export LLVM_CONFIG=`pwd`/"$NAME" ; make source-only ASAN_BUILD=1 ; fi
   - if [ "$TRAVIS_OS_NAME" = "linux" -a "$TRAVIS_CPU_ARCH" = "amd64" ]; then make distrib ASAN_BUILD=1 ; fi
   - if [ "$TRAVIS_CPU_ARCH" = "arm64" ] ; then echo DEBUG ; find / -name llvm-config.h 2>/dev/null; apt-cache search clang | grep clang- ; apt-cache search llvm | grep llvm- ; dpkg -l | egrep 'clang|llvm'; echo DEBUG ; export LLVM_CONFIG=llvm-config-6.0 ; make ASAN_BUILD=1 ; cd qemu_mode && sh ./build_qemu_support.sh ; cd .. ; fi
diff --git a/Dockerfile b/Dockerfile
index 905e8265..0b1645b4 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -5,7 +5,7 @@
 # has focal has gcc-10 but not g++-10 ...
 #
 
-FROM ubuntu:20.04
+FROM ubuntu:20.04 AS aflplusplus
 MAINTAINER afl++ team <afl@aflplus.plus>
 LABEL "about"="AFLplusplus docker image"
 
@@ -20,7 +20,7 @@ RUN apt-get update && apt-get upgrade -y && \
     python3 python3-dev python3-setuptools python-is-python3 \
     libtool libtool-bin \
     libglib2.0-dev \
-    wget vim jupp nano \
+    wget vim jupp nano bash-completion \
     apt-utils apt-transport-https ca-certificates gnupg dialog \
     libpixman-1-dev
 
@@ -46,17 +46,15 @@ RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0
 
 RUN rm -rf /var/cache/apt/archives/*
 
-ARG CC=gcc-10
-ARG CXX=g++-10
-ARG LLVM_CONFIG=llvm-config-11
+ENV LLVM_CONFIG=llvm-config-11
+ENV AFL_SKIP_CPUFREQ=1
 
-RUN git clone https://github.com/AFLplusplus/AFLplusplus
-RUN cd AFLplusplus && export REAL_CXX=g++-10 && make distrib && \
-    make install && make clean
+RUN git clone https://github.com/AFLplusplus/AFLplusplus /AFLplusplus
+RUN cd /AFLplusplus && export REAL_CXX=g++-10 && export CC=gcc-10 && \
+    export CXX=g++-10 && make distrib && make install && make clean
 
-RUN git clone https://github.com/vanhauser-thc/afl-cov afl-cov
-RUN cd afl-cov && make install
+RUN git clone https://github.com/vanhauser-thc/afl-cov /afl-cov
+RUN cd /afl-cov && make install
 
 RUN echo 'alias joe="jupp --wordwrap"' >> ~/.bashrc
 
-ENV AFL_SKIP_CPUFREQ=1
diff --git a/GNUmakefile b/GNUmakefile
index 748cd73c..e2d7314f 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -65,7 +65,7 @@ endif
 
 ifeq "$(shell uname)" "SunOS"
  CFLAGS_OPT += -Wno-format-truncation
- LDFLAGS=-lkstat
+ LDFLAGS=-lkstat -lrt
 endif
 
 ifdef STATIC
@@ -96,7 +96,7 @@ ifneq "$(shell uname -m)" "x86_64"
 endif
 
 CFLAGS     ?= -O3 -funroll-loops $(CFLAGS_OPT)
-override CFLAGS += -Wall -g -Wno-pointer-sign -Wmissing-declarations\
+override CFLAGS += -Wall -g -Wno-pointer-sign -Wmissing-declarations -Wno-unused-result \
 			  -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \
 			  -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
 
@@ -196,7 +196,7 @@ else
 endif
 
 ifneq "$(filter Linux GNU%,$(shell uname))" ""
-  LDFLAGS += -ldl
+  LDFLAGS += -ldl -lrt
 endif
 
 ifneq "$(findstring FreeBSD, $(shell uname))" ""
@@ -254,13 +254,13 @@ ifeq "$(shell echo '$(HASH)include <sys/ipc.h>@$(HASH)include <sys/shm.h>@int ma
 else
 	SHMAT_OK=0
 	override CFLAGS+=-DUSEMMAP=1
-	LDFLAGS += -Wno-deprecated-declarations -lrt
+	LDFLAGS += -Wno-deprecated-declarations
 endif
 
 ifdef TEST_MMAP
 	SHMAT_OK=0
 	override CFLAGS += -DUSEMMAP=1
-	LDFLAGS += -Wno-deprecated-declarations -lrt
+	LDFLAGS += -Wno-deprecated-declarations
 endif
 
 all:	test_x86 test_shm test_python ready $(PROGS) afl-as test_build all_done
@@ -455,10 +455,10 @@ code-format:
 	./.custom-format.py -i llvm_mode/*.h
 	./.custom-format.py -i llvm_mode/*.cc
 	./.custom-format.py -i gcc_plugin/*.c
-	#./.custom-format.py -i gcc_plugin/*.h
+	@#./.custom-format.py -i gcc_plugin/*.h
 	./.custom-format.py -i gcc_plugin/*.cc
 	./.custom-format.py -i custom_mutators/*/*.c
-	./.custom-format.py -i custom_mutators/*/*.h
+	@#./.custom-format.py -i custom_mutators/*/*.h # destroys input.h :-(
 	./.custom-format.py -i examples/*/*.c
 	./.custom-format.py -i examples/*/*.h
 	./.custom-format.py -i test/*.c
diff --git a/README.md b/README.md
index 14a42b7e..074be4b0 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# american fuzzy lop plus plus (afl++)
+# American Fuzzy Lop plus plus (afl++)
 
   <img align="right" src="https://raw.githubusercontent.com/andreafioraldi/AFLplusplus-website/master/static/logo_256x256.png" alt="AFL++ Logo">
 
@@ -8,61 +8,36 @@
 
   Github Version: 2.66d
 
-  includes all necessary/interesting changes from Google's afl 2.56b
-
-  Originally developed by Michal "lcamtuf" Zalewski.
-
   Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
 
   afl++ is maintained by:
-    * Marc "van Hauser" Heuse <mh@mh-sec.de>,
-    * Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>,
-    * Andrea Fioraldi <andreafioraldi@gmail.com> and
-    * Dominik Maier <mail@dmnk.co>.
-
-  Note that although afl now has a Google afl repository [https://github.com/Google/afl](https://github.com/Google/afl),
-  it is unlikely to receive any notable enhancements: [https://twitter.com/Dor3s/status/1154737061787660288](https://twitter.com/Dor3s/status/1154737061787660288)
-
-## The enhancements compared to the original stock afl
-
-  Many improvements were made over the official afl release - which did not
-  get any feature improvements since November 2017.
-
-  Among other changes afl++ has a more performant llvm_mode, supports
-  llvm up to version 11, QEMU 3.1, more speed and crashfixes for QEMU,
-  better *BSD and Android support and much, much more.
-
-  Additionally the following features and patches have been integrated:
-
-  * AFLfast's power schedules by Marcel Böhme: [https://github.com/mboehme/aflfast](https://github.com/mboehme/aflfast)
-
-  * The new excellent MOpt mutator: [https://github.com/puppet-meteor/MOpt-AFL](https://github.com/puppet-meteor/MOpt-AFL)
-
-  * InsTrim, a very effective CFG llvm_mode instrumentation implementation for large targets: [https://github.com/csienslab/instrim](https://github.com/csienslab/instrim)
 
-  * C. Holler's afl-fuzz Python mutator module and llvm_mode instrument file support: [https://github.com/choller/afl](https://github.com/choller/afl)
-
-  * Custom mutator by a library (instead of Python) by kyakdan
+  * Marc "van Hauser" Heuse <mh@mh-sec.de>,
+  * Heiko "hexcoder-" Eißfeldt <heiko.eissfeldt@hexco.de>,
+  * Andrea Fioraldi <andreafioraldi@gmail.com> and
+  * Dominik Maier <mail@dmnk.co>.
 
-  * Unicorn mode which allows fuzzing of binaries from completely different platforms (integration provided by domenukk)
-
-  * LAF-Intel or CompCov support for llvm_mode, qemu_mode and unicorn_mode
+  Originally developed by Michal "lcamtuf" Zalewski.
 
-  * NeverZero patch for afl-gcc, llvm_mode, qemu_mode and unicorn_mode which prevents a wrapping map value to zero, increases coverage
-  
-  * Persistent mode and deferred forkserver for qemu_mode
-  
-  * Win32 PE binary-only fuzzing with QEMU and Wine
+  afl++ is a superiour fork to Google's afl - more speed, more and better
+  mutations, more and better instrumentation, custom module support, etc.
 
-  * Radamsa mutator (as a custom mutator).
+## Contents
 
-  * QBDI mode to fuzz android native libraries via QBDI framework
+  1. [Features](#important-features-of-afl)
+  2. [How to compile and install afl++](#building-and-installing-afl)
+  3. [How to fuzz a target](#how-to-fuzz-with-afl)
+  4. [Fuzzing binary-only targets](#fuzzing-binary-only-targets)
+  5. [Good examples and writeups of afl++ usages](#good-examples-and-writeups)
+  6. [Branches](#branches)
+  7. [Want to help?](#help-wanted)
+  8. [Detailed help and description of afl++](#challenges-of-guided-fuzzing)
 
-  * The new CmpLog instrumentation for LLVM and QEMU inspired by [Redqueen](https://www.syssec.ruhr-uni-bochum.de/media/emma/veroeffentlichungen/2018/12/17/NDSS19-Redqueen.pdf)
+## Important features of afl++
 
-  * LLVM mode Ngram coverage by Adrian Herrera [https://github.com/adrianherrera/afl-ngram-pass](https://github.com/adrianherrera/afl-ngram-pass)
-
-  A more thorough list is available in the [PATCHES](docs/PATCHES.md) file.
+  afl++ supports llvm up to version 12, very fast binary fuzzing with QEMU 3.1
+  with laf-intel and redqueen, unicorn mode, gcc plugin, full *BSD, Solaris and
+  Android support and much, much, much more.
 
   | Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode        | unicorn_mode |
   | ----------------------- |:-------:|:---------:|:----------:|:----------------:|:------------:|
@@ -75,23 +50,37 @@
   | InsTrim                 |         |     x     |            |                  |              |
   | Ngram prev_loc coverage |         |     x(6)  |            |                  |              |
   | Context coverage        |         |     x     |            |                  |              |
+  | Auto dictionary         |         |     x(7)  |            |                  |              |
   | Snapshot LKM support    |         |     x     |            |        (x)(5)    |              |
 
-  neverZero:
-
-  (1) default for LLVM >= 9.0, env var for older version due an efficiency bug in llvm <= 8
+  1. default for LLVM >= 9.0, env var for older version due an efficiency bug in llvm <= 8
+  2. GCC creates non-performant code, hence it is disabled in gcc_plugin
+  3. partially via AFL_CODE_START/AFL_CODE_END
+  4. with pcguard mode and LTO mode for LLVM >= 11
+  5. upcoming, development in the branch
+  6. not compatible with LTO instrumentation and needs at least LLVM >= 4.1
+  7. only in LTO mode with LLVM >= 11
 
-  (2) GCC creates non-performant code, hence it is disabled in gcc_plugin
+  Among others, the following features and patches have been integrated:
 
-  (3) partially via AFL_CODE_START/AFL_CODE_END
-
-  (4) Only for LLVM >= 11 and not all targets compile
-
-  (5) upcoming, development in the branch
+  * NeverZero patch for afl-gcc, llvm_mode, qemu_mode and unicorn_mode which prevents a wrapping map value to zero, increases coverage
+  * Persistent mode and deferred forkserver for qemu_mode
+  * Unicorn mode which allows fuzzing of binaries from completely different platforms (integration provided by domenukk)
+  * The new CmpLog instrumentation for LLVM and QEMU inspired by [Redqueen](https://www.syssec.ruhr-uni-bochum.de/media/emma/veroeffentlichungen/2018/12/17/NDSS19-Redqueen.pdf)
+  * Win32 PE binary-only fuzzing with QEMU and Wine
+  * AFLfast's power schedules by Marcel Böhme: [https://github.com/mboehme/aflfast](https://github.com/mboehme/aflfast)
+  * The MOpt mutator: [https://github.com/puppet-meteor/MOpt-AFL](https://github.com/puppet-meteor/MOpt-AFL)
+  * LLVM mode Ngram coverage by Adrian Herrera [https://github.com/adrianherrera/afl-ngram-pass](https://github.com/adrianherrera/afl-ngram-pass)
+  * InsTrim, an effective CFG llvm_mode instrumentation implementation for large targets: [https://github.com/csienslab/instrim](https://github.com/csienslab/instrim)
+  * C. Holler's afl-fuzz Python mutator module and llvm_mode instrument file support: [https://github.com/choller/afl](https://github.com/choller/afl)
+  * Custom mutator by a library (instead of Python) by kyakdan
+  * LAF-Intel/CompCov support for llvm_mode, qemu_mode and unicorn_mode (with enhanced capabilities)
+  * Radamsa and hongfuzz mutators (as custom mutators).
+  * QBDI mode to fuzz android native libraries via QBDI framework
 
-  (6) not compatible with LTO instrumentation and needs at least LLVM >= 4.1
+  A more thorough list is available in the [PATCHES](docs/PATCHES.md) file.
 
-  So all in all this is the best-of afl that is currently out there :-)
+  So all in all this is the best-of afl that is out there :-)
 
   For new versions and additional information, check out:
   [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)
@@ -115,7 +104,7 @@
 
   For releases, please see the [Releases](https://github.com/AFLplusplus/AFLplusplus/releases) tab.
 
-## Google Summer of Code 2020 (and any other students and enthusiast developers)
+## Help wanted
 
 We are happy to be part of [Google Summer of Code 2020](https://summerofcode.withgoogle.com/organizations/5100744400699392/)! :-)
 
@@ -140,7 +129,7 @@ hence afl-clang-lto is available!) or just pull directly from the docker hub:
 docker pull aflplusplus/aflplusplus
 docker run -ti -v /location/of/your/target:/src aflplusplus/aflplusplus
 ```
-This container is automatically generated when a push to master happens.
+This image is automatically generated when a push to master happens.
 You will find your target source code in /src in the container.
 
 If you want to build afl++ yourself you have many options.
@@ -151,7 +140,7 @@ sudo apt install build-essential libtool-bin python3-dev automake flex bison lib
 make distrib
 sudo make install
 ```
-It is recommended to install the newest available gcc and clang and llvm-dev
+It is recommended to install the newest available gcc, clang and llvm-dev
 possible in your distribution!
 
 Note that "make distrib" also builds llvm_mode, qemu_mode, unicorn_mode and
@@ -197,6 +186,457 @@ These build options exist:
 
 e.g.: make ASAN_BUILD=1
 
+## Good examples and writeups
+
+Here are some good writeups to show how to effectively use AFL++:
+
+ * [https://aflplus.plus/docs/tutorials/libxml2_tutorial/](https://aflplus.plus/docs/tutorials/libxml2_tutorial/)
+ * [https://bananamafia.dev/post/gb-fuzz/](https://bananamafia.dev/post/gb-fuzz/)
+ * [https://securitylab.github.com/research/fuzzing-challenges-solutions-1](https://securitylab.github.com/research/fuzzing-challenges-solutions-1)
+ * [https://securitylab.github.com/research/fuzzing-sockets-FTP](https://securitylab.github.com/research/fuzzing-sockets-FTP)
+
+If you are interested in fuzzing structured data (where you define what the
+structure is), these links have you covered:
+ * Superion for afl++: [https://github.com/adrian-rt/superion-mutator](https://github.com/adrian-rt/superion-mutator)
+ * libprotobuf raw: [https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator)
+ * libprotobuf for old afl++ API: [https://github.com/thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator)
+
+If you find other good ones, please send them to us :-)
+
+## How to fuzz with afl++
+
+The following describes how to fuzz with a target if source code is available.
+If you have a binary-only target please skip to [#Instrumenting binary-only apps](#Instrumenting binary-only apps)
+
+Fuzzing source code is a two step process.
+
+1. compile the target with a special compiler that prepares the target to be
+   fuzzed efficiently. This step is called "instrumenting a target".
+2. Prepare the fuzzing by selecting and optimizing the input corpus for the
+   target.
+3. perform the fuzzing of the target by randomly mutating input and assessing
+   if a generated input was processed in a new path in the target binary
+
+### 1. Instrumenting that target
+
+#### a) Selecting the best afl++ compiler for instrumenting the target
+
+afl++ comes with different compilers and instrumentation options.
+The following evaluation flow will help you to select the best possible.
+
+It is highly recommended to have the newest llvm version possible installed,
+anything below 9 is not recommended.
+
+```
++--------------------------------+
+| clang/clang++ 11+ is available | --> use afl-clang-lto and afl-clang-lto++
++--------------------------------+     see [llvm/README.lto.md](llvm/README.lto.md)
+    |
+    | if not, or if the target fails with with afl-clang-lto/++
+    |
+    v
++---------------------------------+
+| clang/clang++ 3.3+ is available | --> use afl-clang-fast and afl-clang-fast++
++---------------------------------+     see [llvm/README.md](llvm/README.md)
+    |
+    | if not, or if the target fails with afl-clang-fast/++
+    |
+    v
+ +--------------------------------+
+ | if you want to instrument only | -> use afl-gcc-fast and afl-gcc-fast++
+ | parts of the target            |    see [gcc_plugin/README.md](gcc_plugin/README.md) and
+ +--------------------------------+    [gcc_plugin/README.instrument_file.md](gcc_plugin/README.instrument_file.md)
+    |
+    | if not, or if you do not have a gcc with plugin support
+    |
+    v
+   use afl-gcc and afl-g++
+```
+
+Clickable README links for the chosen compiler:
+
+  * [afl-clang-lto](llvm/README.lto.md)
+  * [afl-clang-fast](llvm/README.md)
+  * [afl-gcc-fast](gcc_plugin/README.md)
+  * afl-gcc has no README as it has no features
+
+#### b) Selecting instrumentation options
+
+The following options are available when you instrument with afl-clang-fast or
+afl-clang-lto:
+
+ * Splitting integer, string, float and switch compares so afl++ can easier
+   solve these. This is an important option if you do not have a very good
+   good and large input corpus. This technique is called laf-intel or COMPCOV.
+   To use this set the following environment variable before compiling the
+   target: `export AFL_LLVM_LAF_ALL=1`
+   You can read more about this in [llvm/README.laf-intel.md](llvm/README.laf-intel.md)
+ * A different technique is to instrument the target so that any compare values
+   in the target are sent to afl++ which then tries to put this value into the
+   fuzzing data at different locations. This technique is very fast and good -
+   if the target does not transform input data before comparison. Therefore
+   technique is called `input to state` or `redqueen`.
+   If you want to use this technique, then you have to compile the target
+   twice, once specifically with/for this mode.
+   You can read more about this in [llvm_mode/README.cmplog.md](llvm_mode/README.cmplog.md)
+
+If you use afl-clang-fast, afl-clang-lto or afl-gcc-fast you have the option to
+selectivly only instrument parts of the target that you are interested in:
+
+ * To instrument only those parts of the target that you are interested in
+   create a file with all the filenames of the source code that should be
+   instrumented.
+   For afl-clang-lto and afl-gcc-fast - or afl-clang-fast if either the clang
+   version is < 7 or the CLASSIC instrumentation is used - just put one
+   filename per line, no directory information necessary, and set
+   `export AFL_LLVM_INSTRUMENT_FILE=yourfile.txt`
+   see [llvm_mode/README.instrument_file.md](llvm_mode/README.instrument_file.md)
+   For afl-clang-fast > 6.0 or if PCGUARD instrumentation is used then use the
+   llvm sancov allow-list feature: [http://clang.llvm.org/docs/SanitizerCoverage.html](http://clang.llvm.org/docs/SanitizerCoverage.html)
+
+There are many more options and modes available however these are most of the
+time less effective. See:
+ * [llvm_mode/README.ctx.md](llvm_mode/README.ctx.md)
+ * [llvm_mode/README.ngram.md](llvm_mode/README.ngram.md)
+ * [llvm_mode/README.instrim.md](llvm_mode/README.instrim.md)
+ * [llvm_mode/README.neverzero.md](llvm_mode/README.neverzero.md)
+
+#### c) Modify the target
+
+If the target has features that makes fuzzing more difficult, e.g.
+checksums, HMAC etc. then modify the source code so that this is
+removed.
+This can even be done for productional source code be eliminating
+these checks within this specific defines:
+
+```
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+  // say that the checksum or HMAC was fine - or whatever is required
+  // to eliminate the need for the fuzzer to guess the right checksum
+  return 0;
+#endif
+```
+
+#### d) Instrument the target
+
+In this step the target source code is compiled so that it can be fuzzed.
+
+Basically you have to tell the target build system that the selected afl++
+compiler is used. Also - if possible - you should always configure the
+build system that the target is compiled statically and not dynamically.
+How to do this is described below.
+
+Then build the target. (Usually with `make`)
+
+##### configure
+
+For `configure` build systems this is usually done by:
+`CC=afl-clang-fast CXX=afl-clang-fast++ ./configure --disable-shared`
+
+Note that if you using the (better) afl-clang-lto compiler you also have to
+AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as it is
+described in [llvm/README.lto.md](llvm/README.lto.md)
+
+##### cmake
+
+For `configure` build systems this is usually done by:
+`mkdir build; cd build; CC=afl-clang-fast CXX=afl-clang-fast++ cmake ..`
+
+Some cmake scripts require something like `-DCMAKE_CC=... -DCMAKE_CXX=...`
+or `-DCMAKE_C_COMPILER=... DCMAKE_CPP_COMPILER=...` instead.
+
+Note that if you using the (better) afl-clang-lto compiler you also have to
+AR to llvm-ar[-VERSION] and RANLIB to llvm-ranlib[-VERSION] - as it is
+described in [llvm/README.lto.md](llvm/README.lto.md)
+
+##### other build systems or if configure/cmake didn't work
+
+Sometimes cmake and configure do not pick up the afl compiler, or the ranlib/ar
+that is needed - because this was just not foreseen by the developer of the
+target. Or they have non-standard options. Figure out if there is a 
+non-standard way to set this, otherwise set the build normally and edit the
+generated build environment afterwards by hand to point to the right compiler
+(and/or ranlib and ar).
+
+#### d) Better instrumentation
+
+If you just fuzz a target program as-is you are wasting a great opportunity for
+much more fuzzing speed.
+
+This requires the usage of afl-clang-lto or afl-clang-fast
+
+This is the so-called `persistent mode`, which is much, much faster but
+requires that you code a source file that is specifically calling the target
+functions that you want to fuzz, plus a few specific afl++ functions around
+it. See [llvm_mode/README.persistent_mode.md](llvm_mode/README.persistent_mode.md) for details.
+
+Basically if you do not fuzz a target in persistent mode then you are just
+doing it for a hobby and not professionally :-)
+
+### 2. Preparing the fuzzing
+
+As you fuzz the target with mutated input, having as diverse inputs for the
+target as possible improves the efficiency a lot.
+
+#### a) Collect inputs
+Try to gather valid inputs for the target from wherever you can. E.g. if it
+the PNG picture format try to find as many png files as possible, e.g. from
+reported bugs, test suites, random downloads from the internet, unit test
+case data - from all kind of PNG software.
+
+If the input is not known files, you can also modify a target program to write
+away normal data it receives and processes to a file and use these.
+
+#### b) Making the input corpus unique
+
+Use the afl++ tool `afl-cmin` to remove inputs from the corpus that do not
+use a different paths in the target.
+Put all files from step a) into one directory, e.g. INPUTS.
+
+Put all the files from step a)
+
+If the target program is to be called by fuzzing as `bin/target -d INPUTFILE`
+the run afl-cmin like this:
+`afl-cmin -i INPUTS -o INPUTS_UNIQUE -- bin/target -d @@`
+Note that the INPUTFILE that the target program would read has to be set as `@@`.
+
+If the target reads from stdin instead, just omit  the `@@` as this is the
+default.
+
+#### b) Minimizing all corpus files
+
+The shorter the input files are so that they still traverse the same path
+within the target, the better the fuzzing will be. This is done with `afl-tmin`
+however it is a long processes as this has to be done for every file:
+
+```
+mkdir input
+cd INPUTS_UNIQUE
+for i in *; do
+  afl-tmin -i "$i" -o "../input/$i" -- bin/target -d @@
+done
+```
+
+This can also be parallelized, e.g. with `parallel`
+
+#### c) done!
+
+The INPUTS_UNIQUE/ directory from step a) - or even better if you minimized the
+corpus in step b) then the files in input/ is then the input corpus directory
+to be used in fuzzing! :-)
+
+### Fuzzing the target
+
+In this final step we fuzz the target.
+There are not that many useful options to run the target - unless you want to
+use many CPU cores/threads for the fuzzing, which will make the fuzzing much
+more useful.
+
+If you just use one CPU for fuzzing, then you are fuzzing just for fun and not
+seriously :-)
+
+#### a) running afl-fuzz
+
+Before to do even a test run of afl-fuzz execute `sudo afl-system-config` (on
+the host if you execute afl-fuzz in a docker container). This reconfigured the
+system for optimal speed - which afl-fuzz checks and bails otherwise.
+Set `export AFL_SKIP_CPUFREQ=1` for afl-fuzz to skip this if you cannot run
+afl-system-config with root privileges on the host for whatever reason.
+
+If you have an input corpus from step 2 then specify this directory with the `-i`
+option. Otherwise create a new directory and create a file with any content
+in there.
+
+If you do not want anything special, the defaults are already the usual best,
+hence all you need (from the example in 2a):
+`afl-fuzz -i input -o output -- bin/target -d @@`
+Note that the directory specified with -o will be created if it does not exist.
+
+If you need to stop and re-start the fuzzing, use the same command line option
+and switch the input directory with a dash (`-`):
+`afl-fuzz -i - -o output -- bin/target -d @@`
+
+Adding a dictionary helpful. See the [dictionaries/](dictionaries/) if
+something is already included for your data format, and tell afl-fuzz to load
+that dictionary by adding `-x dicationaries/FORMAT.dict`. With afl-clang-lto
+you have an autodictionary generation for which you need to do nothing except
+to use afl-clang-lto as the compiler. You also have the option to generate
+a dictionary yourself, see [libtokencap/README.md](libtokencap/README.md)
+
+afl-fuzz never stops fuzzing. To terminate afl++ simply press Control-C.
+
+When you start afl-fuzz you will see a user interface that shows what the status
+is:
+![docs/screenshot.png](docs/screenshot.png)
+
+All labels are explained in [docs/status_screen.md](docs/status_screen.md)
+
+#### b) Using multiple cores/threads
+
+If you want to seriously fuzz then use as many cores/threads as possible to
+fuzz your target.
+
+On the same machine - due to the nature how afl++ works - there is a maximum
+number of CPU cores/threads that are useful, more and the overall performance
+degrades instead. This value depends on the target and the limit is between 48
+and 96 cores/threads per machine.
+
+There should be one main fuzzer (`-M main` option) and as many secondary
+fuzzers (eg `-S variant1`) as you cores that you use.
+Every -M/-S entry needs a unique name (that can be whatever), however the same
+-o output directory location has to be used for all.
+
+For every secondary there should be a variation, e.g.:
+ * one should fuzz the target that was compiled differently: with sanitizers
+   activated (`export AFL_USE_ASAN=1 ; export AFL_USE_UBSAN=1 ;
+   export AFL_USE_CFISAN=1 ; `
+ * one should fuzz the target with CMPLOG/redqueen (see above)
+ * At 1-2 should fuzz a target compiled with laf-intel/COMPCOV (see above).
+
+All other secondaries should be:
+ * 1/2 with MOpt option enabled: `-L 0`
+ * run with a different power schedule, available are:
+   `explore (default), fast, coe, lin, quad, exploit, mmopt, rare, seek`
+   which you can set with e.g. `-p seek`
+
+You can also use different fuzzers.
+If you are afl-spinoffs or afl conforming, then just use the same -o directory
+and give it a unique `-S` name.
+Examples are e.g.:
+ * [Angora](https://github.com/AngoraFuzzer/Angora)
+ * [Untracer](https://github.com/FoRTE-Research/UnTracer-AFL)
+ * [AFLsmart](https://github.com/aflsmart/aflsmart)
+ * [FairFuzz](https://github.com/carolemieux/afl-rb)
+ * [Neuzz](https://github.com/Dongdongshe/neuzz)
+
+A long list can be found at [https://github.com/Microsvuln/Awesome-AFL](https://github.com/Microsvuln/Awesome-AFL)
+
+However you can also sync afl++ with honggfuzz, libfuzzer, entropic, etc.
+Just show the main fuzzer (-M) with the `-F` option where the queue
+directory of these other fuzzers are, e.g. `-F /src/target/honggfuzz`
+
+#### c) The status of the fuzz campaign
+
+afl++ comes with the `afl-whatsup` script to show the status of fuzzing
+campaign.
+
+Just supply the directory that afl-fuzz is given with the -o option and
+you will see a detailed status of every fuzzer in that campaign plus
+a summary.
+
+To have only the summary use the `-s` switch e.g.: `afl-whatsup -s output/`
+
+#### d) Checking the coverage of the fuzzing
+
+The `paths found` value is a bad indicator how good the coverage is.
+It is better to check out the exact lines of code that have been reached -
+and which have not been found so far.
+
+An "easy" helper script for this is [https://github.com/vanhauser-thc/afl-cov](https://github.com/vanhauser-thc/afl-cov),
+just follow the README of that seperate project.
+
+If you see that an important area or a feature has not been covered so far then
+try to find an input that is able to reach that and start a new secondary in
+that fuzzing campaign with that seed as input, let it run for a few minutes,
+then terminate it. The main node will pick it up and make it available to the
+other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` if you have no
+free core.
+
+#### e) How long to fuzz a target?
+
+This is a difficult question.
+Basically if no new path is found for a long time (e.g. for a day or a week)
+then you can expect that your fuzzing won't be fruitful anymore.
+However often this just means that you should switch out secondaries for
+others, e.g. custom mutator modules, sync to very different fuzzers, etc.
+
+### The End
+
+This is basically all you need to know to professionally run fuzzing campaigns.
+If you want to know more, the rest of this README and the tons of texts in
+[docs/](docs/) will have you covered.
+
+Note that there are also a lot of tools out there that help fuzzing with afl++
+(some might be deprecated or unsupported):
+
+Minimization of test cases:
+ * [afl-pytmin](https://github.com/ilsani/afl-pytmin) - a wrapper for afl-tmin that tries to speed up the process of the minimization of test case by using many CPU cores.
+ * [afl-ddmin-mod](https://github.com/MarkusTeufelberger/afl-ddmin-mod) - a variation of afl-tmin based on the ddmin algorithm. 
+ * [halfempty](https://github.com/googleprojectzero/halfempty) -  is a fast utility for minimizing test cases by Tavis Ormandy based on parallelization. 
+
+Distributed execution:
+ * [disfuzz-afl](https://github.com/MartijnB/disfuzz-afl) - distributed fuzzing for AFL.
+ * [AFLDFF](https://github.com/quantumvm/AFLDFF) - AFL distributed fuzzing framework.
+ * [afl-launch](https://github.com/bnagy/afl-launch) - a tool for the execution of many AFL instances.
+ * [afl-mothership](https://github.com/afl-mothership/afl-mothership) - management and execution of many synchronized AFL fuzzers on AWS cloud.
+ * [afl-in-the-cloud](https://github.com/abhisek/afl-in-the-cloud) - another script for running AFL in AWS.
+
+Deployment, management, monitoring, reporting
+ * [afl-other-arch](https://github.com/shellphish/afl-other-arch) - is a set of patches and scripts for easily adding support for various non-x86 architectures for AFL.
+ * [afl-trivia](https://github.com/bnagy/afl-trivia) - a few small scripts to simplify the management of AFL.
+ * [afl-monitor](https://github.com/reflare/afl-monitor) - a script for monitoring AFL.
+ * [afl-manager](https://github.com/zx1340/afl-manager) - a web server on Python for managing multi-afl.
+ * [afl-remote](https://github.com/block8437/afl-remote) - a web server for the remote management of AFL instances.
+
+Crash processing
+ * [afl-utils](https://gitlab.com/rc0r/afl-utils) - a set of utilities for automatic processing/analysis of crashes and reducing the number of test cases.
+ * [afl-crash-analyzer](https://github.com/floyd-fuh/afl-crash-analyzer) - another crash analyzer for AFL.
+ * [fuzzer-utils](https://github.com/ThePatrickStar/fuzzer-utils) - a set of scripts for the analysis of results.
+ * [atriage](https://github.com/Ayrx/atriage) - a simple triage tool.
+ * [afl-kit](https://github.com/kcwu/afl-kit) - afl-cmin on Python.
+ * [AFLize](https://github.com/d33tah/aflize) - a tool that automatically generates builds of debian packages suitable for AFL.
+ * [afl-fid](https://github.com/FoRTE-Research/afl-fid) - a set of tools for working with input data.
+
+## Fuzzing binary-only targets
+
+When source code is *NOT* available, afl++ offers various support for fast,
+on-the-fly instrumentation of black-box binaries. 
+
+### QEMU
+
+For linux programs and it's libraries this is accomplished with a version of
+QEMU running in the lesser-known "user space emulation" mode.
+QEMU is a project separate from AFL, but you can conveniently build the
+feature by doing:
+```shell
+cd qemu_mode
+./build_qemu_support.sh
+```
+For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md).
+If possible you should use the persistent mode, see [qemu_mode/README.persistent.md](qemu_mode/README.persistent.md).
+The mode is approximately 2-5x slower than compile-time instrumentation, and is
+less conducive to parallelization.
+
+If [afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) works for
+your binary, then you can use afl-fuzz normally and it will have twice
+the speed compared to qemu_mode (but slower than persistent mode).
+
+### Unicorn
+
+For non-Linux binaries you can use afl++'s unicorn mode which can emulate
+anything you want - for the price of speed and the user writing scripts.
+See [unicorn_mode](unicorn_mode/README.md).
+
+It can be easily build by:
+```shell
+cd unicorn_mode
+./build_unicorn_support.sh
+```
+
+### Shared libraries
+
+If the goal is to fuzz a dynamic library then there are two options available.
+For both you need to write a small hardness that loads and calls the library.
+Faster is the frida solution: [examples/afl_frida/README.md](examples/afl_frida/README.md)
+
+Another, less precise and slower option is using ptrace with debugger interrupt
+instrumentation: [examples/afl_untracer/README.md](examples/afl_untracer/README.md)
+
+### More
+
+A more comprehensive description of these and other options can be found in
+[docs/binaryonly_fuzzing.md](docs/binaryonly_fuzzing.md)
+
 ## Challenges of guided fuzzing
 
 Fuzzing is one of the most powerful and proven strategies for identifying
@@ -262,13 +702,12 @@ closed-source tools.
 The fuzzer is thoroughly tested to deliver out-of-the-box performance far
 superior to blind fuzzing or coverage-only tools.
 
-
 ## Instrumenting programs for use with AFL
 
 PLEASE NOTE: llvm_mode compilation with afl-clang-fast/afl-clang-fast++
 instead of afl-gcc/afl-g++ is much faster and has many cool features.
 See llvm_mode/ - however few code does not compile with llvm.
-We support llvm versions 3.4 to 11.
+We support llvm versions 3.4 to 12.
 
 When source code is available, instrumentation can be injected by a companion
 tool that works as a drop-in replacement for gcc or clang in any standard build
@@ -291,7 +730,7 @@ For C++ programs, you'd would also want to set `CXX=/path/to/afl/afl-g++`.
 The clang wrappers (afl-clang and afl-clang++) can be used in the same way;
 clang users may also opt to leverage a higher-performance instrumentation mode,
 as described in [llvm_mode/README.md](llvm_mode/README.md).
-Clang/LLVM has a much better performance and works with LLVM version 3.4 to 11.
+Clang/LLVM has a much better performance and works with LLVM version 3.4 to 12.
 
 Using the LAF Intel performance enhancements are also recommended, see 
 [llvm_mode/README.laf-intel.md](llvm_mode/README.laf-intel.md)
@@ -318,56 +757,11 @@ simple memory bugs. Libdislocator, a helper library included with AFL (see
 PS. ASAN users are advised to review [docs/notes_for_asan.md](docs/notes_for_asan.md)
 file for important caveats.
 
-
-## Instrumenting binary-only apps
-
-When source code is *NOT* available, the fuzzer offers experimental support for
-fast, on-the-fly instrumentation of black-box binaries. This is accomplished
-with a version of QEMU running in the lesser-known "user space emulation" mode.
-
-QEMU is a project separate from AFL, but you can conveniently build the
-feature by doing:
-
-```shell
-cd qemu_mode
-./build_qemu_support.sh
-```
-
-For additional instructions and caveats, see [qemu_mode/README.md](qemu_mode/README.md).
-
-If possible you should use the persistent mode, see [qemu_mode/README.persistent.md](qemu_mode/README.persistent.md).
-
-The mode is approximately 2-5x slower than compile-time instrumentation, is
-less conducive to parallelization, and may have some other quirks.
-
-If [afl-dyninst](https://github.com/vanhauser-thc/afl-dyninst) works for
-your binary, then you can use afl-fuzz normally and it will have twice
-the speed compared to qemu_mode.
-
-A more comprehensive description of these and other options can be found in
-[docs/binaryonly_fuzzing.md](docs/binaryonly_fuzzing.md)
-
-## Good examples and writeups
-
-Here are some good writeups to show how to effectively use AFL++:
-
- * [https://aflplus.plus/docs/tutorials/libxml2_tutorial/](https://aflplus.plus/docs/tutorials/libxml2_tutorial/)
- * [https://bananamafia.dev/post/gb-fuzz/](https://bananamafia.dev/post/gb-fuzz/)
- * [https://securitylab.github.com/research/fuzzing-challenges-solutions-1](https://securitylab.github.com/research/fuzzing-challenges-solutions-1)
- * [https://securitylab.github.com/research/fuzzing-sockets-FTP](https://securitylab.github.com/research/fuzzing-sockets-FTP)
-
-If you are interested in fuzzing structured data (where you define what the
-structure is), these two links have you covered:
- * [https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator](https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator)
- * [https://github.com/thebabush/afl-libprotobuf-mutator](https://github.com/thebabush/afl-libprotobuf-mutator)
-
-If you find other good ones, please send them to us :-)
-
 ## Power schedules
 
-The power schedules were copied from Marcel Böhme's excellent AFLfast
-implementation and expand on the ability to discover new paths and
-therefore may increase the code coverage.
+The power schedules were copied from Marcel Böhme's AFLfast implementation and
+measure differently which queue entries to prefer and therefore may find
+different paths faster for large queues.
 
 The available schedules are:
  
@@ -381,16 +775,10 @@ The available schedules are:
  - mmopt (afl++ experimental)
  - seek (afl++ experimental)
 
-In parallel mode (-M/-S, several instances with the shared queue), we suggest to
-run the main node using the explore or fast schedule (-p explore) and the secondary
-nodes with a combination of cut-off-exponential (-p coe), exponential (-p fast),
-explore (-p explore) and mmopt (-p mmopt) schedules. If a schedule does
-not perform well for a target, restart the secondary nodes with a different schedule.
-
-In single mode, using -p fast is usually slightly more beneficial than the
-default explore mode.
-(We don't want to change the default behavior of afl, so "fast" has not been
-made the default mode).
+In parallel mode (-M/-S, several instances with the shared queue), we suggest
+to run the main node using the default explore schedule (`-p explore`) and the
+secondary nodes with different schedules. If a schedule does not perform well
+for a target, restart the secondary nodes with a different schedule.
 
 More details can be found in the paper published at the 23rd ACM Conference on
 Computer and Communications Security [CCS'16](https://www.sigsac.org/ccs/CCS2016/accepted-papers/)
diff --git a/TODO.md b/TODO.md
index 8085bc07..ad743b6b 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,7 +1,9 @@
 # TODO list for AFL++
 
-## Roadmap 2.66+
+## Roadmap 2.67+
 
+ - -i - + foreign fuzzer sync support: scandir with time sort
+ - expand on AFL_LLVM_INSTRUMENT_FILE to also support sancov allowlist format
  - AFL_MAP_SIZE for qemu_mode and unicorn_mode
  - namespace for targets? e.g. network
  - learn from honggfuzz (mutations, maybe ptrace?)
@@ -21,6 +23,11 @@ gcc_plugin:
  - laf-intel
  - better instrumentation (seems to be better with gcc-9+)
 
+better documentation:
+ - flow graph
+ - short intro
+ - faq (how to increase stability, speed, many parallel ...)
+
 qemu_mode:
  - update to 5.x (if the performance bug if gone)
  - non colliding instrumentation
diff --git a/afl-plot b/afl-plot
index 1074552a..0faed0ec 100755
--- a/afl-plot
+++ b/afl-plot
@@ -68,6 +68,15 @@ if [ ! -f "$inputdir/plot_data" ]; then
 
 fi
 
+LINES=`cat "$inputdir/plot_data" | wc -l`
+
+if [ "$LINES" -lt 3 ]; then
+
+  echo "[-] Error: plot_data carries too little data, let it run longer." 1>&2
+  exit 1
+
+fi
+
 BANNER="`cat "$inputdir/fuzzer_stats" 2> /dev/null | grep '^afl_banner ' | cut -d: -f2- | cut -b2-`"
 
 test "$BANNER" = "" && BANNER="(none)"
@@ -118,6 +127,9 @@ set key outside
 set autoscale xfixmin
 set autoscale xfixmax
 
+set xlabel "all times in UTC" font "small"
+
+set ytics auto
 plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' linecolor rgb '#000000' fillstyle transparent solid 0.2 noborder, \\
      '' using 1:3 with filledcurve x1 title 'current path' linecolor rgb '#f0f0f0' fillstyle transparent solid 0.5 noborder, \\
      '' using 1:5 with lines title 'pending paths' linecolor rgb '#0090ff' linewidth 3, \\
@@ -127,6 +139,7 @@ plot '$inputdir/plot_data' using 1:4 with filledcurve x1 title 'total paths' lin
 set terminal png truecolor enhanced size 1000,200 butt
 set output '$outputdir/low_freq.png'
 
+set ytics 1
 plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb '#c00080' fillstyle transparent solid 0.2 noborder, \\
      '' using 1:8 with lines title ' uniq crashes' linecolor rgb '#c00080' linewidth 3, \\
      '' using 1:9 with lines title 'uniq hangs' linecolor rgb '#c000f0' linewidth 3, \\
@@ -135,6 +148,7 @@ plot '$inputdir/plot_data' using 1:8 with filledcurve x1 title '' linecolor rgb
 set terminal png truecolor enhanced size 1000,200 butt
 set output '$outputdir/exec_speed.png'
 
+set ytics auto
 plot '$inputdir/plot_data' using 1:11 with filledcurve x1 title '' linecolor rgb '#0090ff' fillstyle transparent solid 0.2 noborder, \\
      '$inputdir/plot_data' using 1:11 with lines title '    execs/sec' linecolor rgb '#0090ff' linewidth 3 smooth bezier;
 
diff --git a/afl-system-config b/afl-system-config
index 1e180d8b..34db61aa 100755
--- a/afl-system-config
+++ b/afl-system-config
@@ -1,5 +1,5 @@
 #!/bin/sh
-test "$1" = "-h" && {
+test "$1" = "-h" -o "$1" = "-hh" && {
   echo 'afl-system-config by Marc Heuse <mh@mh-sec.de>'
   echo
   echo $0
diff --git a/afl-whatsup b/afl-whatsup
index 1a276964..abcddbf1 100755
--- a/afl-whatsup
+++ b/afl-whatsup
@@ -20,7 +20,7 @@
 
 echo "$0 status check tool for afl-fuzz by Michal Zalewski"
 echo
-test "$1" = "-h" && {
+test "$1" = "-h" -o "$1" = "-hh" && {
   echo $0 [-s] output_directory
   echo
   echo Options:
@@ -162,7 +162,8 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
 
   ALIVE_CNT=$((ALIVE_CNT + 1))
 
-  EXEC_SEC=$((execs_done / RUN_UNIX))
+  EXEC_SEC=0
+  test -z "$RUN_UNIX" -o "$RUN_UNIX" = 0 || EXEC_SEC=$((execs_done / RUN_UNIX))
   PATH_PERC=$((cur_path * 100 / paths_total))
 
   TOTAL_TIME=$((TOTAL_TIME + RUN_UNIX))
@@ -184,7 +185,9 @@ for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
       echo "  ${RED}timeout_ratio $TIMEOUT_PERC%${NC}"
     fi
 
-    if [ $EXEC_SEC -lt 100 ]; then
+    if [ $EXEC_SEC -eq 0 ]; then
+      echo "  ${YELLOW}no data yet, 0 execs/sec${NC}"
+    elif [ $EXEC_SEC -lt 100 ]; then
       echo "  ${RED}slow execution, $EXEC_SEC execs/sec${NC}"
     fi
 
diff --git a/custom_mutators/README.md b/custom_mutators/README.md
index 0abce32f..a3b164be 100644
--- a/custom_mutators/README.md
+++ b/custom_mutators/README.md
@@ -10,3 +10,22 @@ Use with e.g.
 and add `AFL_CUSTOM_MUTATOR_ONLY=1` if you only want to use the custom mutator.
 
 Multiple custom mutators can be used by separating their paths with `:` in the environment variable.
+
+# Other custom mutators
+
+## Superion port
+
+Adrian Tiron ported the Superion grammar fuzzer to afl++, it is WIP and
+requires cmake (among other things):
+[https://github.com/adrian-rt/superion-mutator](https://github.com/adrian-rt/superion-mutator)
+
+## Protobuf
+
+There are two WIP protobuf projects, that require work to be working though:
+
+transforms protobuf raw:
+https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/tree/master/4_libprotobuf_aflpp_custom_mutator
+
+has a transform function you need to fill for your protobuf format, however
+needs to be ported to the updated afl++ custom mutator API (not much work):
+https://github.com/thebabush/afl-libprotobuf-mutator
diff --git a/custom_mutators/honggfuzz/Makefile b/custom_mutators/honggfuzz/Makefile
new file mode 100644
index 00000000..2f46d0e7
--- /dev/null
+++ b/custom_mutators/honggfuzz/Makefile
@@ -0,0 +1,15 @@
+
+CFLAGS = -O3 -funroll-loops -fPIC -Wl,-Bsymbolic
+
+all: honggfuzz.so
+
+honggfuzz.so:	honggfuzz.c input.h mangle.c ../../src/afl-performance.c
+	$(CC) $(CFLAGS) -I../../include -I. -shared -o honggfuzz.so honggfuzz.c mangle.c ../../src/afl-performance.c
+
+update:
+	wget --unlink https://github.com/google/honggfuzz/raw/master/mangle.c
+	wget --unlink https://github.com/google/honggfuzz/raw/master/mangle.h
+	wget --unlink https://github.com/google/honggfuzz/raw/master/honggfuzz.h
+
+clean:
+	rm -f *.o *~ *.so core
diff --git a/custom_mutators/honggfuzz/README.md b/custom_mutators/honggfuzz/README.md
new file mode 100644
index 00000000..8824976f
--- /dev/null
+++ b/custom_mutators/honggfuzz/README.md
@@ -0,0 +1,12 @@
+# custum mutator: honggfuzz mangle
+
+this is the very good honggfuzz mutator in mangle.c as a custom mutator
+module for afl++. It is the original mangle.c, mangle.h and honggfuzz.h
+with a lot of mocking around it :-)
+
+just type `make` to build
+
+```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/honggfuzz/honggfuzz.so afl-fuzz ...```
+
+> Original repository: https://github.com/google/honggfuzz
+> Source commit: d0fbcb0373c32436b8fb922e6937da93b17291f5
diff --git a/custom_mutators/honggfuzz/common.h b/custom_mutators/honggfuzz/common.h
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/custom_mutators/honggfuzz/common.h
diff --git a/custom_mutators/honggfuzz/custom_mutator_helpers.h b/custom_mutators/honggfuzz/custom_mutator_helpers.h
new file mode 100644
index 00000000..57754697
--- /dev/null
+++ b/custom_mutators/honggfuzz/custom_mutator_helpers.h
@@ -0,0 +1,22 @@
+#ifndef CUSTOM_MUTATOR_HELPERS
+#define CUSTOM_MUTATOR_HELPERS
+
+#include "config.h"
+#include "types.h"
+#include "afl-fuzz.h"
+#include <stdlib.h>
+
+#define INITIAL_GROWTH_SIZE (64)
+
+/* Use in a struct: creates a name_buf and a name_size variable. */
+#define BUF_VAR(type, name) \
+  type * name##_buf;        \
+  size_t name##_size;
+/* this filles in `&structptr->something_buf, &structptr->something_size`. */
+#define BUF_PARAMS(struct, name) \
+  (void **)&struct->name##_buf, &struct->name##_size
+
+#undef INITIAL_GROWTH_SIZE
+
+#endif
+
diff --git a/custom_mutators/honggfuzz/honggfuzz.c b/custom_mutators/honggfuzz/honggfuzz.c
new file mode 100644
index 00000000..bde922c6
--- /dev/null
+++ b/custom_mutators/honggfuzz/honggfuzz.c
@@ -0,0 +1,143 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "custom_mutator_helpers.h"
+#include "mangle.h"
+
+#define NUMBER_OF_MUTATIONS 5
+
+uint8_t *         queue_input;
+size_t            queue_input_size;
+afl_state_t *     afl_struct;
+run_t             run;
+honggfuzz_t       global;
+struct _dynfile_t dynfile;
+
+typedef struct my_mutator {
+
+  afl_state_t *afl;
+  run_t *      run;
+  u8 *         mutator_buf;
+  unsigned int seed;
+  unsigned int extras_cnt, a_extras_cnt;
+
+} my_mutator_t;
+
+my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
+
+  my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
+  if (!data) {
+
+    perror("afl_custom_init alloc");
+    return NULL;
+
+  }
+
+  if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) {
+
+    perror("mutator_buf alloc");
+    return NULL;
+
+  }
+
+  run.dynfile = &dynfile;
+  run.global = &global;
+  data->afl = afl;
+  data->seed = seed;
+  data->run = &run;
+  afl_struct = afl;
+
+  run.global->mutate.maxInputSz = MAX_FILE;
+  run.global->mutate.mutationsPerRun = NUMBER_OF_MUTATIONS;
+  run.mutationsPerRun = NUMBER_OF_MUTATIONS;
+  run.global->timing.lastCovUpdate = 6;
+
+  // global->feedback.cmpFeedback
+  // global->feedback.cmpFeedbackMap
+
+  return data;
+
+}
+
+/* When a new queue entry is added we check if there are new dictionary
+   entries to add to honggfuzz structure */
+
+void afl_custom_queue_new_entry(my_mutator_t * data,
+                                const uint8_t *filename_new_queue,
+                                const uint8_t *filename_orig_queue) {
+
+  if (run.global->mutate.dictionaryCnt >= 1024) return;
+
+  while (data->extras_cnt < data->afl->extras_cnt &&
+         run.global->mutate.dictionaryCnt < 1024) {
+
+    memcpy(run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].val,
+           data->afl->extras[data->extras_cnt].data,
+           data->afl->extras[data->extras_cnt].len);
+    run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].len =
+        data->afl->extras[data->extras_cnt].len;
+    run.global->mutate.dictionaryCnt++;
+    data->extras_cnt++;
+
+  }
+
+  while (data->a_extras_cnt < data->afl->a_extras_cnt &&
+         run.global->mutate.dictionaryCnt < 1024) {
+
+    memcpy(run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].val,
+           data->afl->a_extras[data->a_extras_cnt].data,
+           data->afl->a_extras[data->a_extras_cnt].len);
+    run.global->mutate.dictionary[run.global->mutate.dictionaryCnt].len =
+        data->afl->a_extras[data->a_extras_cnt].len;
+    run.global->mutate.dictionaryCnt++;
+    data->a_extras_cnt++;
+
+  }
+
+}
+
+/* we could set only_printable if is_ascii is set ... let's see
+uint8_t afl_custom_queue_get(void *data, const uint8_t *filename) {
+
+  //run.global->cfg.only_printable = ...
+
+}
+
+*/
+
+/* here we run the honggfuzz mutator, which is really good */
+
+size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
+                       u8 **out_buf, uint8_t *add_buf, size_t add_buf_size,
+                       size_t max_size) {
+
+  /* set everything up, costly ... :( */
+  memcpy(data->mutator_buf, buf, buf_size);
+  queue_input = data->mutator_buf;
+  run.dynfile->data = data->mutator_buf;
+  queue_input_size = buf_size;
+  run.dynfile->size = buf_size;
+  *out_buf = data->mutator_buf;
+
+  /* the mutation */
+  mangle_mangleContent(&run, NUMBER_OF_MUTATIONS);
+
+  /* return size of mutated data */
+  return run.dynfile->size;
+
+}
+
+/**
+ * Deinitialize everything
+ *
+ * @param data The data ptr from afl_custom_init
+ */
+void afl_custom_deinit(my_mutator_t *data) {
+
+  free(data->mutator_buf);
+  free(data);
+
+}
+
diff --git a/custom_mutators/honggfuzz/honggfuzz.h b/custom_mutators/honggfuzz/honggfuzz.h
new file mode 100644
index 00000000..4e045272
--- /dev/null
+++ b/custom_mutators/honggfuzz/honggfuzz.h
@@ -0,0 +1,460 @@
+/*
+ *
+ * honggfuzz - core structures and macros
+ * -----------------------------------------
+ *
+ * Author: Robert Swiecki <swiecki@google.com>
+ *
+ * Copyright 2010-2018 by Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ *
+ */
+
+#ifndef _HF_HONGGFUZZ_H_
+#define _HF_HONGGFUZZ_H_
+
+#include <dirent.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "libhfcommon/util.h"
+
+#define PROG_NAME "honggfuzz"
+#define PROG_VERSION "2.2"
+
+/* Name of the template which will be replaced with the proper name of the file
+ */
+#define _HF_FILE_PLACEHOLDER "___FILE___"
+
+/* Default name of the report created with some architectures */
+#define _HF_REPORT_FILE "HONGGFUZZ.REPORT.TXT"
+
+/* Default stack-size of created threads. */
+#define _HF_PTHREAD_STACKSIZE (1024ULL * 1024ULL * 2ULL)             /* 2MB */
+
+/* Name of envvar which indicates sequential number of fuzzer */
+#define _HF_THREAD_NO_ENV "HFUZZ_THREAD_NO"
+
+/* Name of envvar which indicates that the netDriver should be used */
+#define _HF_THREAD_NETDRIVER_ENV "HFUZZ_USE_NETDRIVER"
+
+/* Name of envvar which indicates honggfuzz's log level in use */
+#define _HF_LOG_LEVEL_ENV "HFUZZ_LOG_LEVEL"
+
+/* Number of crash verifier iterations before tag crash as stable */
+#define _HF_VERIFIER_ITER 5
+
+/* Size (in bytes) for report data to be stored in stack before written to file
+ */
+#define _HF_REPORT_SIZE 32768
+
+/* Perf bitmap size */
+#define _HF_PERF_BITMAP_SIZE_16M (1024U * 1024U * 16U)
+#define _HF_PERF_BITMAP_BITSZ_MASK 0x7FFFFFFULL
+/* Maximum number of PC guards (=trace-pc-guard) we support */
+#define _HF_PC_GUARD_MAX (1024ULL * 1024ULL * 64ULL)
+
+/* Maximum size of the input file in bytes (1 MiB) */
+#define _HF_INPUT_MAX_SIZE (1024ULL * 1024ULL)
+
+/* Default maximum size of produced inputs */
+#define _HF_INPUT_DEFAULT_SIZE (1024ULL * 8)
+
+/* Per-thread bitmap */
+#define _HF_PERTHREAD_BITMAP_FD 1018
+/* FD used to report back used int/str constants from the fuzzed process */
+#define _HF_CMP_BITMAP_FD 1019
+/* FD used to log inside the child process */
+#define _HF_LOG_FD 1020
+/* FD used to represent the input file */
+#define _HF_INPUT_FD 1021
+/* FD used to pass coverage feedback from the fuzzed process */
+#define _HF_COV_BITMAP_FD 1022
+#define _HF_BITMAP_FD _HF_COV_BITMAP_FD   /* Old name for _HF_COV_BITMAP_FD */
+/* FD used to pass data to a persistent process */
+#define _HF_PERSISTENT_FD 1023
+
+/* Input file as a string */
+#define _HF_INPUT_FILE_PATH "/dev/fd/" HF_XSTR(_HF_INPUT_FD)
+
+/* Maximum number of supported execve() args */
+#define _HF_ARGS_MAX 2048
+
+/* Message indicating that the fuzzed process is ready for new data */
+static const uint8_t HFReadyTag = 'R';
+
+/* Maximum number of active fuzzing threads */
+#define _HF_THREAD_MAX 1024U
+
+/* Persistent-binary signature - if found within file, it means it's a
+ * persistent mode binary */
+#define _HF_PERSISTENT_SIG "\x01_LIBHFUZZ_PERSISTENT_BINARY_SIGNATURE_\x02\xFF"
+/* HF NetDriver signature - if found within file, it means it's a
+ * NetDriver-based binary */
+#define _HF_NETDRIVER_SIG "\x01_LIBHFUZZ_NETDRIVER_BINARY_SIGNATURE_\x02\xFF"
+
+/* printf() nonmonetary separator. According to MacOSX's man it's supported
+ * there as well */
+#define _HF_NONMON_SEP "'"
+
+typedef enum {
+
+  _HF_DYNFILE_NONE = 0x0,
+  _HF_DYNFILE_INSTR_COUNT = 0x1,
+  _HF_DYNFILE_BRANCH_COUNT = 0x2,
+  _HF_DYNFILE_BTS_EDGE = 0x10,
+  _HF_DYNFILE_IPT_BLOCK = 0x20,
+  _HF_DYNFILE_SOFT = 0x40,
+
+} dynFileMethod_t;
+
+typedef struct {
+
+  uint64_t cpuInstrCnt;
+  uint64_t cpuBranchCnt;
+  uint64_t bbCnt;
+  uint64_t newBBCnt;
+  uint64_t softCntPc;
+  uint64_t softCntEdge;
+  uint64_t softCntCmp;
+
+} hwcnt_t;
+
+typedef enum {
+
+  _HF_STATE_UNSET = 0,
+  _HF_STATE_STATIC,
+  _HF_STATE_DYNAMIC_DRY_RUN,
+  _HF_STATE_DYNAMIC_MAIN,
+  _HF_STATE_DYNAMIC_MINIMIZE,
+
+} fuzzState_t;
+
+typedef enum {
+
+  HF_MAYBE = -1,
+  HF_NO = 0,
+  HF_YES = 1,
+
+} tristate_t;
+
+struct _dynfile_t {
+
+  size_t             size;
+  uint64_t           cov[4];
+  size_t             idx;
+  int                fd;
+  uint64_t           timeExecUSecs;
+  char               path[PATH_MAX];
+  struct _dynfile_t *src;
+  uint32_t           refs;
+  uint8_t *          data;
+  TAILQ_ENTRY(_dynfile_t) pointers;
+
+};
+
+typedef struct _dynfile_t dynfile_t;
+
+struct strings_t {
+
+  size_t len;
+  TAILQ_ENTRY(strings_t) pointers;
+  char s[];
+
+};
+
+typedef struct {
+
+  uint8_t  pcGuardMap[_HF_PC_GUARD_MAX];
+  uint8_t  bbMapPc[_HF_PERF_BITMAP_SIZE_16M];
+  uint32_t bbMapCmp[_HF_PERF_BITMAP_SIZE_16M];
+  uint64_t pidNewPC[_HF_THREAD_MAX];
+  uint64_t pidNewEdge[_HF_THREAD_MAX];
+  uint64_t pidNewCmp[_HF_THREAD_MAX];
+  uint64_t guardNb;
+  uint64_t pidTotalPC[_HF_THREAD_MAX];
+  uint64_t pidTotalEdge[_HF_THREAD_MAX];
+  uint64_t pidTotalCmp[_HF_THREAD_MAX];
+
+} feedback_t;
+
+typedef struct {
+
+  uint32_t cnt;
+  struct {
+
+    uint8_t  val[32];
+    uint32_t len;
+
+  } valArr[1024 * 16];
+
+} cmpfeedback_t;
+
+typedef struct {
+
+  struct {
+
+    size_t    threadsMax;
+    size_t    threadsFinished;
+    uint32_t  threadsActiveCnt;
+    pthread_t mainThread;
+    pid_t     mainPid;
+    pthread_t threads[_HF_THREAD_MAX];
+
+  } threads;
+
+  struct {
+
+    const char *inputDir;
+    const char *outputDir;
+    DIR *       inputDirPtr;
+    size_t      fileCnt;
+    size_t      testedFileCnt;
+    const char *fileExtn;
+    size_t      maxFileSz;
+    size_t      newUnitsAdded;
+    char        workDir[PATH_MAX];
+    const char *crashDir;
+    const char *covDirNew;
+    bool        saveUnique;
+    size_t      dynfileqMaxSz;
+    size_t      dynfileqCnt;
+    dynfile_t * dynfileqCurrent;
+    dynfile_t * dynfileq2Current;
+    TAILQ_HEAD(dyns_t, _dynfile_t) dynfileq;
+    bool exportFeedback;
+
+  } io;
+
+  struct {
+
+    int                argc;
+    const char *const *cmdline;
+    bool               nullifyStdio;
+    bool               fuzzStdin;
+    const char *       externalCommand;
+    const char *       postExternalCommand;
+    const char *       feedbackMutateCommand;
+    bool               netDriver;
+    bool               persistent;
+    uint64_t           asLimit;
+    uint64_t           rssLimit;
+    uint64_t           dataLimit;
+    uint64_t           coreLimit;
+    uint64_t           stackLimit;
+    bool               clearEnv;
+    char *             env_ptrs[128];
+    char               env_vals[128][4096];
+    sigset_t           waitSigSet;
+
+  } exe;
+
+  struct {
+
+    time_t  timeStart;
+    time_t  runEndTime;
+    time_t  tmOut;
+    time_t  lastCovUpdate;
+    int64_t timeOfLongestUnitUSecs;
+    bool    tmoutVTALRM;
+
+  } timing;
+
+  struct {
+
+    struct {
+
+      uint8_t val[256];
+      size_t  len;
+
+    } dictionary[1024];
+
+    size_t      dictionaryCnt;
+    const char *dictionaryFile;
+    size_t      mutationsMax;
+    unsigned    mutationsPerRun;
+    size_t      maxInputSz;
+
+  } mutate;
+
+  struct {
+
+    bool    useScreen;
+    char    cmdline_txt[65];
+    int64_t lastDisplayUSecs;
+
+  } display;
+
+  struct {
+
+    bool        useVerifier;
+    bool        exitUponCrash;
+    const char *reportFile;
+    size_t      dynFileIterExpire;
+    bool        only_printable;
+    bool        minimize;
+    bool        switchingToFDM;
+
+  } cfg;
+
+  struct {
+
+    bool enable;
+    bool del_report;
+
+  } sanitizer;
+
+  struct {
+
+    fuzzState_t     state;
+    feedback_t *    covFeedbackMap;
+    int             covFeedbackFd;
+    cmpfeedback_t * cmpFeedbackMap;
+    int             cmpFeedbackFd;
+    bool            cmpFeedback;
+    const char *    blacklistFile;
+    uint64_t *      blacklist;
+    size_t          blacklistCnt;
+    bool            skipFeedbackOnTimeout;
+    uint64_t        maxCov[4];
+    dynFileMethod_t dynFileMethod;
+    hwcnt_t         hwCnts;
+
+  } feedback;
+
+  struct {
+
+    size_t mutationsCnt;
+    size_t crashesCnt;
+    size_t uniqueCrashesCnt;
+    size_t verifiedCrashesCnt;
+    size_t blCrashesCnt;
+    size_t timeoutedCnt;
+
+  } cnts;
+
+  struct {
+
+    bool enabled;
+    int  serverSocket;
+    int  clientSocket;
+
+  } socketFuzzer;
+
+  struct {
+
+    pthread_rwlock_t dynfileq;
+    pthread_mutex_t  feedback;
+    pthread_mutex_t  report;
+    pthread_mutex_t  state;
+    pthread_mutex_t  input;
+    pthread_mutex_t  timing;
+
+  } mutex;
+
+  /* For the Linux code */
+  struct {
+
+    int         exeFd;
+    uint64_t    dynamicCutOffAddr;
+    bool        disableRandomization;
+    void *      ignoreAddr;
+    const char *symsBlFile;
+    char **     symsBl;
+    size_t      symsBlCnt;
+    const char *symsWlFile;
+    char **     symsWl;
+    size_t      symsWlCnt;
+    uintptr_t   cloneFlags;
+    tristate_t  useNetNs;
+    bool        kernelOnly;
+    bool        useClone;
+
+  } arch_linux;
+
+  /* For the NetBSD code */
+  struct {
+
+    void *      ignoreAddr;
+    const char *symsBlFile;
+    char **     symsBl;
+    size_t      symsBlCnt;
+    const char *symsWlFile;
+    char **     symsWl;
+    size_t      symsWlCnt;
+
+  } arch_netbsd;
+
+} honggfuzz_t;
+
+typedef enum {
+
+  _HF_RS_UNKNOWN = 0,
+  _HF_RS_WAITING_FOR_INITIAL_READY = 1,
+  _HF_RS_WAITING_FOR_READY = 2,
+  _HF_RS_SEND_DATA = 3,
+
+} runState_t;
+
+typedef struct {
+
+  honggfuzz_t *global;
+  pid_t        pid;
+  int64_t      timeStartedUSecs;
+  char         crashFileName[PATH_MAX];
+  uint64_t     pc;
+  uint64_t     backtrace;
+  uint64_t     access;
+  int          exception;
+  char         report[_HF_REPORT_SIZE];
+  bool         mainWorker;
+  unsigned     mutationsPerRun;
+  dynfile_t *  dynfile;
+  bool         staticFileTryMore;
+  uint32_t     fuzzNo;
+  int          persistentSock;
+  runState_t   runState;
+  bool         tmOutSignaled;
+  char *       args[_HF_ARGS_MAX + 1];
+  int          perThreadCovFeedbackFd;
+  unsigned     triesLeft;
+  dynfile_t *  current;
+#if !defined(_HF_ARCH_DARWIN)
+  timer_t timerId;
+#endif  // !defined(_HF_ARCH_DARWIN)
+  hwcnt_t hwCnts;
+
+  struct {
+
+    /* For Linux code */
+    uint8_t *perfMmapBuf;
+    uint8_t *perfMmapAux;
+    int      cpuInstrFd;
+    int      cpuBranchFd;
+    int      cpuIptBtsFd;
+
+  } arch_linux;
+
+} run_t;
+
+#endif
+
diff --git a/custom_mutators/honggfuzz/input.h b/custom_mutators/honggfuzz/input.h
new file mode 100644
index 00000000..7b0c55ae
--- /dev/null
+++ b/custom_mutators/honggfuzz/input.h
@@ -0,0 +1,106 @@
+#ifndef _HG_INPUT_
+#define _HG_INPUT_
+
+#include <stdarg.h>
+#ifdef __clang__
+#include <stdatomic.h>
+#endif
+#include <stdbool.h>
+#include <stdint.h>
+#include <time.h>
+
+#include "honggfuzz.h"
+#include "afl-fuzz.h"
+
+/*
+ * Go-style defer scoped implementation
+ *
+ * If compiled with clang, use: -fblocks -lBlocksRuntime
+ *
+ * Example of use:
+ *
+ * {
+ *   int fd = open(fname, O_RDONLY);
+ *   if (fd == -1) {
+ *     error(....);
+ *     return;
+ *   }
+ *   defer { close(fd); };
+ *   ssize_t sz = read(fd, buf, sizeof(buf));
+ *   ...
+ *   ...
+ * }
+ *
+ */
+
+#define __STRMERGE(a, b) a##b
+#define _STRMERGE(a, b)  __STRMERGE(a, b)
+#ifdef __clang__
+#if __has_extension(blocks)
+static void __attribute__((unused)) __clang_cleanup_func(void (^*dfunc)(void)) {
+    (*dfunc)();
+}
+
+#define defer                                                                                      \
+    void (^_STRMERGE(__defer_f_, __COUNTER__))(void)                                               \
+        __attribute__((cleanup(__clang_cleanup_func))) __attribute__((unused)) = ^
+
+#else /* __has_extension(blocks) */
+#define defer UNIMPLEMENTED - NO - SUPPORT - FOR - BLOCKS - IN - YOUR - CLANG - ENABLED
+#endif /*  __has_extension(blocks) */
+#else  /* !__clang__, e.g.: gcc */
+
+#define __block
+#define _DEFER(a, count)                                                                            \
+    auto void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused)));               \
+    int       _STRMERGE(__defer_var_, count) __attribute__((cleanup(_STRMERGE(__defer_f_, count)))) \
+        __attribute__((unused));                                                                    \
+    void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused)))
+#define defer _DEFER(a, __COUNTER__)
+#endif /* ifdef __clang__ */
+
+#define HF_MIN(x, y) (x <= y ? x : y)
+#define HF_MAX(x, y) (x >= y ? x : y)
+#define ATOMIC_GET
+#define ARRAYSIZE(x) (sizeof(x) / sizeof(*x))
+#define HF_ATTR_UNUSED __attribute__((unused))
+#define util_Malloc(x) malloc(x)
+
+extern uint8_t *         queue_input;
+extern size_t            queue_input_size;
+extern afl_state_t *     afl_struct;
+
+inline void wmb() { }
+inline void LOG_F(const char *format, ...) { }
+static inline uint64_t util_rndGet(uint64_t min, uint64_t max) {
+  return min + rand_below(afl_struct, max - min + 1);
+}
+static inline uint64_t util_rnd64() { return rand_below(afl_struct, 1 << 30); }
+
+static inline size_t input_getRandomInputAsBuf(run_t *run, const uint8_t **buf) {
+  *buf = queue_input;
+  run->dynfile->data = queue_input;
+  run->dynfile->size = queue_input_size;
+  return queue_input_size;
+}
+static inline void input_setSize(run_t* run, size_t sz) {
+  run->dynfile->size = sz;
+}
+static inline void util_turnToPrintable(uint8_t* buf, size_t sz) {
+  for (size_t i = 0; i < sz; i++)
+    buf[i] = buf[i] % 95 + 32;
+}
+static inline void util_rndBuf(uint8_t* buf, size_t sz) {
+  if (sz == 0) return;
+  for (size_t i = 0; i < sz; i++)
+    buf[i] = (uint8_t)rand_below(afl_struct, 256);
+}
+static inline uint8_t util_rndPrintable() {
+  return 32 + rand_below(afl_struct, 127 - 32);
+}
+static inline void util_rndBufPrintable(uint8_t* buf, size_t sz) {
+  for (size_t i = 0; i < sz; i++)
+    buf[i] = util_rndPrintable();
+}
+
+#endif
diff --git a/custom_mutators/honggfuzz/libhfcommon b/custom_mutators/honggfuzz/libhfcommon
new file mode 120000
index 00000000..945c9b46
--- /dev/null
+++ b/custom_mutators/honggfuzz/libhfcommon
@@ -0,0 +1 @@
+.
\ No newline at end of file
diff --git a/custom_mutators/honggfuzz/log.h b/custom_mutators/honggfuzz/log.h
new file mode 120000
index 00000000..51e19654
--- /dev/null
+++ b/custom_mutators/honggfuzz/log.h
@@ -0,0 +1 @@
+common.h
\ No newline at end of file
diff --git a/custom_mutators/honggfuzz/mangle.c b/custom_mutators/honggfuzz/mangle.c
new file mode 100644
index 00000000..05e0dcfa
--- /dev/null
+++ b/custom_mutators/honggfuzz/mangle.c
@@ -0,0 +1,1039 @@
+/*
+ *
+ * honggfuzz - run->dynfile->datafer mangling routines
+ * -----------------------------------------
+ *
+ * Author:
+ * Robert Swiecki <swiecki@google.com>
+ *
+ * Copyright 2010-2018 by Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ *
+ */
+
+#include "mangle.h"
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "input.h"
+#include "libhfcommon/common.h"
+#include "libhfcommon/log.h"
+#include "libhfcommon/util.h"
+
+static inline size_t mangle_LenLeft(run_t *run, size_t off) {
+
+  if (off >= run->dynfile->size) {
+
+    LOG_F("Offset is too large: off:%zu >= len:%zu", off, run->dynfile->size);
+
+  }
+
+  return (run->dynfile->size - off - 1);
+
+}
+
+/* Get a random value between <1:max> with x^2 distribution */
+static inline size_t mangle_getLen(size_t max) {
+
+  if (max > _HF_INPUT_MAX_SIZE) {
+
+    LOG_F("max (%zu) > _HF_INPUT_MAX_SIZE (%zu)", max,
+          (size_t)_HF_INPUT_MAX_SIZE);
+
+  }
+
+  if (max == 0) { LOG_F("max == 0"); }
+  if (max == 1) { return 1; }
+
+  const uint64_t max2 = (uint64_t)max * max;
+  const uint64_t max3 = (uint64_t)max * max * max;
+  const uint64_t rnd = util_rndGet(1, max2 - 1);
+
+  uint64_t ret = rnd * rnd;
+  ret /= max3;
+  ret += 1;
+
+  if (ret < 1) {
+
+    LOG_F("ret (%" PRIu64 ") < 1, max:%zu, rnd:%" PRIu64, ret, max, rnd);
+
+  }
+
+  if (ret > max) {
+
+    LOG_F("ret (%" PRIu64 ") > max (%zu), rnd:%" PRIu64, ret, max, rnd);
+
+  }
+
+  return (size_t)ret;
+
+}
+
+/* Prefer smaller values here, so use mangle_getLen() */
+static inline size_t mangle_getOffSet(run_t *run) {
+
+  return mangle_getLen(run->dynfile->size) - 1;
+
+}
+
+/* Offset which can be equal to the file size */
+static inline size_t mangle_getOffSetPlus1(run_t *run) {
+
+  size_t reqlen = HF_MIN(run->dynfile->size + 1, _HF_INPUT_MAX_SIZE);
+  return mangle_getLen(reqlen) - 1;
+
+}
+
+static inline void mangle_Move(run_t *run, size_t off_from, size_t off_to,
+                               size_t len) {
+
+  if (off_from >= run->dynfile->size) { return; }
+  if (off_to >= run->dynfile->size) { return; }
+  if (off_from == off_to) { return; }
+
+  size_t len_from = run->dynfile->size - off_from;
+  len = HF_MIN(len, len_from);
+
+  size_t len_to = run->dynfile->size - off_to;
+  len = HF_MIN(len, len_to);
+
+  memmove(&run->dynfile->data[off_to], &run->dynfile->data[off_from], len);
+
+}
+
+static inline void mangle_Overwrite(run_t *run, size_t off, const uint8_t *src,
+                                    size_t len, bool printable) {
+
+  if (len == 0) { return; }
+  size_t maxToCopy = run->dynfile->size - off;
+  if (len > maxToCopy) { len = maxToCopy; }
+
+  memmove(&run->dynfile->data[off], src, len);
+  if (printable) { util_turnToPrintable(&run->dynfile->data[off], len); }
+
+}
+
+static inline size_t mangle_Inflate(run_t *run, size_t off, size_t len,
+                                    bool printable) {
+
+  if (run->dynfile->size >= run->global->mutate.maxInputSz) { return 0; }
+  if (len > (run->global->mutate.maxInputSz - run->dynfile->size)) {
+
+    len = run->global->mutate.maxInputSz - run->dynfile->size;
+
+  }
+
+  input_setSize(run, run->dynfile->size + len);
+  mangle_Move(run, off, off + len, run->dynfile->size);
+  if (printable) { memset(&run->dynfile->data[off], ' ', len); }
+
+  return len;
+
+}
+
+static inline void mangle_Insert(run_t *run, size_t off, const uint8_t *val,
+                                 size_t len, bool printable) {
+
+  len = mangle_Inflate(run, off, len, printable);
+  mangle_Overwrite(run, off, val, len, printable);
+
+}
+
+static inline void mangle_UseValue(run_t *run, const uint8_t *val, size_t len,
+                                   bool printable) {
+
+  if (util_rnd64() % 2) {
+
+    mangle_Insert(run, mangle_getOffSetPlus1(run), val, len, printable);
+
+  } else {
+
+    mangle_Overwrite(run, mangle_getOffSet(run), val, len, printable);
+
+  }
+
+}
+
+static void mangle_MemSwap(run_t *run, bool printable HF_ATTR_UNUSED) {
+
+  size_t off1 = mangle_getOffSet(run);
+  size_t maxlen1 = run->dynfile->size - off1;
+
+  size_t off2 = mangle_getOffSet(run);
+  size_t maxlen2 = run->dynfile->size - off2;
+
+  size_t   len = mangle_getLen(HF_MIN(maxlen1, maxlen2));
+  uint8_t *tmpbuf = (uint8_t *)util_Malloc(len);
+  defer {
+
+    free(tmpbuf);
+
+  };
+
+  memcpy(tmpbuf, &run->dynfile->data[off1], len);
+  memmove(&run->dynfile->data[off1], &run->dynfile->data[off2], len);
+  memcpy(&run->dynfile->data[off2], tmpbuf, len);
+
+}
+
+static void mangle_MemCopy(run_t *run, bool printable HF_ATTR_UNUSED) {
+
+  size_t off = mangle_getOffSet(run);
+  size_t len = mangle_getLen(run->dynfile->size - off);
+
+  /* Use a temp buf, as Insert/Inflate can change source bytes */
+  uint8_t *tmpbuf = (uint8_t *)util_Malloc(len);
+  defer {
+
+    free(tmpbuf);
+
+  };
+
+  memcpy(tmpbuf, &run->dynfile->data[off], len);
+
+  mangle_UseValue(run, tmpbuf, len, printable);
+
+}
+
+static void mangle_Bytes(run_t *run, bool printable) {
+
+  uint16_t buf;
+  if (printable) {
+
+    util_rndBufPrintable((uint8_t *)&buf, sizeof(buf));
+
+  } else {
+
+    buf = util_rnd64();
+
+  }
+
+  /* Overwrite with random 1-2-byte values */
+  size_t toCopy = util_rndGet(1, 2);
+  mangle_UseValue(run, (const uint8_t *)&buf, toCopy, printable);
+
+}
+
+static void mangle_ByteRepeatOverwrite(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+  size_t destOff = off + 1;
+  size_t maxSz = run->dynfile->size - destOff;
+
+  /* No space to repeat */
+  if (!maxSz) {
+
+    mangle_Bytes(run, printable);
+    return;
+
+  }
+
+  size_t len = mangle_getLen(maxSz);
+  memset(&run->dynfile->data[destOff], run->dynfile->data[off], len);
+
+}
+
+static void mangle_ByteRepeatInsert(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+  size_t destOff = off + 1;
+  size_t maxSz = run->dynfile->size - destOff;
+
+  /* No space to repeat */
+  if (!maxSz) {
+
+    mangle_Bytes(run, printable);
+    return;
+
+  }
+
+  size_t len = mangle_getLen(maxSz);
+  len = mangle_Inflate(run, destOff, len, printable);
+  memset(&run->dynfile->data[destOff], run->dynfile->data[off], len);
+
+}
+
+static void mangle_Bit(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+  run->dynfile->data[off] ^= (uint8_t)(1U << util_rndGet(0, 7));
+  if (printable) { util_turnToPrintable(&(run->dynfile->data[off]), 1); }
+
+}
+
+static const struct {
+
+  const uint8_t val[8];
+  const size_t  size;
+
+} mangleMagicVals[] = {
+
+    /* 1B - No endianness */
+    {"\x00\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x01\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x02\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x03\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x04\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x05\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x06\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x07\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x08\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x09\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x0A\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x0B\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x0C\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x0D\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x0E\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x0F\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x10\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x20\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x40\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x7E\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x7F\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x80\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\x81\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\xC0\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\xFE\x00\x00\x00\x00\x00\x00\x00", 1},
+    {"\xFF\x00\x00\x00\x00\x00\x00\x00", 1},
+    /* 2B - NE */
+    {"\x00\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x01\x01\x00\x00\x00\x00\x00\x00", 2},
+    {"\x80\x80\x00\x00\x00\x00\x00\x00", 2},
+    {"\xFF\xFF\x00\x00\x00\x00\x00\x00", 2},
+    /* 2B - BE */
+    {"\x00\x01\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x02\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x03\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x04\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x05\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x06\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x07\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x08\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x09\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x0A\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x0B\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x0C\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x0D\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x0E\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x0F\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x10\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x20\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x40\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x7E\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x7F\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x80\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x81\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\xC0\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\xFE\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\xFF\x00\x00\x00\x00\x00\x00", 2},
+    {"\x7E\xFF\x00\x00\x00\x00\x00\x00", 2},
+    {"\x7F\xFF\x00\x00\x00\x00\x00\x00", 2},
+    {"\x80\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x80\x01\x00\x00\x00\x00\x00\x00", 2},
+    {"\xFF\xFE\x00\x00\x00\x00\x00\x00", 2},
+    /* 2B - LE */
+    {"\x00\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x01\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x02\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x03\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x04\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x05\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x06\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x07\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x08\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x09\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x0A\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x0B\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x0C\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x0D\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x0E\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x0F\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x10\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x20\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x40\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x7E\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x7F\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x80\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\x81\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\xC0\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\xFE\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\xFF\x00\x00\x00\x00\x00\x00\x00", 2},
+    {"\xFF\x7E\x00\x00\x00\x00\x00\x00", 2},
+    {"\xFF\x7F\x00\x00\x00\x00\x00\x00", 2},
+    {"\x00\x80\x00\x00\x00\x00\x00\x00", 2},
+    {"\x01\x80\x00\x00\x00\x00\x00\x00", 2},
+    {"\xFE\xFF\x00\x00\x00\x00\x00\x00", 2},
+    /* 4B - NE */
+    {"\x00\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x01\x01\x01\x01\x00\x00\x00\x00", 4},
+    {"\x80\x80\x80\x80\x00\x00\x00\x00", 4},
+    {"\xFF\xFF\xFF\xFF\x00\x00\x00\x00", 4},
+    /* 4B - BE */
+    {"\x00\x00\x00\x01\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x02\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x03\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x04\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x05\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x06\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x07\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x08\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x09\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x0A\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x0B\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x0C\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x0D\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x0E\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x0F\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x10\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x20\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x40\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x7E\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x7F\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x80\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x81\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\xC0\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\xFE\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\xFF\x00\x00\x00\x00", 4},
+    {"\x7E\xFF\xFF\xFF\x00\x00\x00\x00", 4},
+    {"\x7F\xFF\xFF\xFF\x00\x00\x00\x00", 4},
+    {"\x80\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x80\x00\x00\x01\x00\x00\x00\x00", 4},
+    {"\xFF\xFF\xFF\xFE\x00\x00\x00\x00", 4},
+    /* 4B - LE */
+    {"\x00\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x01\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x02\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x03\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x04\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x05\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x06\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x07\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x08\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x09\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x0A\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x0B\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x0C\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x0D\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x0E\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x0F\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x10\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x20\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x40\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x7E\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x7F\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x80\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\x81\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\xC0\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\xFE\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\xFF\x00\x00\x00\x00\x00\x00\x00", 4},
+    {"\xFF\xFF\xFF\x7E\x00\x00\x00\x00", 4},
+    {"\xFF\xFF\xFF\x7F\x00\x00\x00\x00", 4},
+    {"\x00\x00\x00\x80\x00\x00\x00\x00", 4},
+    {"\x01\x00\x00\x80\x00\x00\x00\x00", 4},
+    {"\xFE\xFF\xFF\xFF\x00\x00\x00\x00", 4},
+    /* 8B - NE */
+    {"\x00\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x01\x01\x01\x01\x01\x01\x01\x01", 8},
+    {"\x80\x80\x80\x80\x80\x80\x80\x80", 8},
+    {"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
+    /* 8B - BE */
+    {"\x00\x00\x00\x00\x00\x00\x00\x01", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x02", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x03", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x04", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x05", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x06", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x07", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x08", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x09", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x0A", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x0B", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x0C", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x0D", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x0E", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x0F", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x10", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x20", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x40", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x7E", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x7F", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x80", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x81", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\xC0", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\xFE", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\xFF", 8},
+    {"\x7E\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
+    {"\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
+    {"\x80\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x80\x00\x00\x00\x00\x00\x00\x01", 8},
+    {"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE", 8},
+    /* 8B - LE */
+    {"\x00\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x01\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x02\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x03\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x04\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x05\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x06\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x07\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x08\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x09\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x0A\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x0B\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x0C\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x0D\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x0E\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x0F\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x10\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x20\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x40\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x7E\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x7F\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x80\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\x81\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\xC0\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\xFE\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\xFF\x00\x00\x00\x00\x00\x00\x00", 8},
+    {"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7E", 8},
+    {"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F", 8},
+    {"\x00\x00\x00\x00\x00\x00\x00\x80", 8},
+    {"\x01\x00\x00\x00\x00\x00\x00\x80", 8},
+    {"\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
+
+};
+
+static void mangle_Magic(run_t *run, bool printable) {
+
+  uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleMagicVals) - 1);
+  mangle_UseValue(run, mangleMagicVals[choice].val,
+                  mangleMagicVals[choice].size, printable);
+
+}
+
+static void mangle_StaticDict(run_t *run, bool printable) {
+
+  if (run->global->mutate.dictionaryCnt == 0) {
+
+    mangle_Bytes(run, printable);
+    return;
+
+  }
+
+  uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1);
+  mangle_UseValue(run, run->global->mutate.dictionary[choice].val,
+                  run->global->mutate.dictionary[choice].len, printable);
+
+}
+
+static inline const uint8_t *mangle_FeedbackDict(run_t *run, size_t *len) {
+
+  if (!run->global->feedback.cmpFeedback) { return NULL; }
+  cmpfeedback_t *cmpf = run->global->feedback.cmpFeedbackMap;
+  uint32_t       cnt = ATOMIC_GET(cmpf->cnt);
+  if (cnt == 0) { return NULL; }
+  if (cnt > ARRAYSIZE(cmpf->valArr)) { cnt = ARRAYSIZE(cmpf->valArr); }
+  uint32_t choice = util_rndGet(0, cnt - 1);
+  *len = (size_t)ATOMIC_GET(cmpf->valArr[choice].len);
+  if (*len == 0) { return NULL; }
+  return cmpf->valArr[choice].val;
+
+}
+
+static void mangle_ConstFeedbackDict(run_t *run, bool printable) {
+
+  size_t         len;
+  const uint8_t *val = mangle_FeedbackDict(run, &len);
+  if (val == NULL) {
+
+    mangle_Bytes(run, printable);
+    return;
+
+  }
+
+  mangle_UseValue(run, val, len, printable);
+
+}
+
+static void mangle_MemSet(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+  size_t len = mangle_getLen(run->dynfile->size - off);
+  int    val =
+      printable ? (int)util_rndPrintable() : (int)util_rndGet(0, UINT8_MAX);
+
+  memset(&run->dynfile->data[off], val, len);
+
+}
+
+static void mangle_RandomOverwrite(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+  size_t len = mangle_getLen(run->dynfile->size - off);
+  if (printable) {
+
+    util_rndBufPrintable(&run->dynfile->data[off], len);
+
+  } else {
+
+    util_rndBuf(&run->dynfile->data[off], len);
+
+  }
+
+}
+
+static void mangle_RandomInsert(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+  size_t len = mangle_getLen(run->dynfile->size - off);
+
+  len = mangle_Inflate(run, off, len, printable);
+
+  if (printable) {
+
+    util_rndBufPrintable(&run->dynfile->data[off], len);
+
+  } else {
+
+    util_rndBuf(&run->dynfile->data[off], len);
+
+  }
+
+}
+
+static inline void mangle_AddSubWithRange(run_t *run, size_t off, size_t varLen,
+                                          uint64_t range, bool printable) {
+
+  int64_t delta = (int64_t)util_rndGet(0, range * 2) - (int64_t)range;
+
+  switch (varLen) {
+
+    case 1: {
+
+      run->dynfile->data[off] += delta;
+      break;
+
+    }
+
+    case 2: {
+
+      int16_t val;
+      memcpy(&val, &run->dynfile->data[off], sizeof(val));
+      if (util_rnd64() & 0x1) {
+
+        val += delta;
+
+      } else {
+
+        /* Foreign endianess */
+        val = __builtin_bswap16(val);
+        val += delta;
+        val = __builtin_bswap16(val);
+
+      }
+
+      mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable);
+      break;
+
+    }
+
+    case 4: {
+
+      int32_t val;
+      memcpy(&val, &run->dynfile->data[off], sizeof(val));
+      if (util_rnd64() & 0x1) {
+
+        val += delta;
+
+      } else {
+
+        /* Foreign endianess */
+        val = __builtin_bswap32(val);
+        val += delta;
+        val = __builtin_bswap32(val);
+
+      }
+
+      mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable);
+      break;
+
+    }
+
+    case 8: {
+
+      int64_t val;
+      memcpy(&val, &run->dynfile->data[off], sizeof(val));
+      if (util_rnd64() & 0x1) {
+
+        val += delta;
+
+      } else {
+
+        /* Foreign endianess */
+        val = __builtin_bswap64(val);
+        val += delta;
+        val = __builtin_bswap64(val);
+
+      }
+
+      mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable);
+      break;
+
+    }
+
+    default: {
+
+      LOG_F("Unknown variable length size: %zu", varLen);
+
+    }
+
+  }
+
+}
+
+static void mangle_AddSub(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+
+  /* 1,2,4,8 */
+  size_t varLen = 1U << util_rndGet(0, 3);
+  if ((run->dynfile->size - off) < varLen) { varLen = 1; }
+
+  uint64_t range;
+  switch (varLen) {
+
+    case 1:
+      range = 16;
+      break;
+    case 2:
+      range = 4096;
+      break;
+    case 4:
+      range = 1048576;
+      break;
+    case 8:
+      range = 268435456;
+      break;
+    default:
+      LOG_F("Invalid operand size: %zu", varLen);
+
+  }
+
+  mangle_AddSubWithRange(run, off, varLen, range, printable);
+
+}
+
+static void mangle_IncByte(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+  if (printable) {
+
+    run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 1) % 95 + 32;
+
+  } else {
+
+    run->dynfile->data[off] += (uint8_t)1UL;
+
+  }
+
+}
+
+static void mangle_DecByte(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+  if (printable) {
+
+    run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 94) % 95 + 32;
+
+  } else {
+
+    run->dynfile->data[off] -= (uint8_t)1UL;
+
+  }
+
+}
+
+static void mangle_NegByte(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+  if (printable) {
+
+    run->dynfile->data[off] = 94 - (run->dynfile->data[off] - 32) + 32;
+
+  } else {
+
+    run->dynfile->data[off] = ~(run->dynfile->data[off]);
+
+  }
+
+}
+
+static void mangle_Expand(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+  size_t len;
+  if (util_rnd64() % 16) {
+
+    len = mangle_getLen(HF_MIN(16, run->global->mutate.maxInputSz - off));
+
+  } else {
+
+    len = mangle_getLen(run->global->mutate.maxInputSz - off);
+
+  }
+
+  mangle_Inflate(run, off, len, printable);
+
+}
+
+static void mangle_Shrink(run_t *run, bool printable HF_ATTR_UNUSED) {
+
+  if (run->dynfile->size <= 2U) { return; }
+
+  size_t off_start = mangle_getOffSet(run);
+  size_t len = mangle_LenLeft(run, off_start);
+  if (len == 0) { return; }
+  if (util_rnd64() % 16) {
+
+    len = mangle_getLen(HF_MIN(16, len));
+
+  } else {
+
+    len = mangle_getLen(len);
+
+  }
+
+  size_t off_end = off_start + len;
+  size_t len_to_move = run->dynfile->size - off_end;
+
+  mangle_Move(run, off_end, off_start, len_to_move);
+  input_setSize(run, run->dynfile->size - len);
+
+}
+
+static void mangle_ASCIINum(run_t *run, bool printable) {
+
+  size_t len = util_rndGet(2, 8);
+
+  char buf[20];
+  snprintf(buf, sizeof(buf), "%-19" PRId64, (int64_t)util_rnd64());
+
+  mangle_UseValue(run, (const uint8_t *)buf, len, printable);
+
+}
+
+static void mangle_ASCIINumChange(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+
+  /* Find a digit */
+  for (; off < run->dynfile->size; off++) {
+
+    if (isdigit(run->dynfile->data[off])) { break; }
+
+  }
+
+  if (off == run->dynfile->size) {
+
+    mangle_Bytes(run, printable);
+    return;
+
+  }
+
+  size_t len = HF_MIN(20, run->dynfile->size - off);
+  char   numbuf[21] = {};
+  strncpy(numbuf, (const char *)&run->dynfile->data[off], len);
+  uint64_t val = (uint64_t)strtoull(numbuf, NULL, 10);
+
+  switch (util_rndGet(0, 5)) {
+
+    case 0:
+      val += util_rndGet(1, 256);
+      break;
+    case 1:
+      val -= util_rndGet(1, 256);
+      break;
+    case 2:
+      val *= util_rndGet(1, 256);
+      break;
+    case 3:
+      val /= util_rndGet(1, 256);
+      break;
+    case 4:
+      val = ~(val);
+      break;
+    case 5:
+      val = util_rnd64();
+      break;
+    default:
+      LOG_F("Invalid choice");
+
+  };
+
+  len = HF_MIN((size_t)snprintf(numbuf, sizeof(numbuf), "%" PRIu64, val), len);
+  mangle_Overwrite(run, off, (const uint8_t *)numbuf, len, printable);
+
+}
+
+static void mangle_Splice(run_t *run, bool printable) {
+
+  const uint8_t *buf;
+  size_t         sz = input_getRandomInputAsBuf(run, &buf);
+  if (!sz) {
+
+    mangle_Bytes(run, printable);
+    return;
+
+  }
+
+  size_t remoteOff = mangle_getLen(sz) - 1;
+  size_t len = mangle_getLen(sz - remoteOff);
+  mangle_UseValue(run, &buf[remoteOff], len, printable);
+
+}
+
+static void mangle_Resize(run_t *run, bool printable) {
+
+  ssize_t oldsz = run->dynfile->size;
+  ssize_t newsz = 0;
+
+  uint64_t choice = util_rndGet(0, 32);
+  switch (choice) {
+
+    case 0:                                     /* Set new size arbitrarily */
+      newsz = (ssize_t)util_rndGet(1, run->global->mutate.maxInputSz);
+      break;
+    case 1 ... 4:                         /* Increase size by a small value */
+      newsz = oldsz + (ssize_t)util_rndGet(0, 8);
+      break;
+    case 5:                              /* Increase size by a larger value */
+      newsz = oldsz + (ssize_t)util_rndGet(9, 128);
+      break;
+    case 6 ... 9:                         /* Decrease size by a small value */
+      newsz = oldsz - (ssize_t)util_rndGet(0, 8);
+      break;
+    case 10:                             /* Decrease size by a larger value */
+      newsz = oldsz - (ssize_t)util_rndGet(9, 128);
+      break;
+    case 11 ... 32:                                           /* Do nothing */
+      newsz = oldsz;
+      break;
+    default:
+      LOG_F("Illegal value from util_rndGet: %" PRIu64, choice);
+      break;
+
+  }
+
+  if (newsz < 1) { newsz = 1; }
+  if (newsz > (ssize_t)run->global->mutate.maxInputSz) {
+
+    newsz = run->global->mutate.maxInputSz;
+
+  }
+
+  input_setSize(run, (size_t)newsz);
+  if (newsz > oldsz) {
+
+    if (printable) { memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz); }
+
+  }
+
+}
+
+void mangle_mangleContent(run_t *run, int speed_factor) {
+
+  static void (*const mangleFuncs[])(run_t * run, bool printable) = {
+
+      /* Every *Insert or Expand expands file, so add more Shrink's */
+      mangle_Shrink,
+      mangle_Shrink,
+      mangle_Shrink,
+      mangle_Shrink,
+      mangle_Expand,
+      mangle_Bit,
+      mangle_IncByte,
+      mangle_DecByte,
+      mangle_NegByte,
+      mangle_AddSub,
+      mangle_MemSet,
+      mangle_MemSwap,
+      mangle_MemCopy,
+      mangle_Bytes,
+      mangle_ASCIINum,
+      mangle_ASCIINumChange,
+      mangle_ByteRepeatOverwrite,
+      mangle_ByteRepeatInsert,
+      mangle_Magic,
+      mangle_StaticDict,
+      mangle_ConstFeedbackDict,
+      mangle_RandomOverwrite,
+      mangle_RandomInsert,
+      mangle_Splice,
+
+  };
+
+  if (run->mutationsPerRun == 0U) { return; }
+  if (run->dynfile->size == 0U) {
+
+    mangle_Resize(run, /* printable= */ run->global->cfg.only_printable);
+
+  }
+
+  uint64_t changesCnt = run->global->mutate.mutationsPerRun;
+
+  if (speed_factor < 5) {
+
+    changesCnt = util_rndGet(1, run->global->mutate.mutationsPerRun);
+
+  } else if (speed_factor < 10) {
+
+    changesCnt = run->global->mutate.mutationsPerRun;
+
+  } else {
+
+    changesCnt = HF_MIN(speed_factor, 12);
+    changesCnt = HF_MAX(changesCnt, run->global->mutate.mutationsPerRun);
+
+  }
+
+  /* If last coverage acquisition was more than 5 secs ago, use splicing more
+   * frequently */
+  if ((time(NULL) - ATOMIC_GET(run->global->timing.lastCovUpdate)) > 5) {
+
+    if (util_rnd64() % 2) {
+
+      mangle_Splice(run, run->global->cfg.only_printable);
+
+    }
+
+  }
+
+  for (uint64_t x = 0; x < changesCnt; x++) {
+
+    uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1);
+    mangleFuncs[choice](run, /* printable= */ run->global->cfg.only_printable);
+
+  }
+
+  wmb();
+
+}
+
diff --git a/custom_mutators/honggfuzz/mangle.h b/custom_mutators/honggfuzz/mangle.h
new file mode 100644
index 00000000..1b6a4943
--- /dev/null
+++ b/custom_mutators/honggfuzz/mangle.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * honggfuzz - buffer mangling routines
+ * -----------------------------------------
+ *
+ * Author: Robert Swiecki <swiecki@google.com>
+ *
+ * Copyright 2010-2018 by Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ *
+ */
+
+#ifndef _HF_MANGLE_H_
+#define _HF_MANGLE_H_
+
+#include "honggfuzz.h"
+
+extern void mangle_mangleContent(run_t *run, int speed_factor);
+
+#endif
+
diff --git a/custom_mutators/honggfuzz/util.h b/custom_mutators/honggfuzz/util.h
new file mode 120000
index 00000000..51e19654
--- /dev/null
+++ b/custom_mutators/honggfuzz/util.h
@@ -0,0 +1 @@
+common.h
\ No newline at end of file
diff --git a/dictionaries/rtf.dict b/dictionaries/rtf.dict
index 8b8f0cad..2d5019ef 100644
--- a/dictionaries/rtf.dict
+++ b/dictionaries/rtf.dict
@@ -3,10 +3,12 @@
 # charset
 "\\ansi"
 "\\mac"
+"\\pc"
 "\\pca"
 
 # font table
 "\\fnil"
+"\\fRoman"
 "\\fswiss"
 "\\fmodern"
 "\\fscript"
@@ -28,6 +30,7 @@
 "\\cb"
 
 # pictures
+"\\pict"
 "\\macpict"
 "\\pmmetafile"
 "\\wmetafile"
@@ -40,36 +43,15 @@
 "\\pich"
 "\\picwgoal"
 "\\pichgoal"
+"\\picscalex"
 "\\picscaley"
 "\\picscaled"
 "\\piccropt"
 "\\piccropb"
 "\\piccropl"
 "\\piccropr"
-"\\brdrs"
-"\\brdrdb"
-"\\brdrth"
-"\\brdrsh"
-"\\brdrdot"
-"\\brdrhair"
-"\\brdrw"
-"\\brdrcf"
-"\\shading"
-"\\bghoriz"
-"\\bgvert"
-"\\bgfdiag"
-"\\bgbdiag"
-"\\bgcross"
-"\\bgdcross"
-"\\bgdkhoriz"
-"\\bgdkvert"
-"\\bgdkfdiag"
-"\\bgdkbdiag"
-"\\bgdkcross"
-"\\bgdkdcross"
-"\\cfpat"
-"\\cbpat"
 "\\bin"
+# these strings are probably not necessary
 "MM_TEXT"
 "MM_LOMETRIC"
 "MM_HIMETRIC"
@@ -86,25 +68,31 @@
 "PU_HIENGLISH"
 "PU_TWIPS"
 
-# headers and gooters
-"\headerr"
-"\headerf"
-"\footerl"
-"\footerr"
-"\footerf"
+# headers and footers
+"\\headerl"
+"\\headerr"
+"\\headerf"
+"\\footerl"
+"\\footerr"
+"\\footerf"
 
 # misc
-"\\chftn"
 "\\*\\footnote"
 "\\*\\annotation"
+"\\xe"
+"\\txe"
+"\\rxe"
 "\\bxe"
 "\\ixe"
 "\\tcf"
 "\\tcl"
 "\\*\\bkmkstart"
 "\\*\\bkmkend"
+"\\bkmkcolf"
+"\\bkmkcoll"
 
 # metadata
+"\\info"
 "\\title"
 "\\subject"
 "\\author"
@@ -128,10 +116,13 @@
 "\\nofwords"
 "\\nofchars"
 "\\id"
+"\\field"
 "\\flddirty"
 "\\fldedit"
 "\\fldlock"
 "\\fldpriv"
+"\\*\\fldinst"
+"\\fldrslt"
 
 # objects
 "\\objemb"
@@ -166,16 +157,14 @@
 # macintosh editor
 "\\bkmkpub"
 "\\pubauto"
-"\\objalias"
-"\\objsect"
 
 # formating
 "\\deftab"
 "\\hyphhotz"
 "\\linestart"
 "\\fracwidth"
-"\\*\nextfile"
-"\\*\template"
+"\\*\\nextfile"
+"\\*\\template"
 "\\makebackup"
 "\\defformat"
 "\\psover"
diff --git a/docs/Changelog.md b/docs/Changelog.md
index afb9dea6..38787def 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -9,6 +9,24 @@ Want to stay in the loop on major new features? Join our mailing list by
 sending a mail to <afl-users+subscribe@googlegroups.com>.
 
 
+### Version ++2.66d (devel)
+  - afl-fuzz:
+     - added -F option to allow -M main fuzzers to sync to foreign fuzzers,
+       e.g. honggfuzz or libfuzzer
+     - eliminated CPU affinity race condition for -S/-M runs
+  - llvm_mode:
+     - now supports llvm 12!
+     - fixes for laf-intel float splitting (thanks to mark-griffin for
+       reporting)
+     - LTO: autodictionary mode is a default
+     - LTO: instrim instrumentation disabled, only classic support used
+            as it is always better
+  - added honggfuzz mangle as a custom mutator in custom_mutators/honggfuzz :)
+  - added afl-frida gum solution to examples/afl_frida (mostly imported
+    from https://github.com/meme/hotwax/)
+  - small fixes to afl-plot, afl-whatsup and man page creation
+
+
 ### Version ++2.66c (release)
   - renamed the main branch on Github to "stable"
   - renamed master/slave to main/secondary
diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md
index 464acbee..a22c809b 100644
--- a/docs/custom_mutators.md
+++ b/docs/custom_mutators.md
@@ -36,7 +36,7 @@ size_t afl_custom_fuzz(void *data, uint8_t *buf, size_t buf_size, u8 **out_buf,
 size_t afl_custom_post_process(void *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf);
 int32_t afl_custom_init_trim(void *data, uint8_t *buf, size_t buf_size);
 size_t afl_custom_trim(void *data, uint8_t **out_buf);
-int32_t afl_custom_post_trim(void *data, int success) {
+int32_t afl_custom_post_trim(void *data, int success);
 size_t afl_custom_havoc_mutation(void *data, u8 *buf, size_t buf_size, u8 **out_buf, size_t max_size);
 uint8_t afl_custom_havoc_mutation_probability(void *data);
 uint8_t afl_custom_queue_get(void *data, const uint8_t *filename);
diff --git a/docs/parallel_fuzzing.md b/docs/parallel_fuzzing.md
index 271f8369..2ab1466c 100644
--- a/docs/parallel_fuzzing.md
+++ b/docs/parallel_fuzzing.md
@@ -99,7 +99,15 @@ example may be:
 This is not a concern if you use @@ without -f and let afl-fuzz come up with the
 file name.
 
-## 3) Multi-system parallelization
+## 3) Syncing with non-afl fuzzers or independant instances
+
+A -M main node can be told with the `-F other_fuzzer_queue_directory` option
+to sync results from other fuzzers, e.g. libfuzzer or honggfuzz.
+
+Only the specified directory will by synced into afl, not subdirectories.
+The specified directories do not need to exist yet at the start of afl.
+
+## 4) Multi-system parallelization
 
 The basic operating principle for multi-system parallelization is similar to
 the mechanism explained in section 2. The key difference is that you need to
@@ -176,7 +184,7 @@ It is *not* advisable to skip the synchronization script and run the fuzzers
 directly on a network filesystem; unexpected latency and unkillable processes
 in I/O wait state can mess things up.
 
-## 4) Remote monitoring and data collection
+## 5) Remote monitoring and data collection
 
 You can use screen, nohup, tmux, or something equivalent to run remote
 instances of afl-fuzz. If you redirect the program's output to a file, it will
@@ -200,7 +208,7 @@ Keep in mind that crashing inputs are *not* automatically propagated to the
 main instance, so you may still want to monitor for crashes fleet-wide
 from within your synchronization or health checking scripts (see afl-whatsup).
 
-## 5) Asymmetric setups
+## 6) Asymmetric setups
 
 It is perhaps worth noting that all of the following is permitted:
 
diff --git a/docs/screenshot.png b/docs/screenshot.png
new file mode 100644
index 00000000..7b4dd7e4
--- /dev/null
+++ b/docs/screenshot.png
Binary files differdiff --git a/examples/afl_frida/Makefile b/examples/afl_frida/Makefile
new file mode 100644
index 00000000..c154f3a4
--- /dev/null
+++ b/examples/afl_frida/Makefile
@@ -0,0 +1,23 @@
+ifdef DEBUG
+  OPT=-O0 -D_DEBUG=\"1\"
+else
+  OPT=-O3 -funroll-loops
+endif
+
+all:	afl-frida libtestinstr.so
+
+libfrida-gum.a:
+	@echo Download and extract frida-gum-devkit-VERSION-PLATFORM.tar.xz for your platform from https://github.com/frida/frida/releases/latest
+	@exit 1
+	
+afl-frida:	afl-frida.c libfrida-gum.a
+	$(CC) -g $(OPT) -o afl-frida -Wno-format -Wno-pointer-sign -I. -fpermissive -fPIC afl-frida.c ../../afl-llvm-rt.o libfrida-gum.a -ldl -lresolv -pthread
+
+libtestinstr.so:        libtestinstr.c
+	$(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c
+
+clean:
+	rm -f afl-frida *~ core *.o libtestinstr.so
+
+deepclean: clean
+	rm -f libfrida-gum.a frida-gum*
diff --git a/examples/afl_frida/README.md b/examples/afl_frida/README.md
new file mode 100644
index 00000000..7743479b
--- /dev/null
+++ b/examples/afl_frida/README.md
@@ -0,0 +1,34 @@
+# afl-frida - faster fuzzing of binary-only libraries
+
+## Introduction
+
+afl-frida is an example skeleton file which can easily be used to fuzz
+a closed source library.
+
+It requires less memory and is x5-10 faster than qemu_mode but does not
+provide interesting features like compcov or cmplog.
+
+## How-to
+
+### Modify afl-frida.c
+
+Read and modify afl-frida.c then `make`.
+To adapt afl-frida.c to your needs, read the header of the file and then
+search and edit the `STEP 1`, `STEP 2` and `STEP 3` locations.
+
+### Fuzzing
+
+Example (after modifying afl-frida.c to your needs and compile it):
+```
+LD_LIBRARY_PATH=/path/to/the/target/library afl-fuzz -i in -o out -- ./afl-frida
+```
+(or even remote via afl-network-proxy).
+
+# Speed and stability
+
+The speed is very good, about x12 of fork() qemu_mode.
+However the stability is low. Reason is currently unknown.
+
+# Background
+
+This code is copied for a larger part from https://github.com/meme/hotwax
diff --git a/examples/afl_frida/afl-frida.c b/examples/afl_frida/afl-frida.c
new file mode 100644
index 00000000..2ad5a72a
--- /dev/null
+++ b/examples/afl_frida/afl-frida.c
@@ -0,0 +1,541 @@
+/*
+   american fuzzy lop++ - afl-frida skeleton example
+   -------------------------------------------------
+
+   Copyright 2020 AFLplusplus Project. All rights reserved.
+
+   Written mostly by meme -> https://github.com/meme/hotwax
+
+   Modificationy by Marc Heuse <mh@mh-sec.de>
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at:
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   HOW-TO
+   ======
+
+   You only need to change the following:
+
+   1. set the defines and function call parameters.
+   2. dl load the library you want to fuzz, lookup the functions you need
+      and setup the calls to these.
+   3. in the while loop you call the functions in the necessary order -
+      incl the cleanup. the cleanup is important!
+
+   Just look these steps up in the code, look for "// STEP x:"
+
+*/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/shm.h>
+#include <dlfcn.h>
+
+#ifndef __APPLE__
+  #include <sys/wait.h>
+  #include <sys/personality.h>
+#endif
+
+int debug = 0;
+
+// STEP 1:
+
+// The presets are for the example libtestinstr.so:
+
+/* What is the name of the library to fuzz */
+#define TARGET_LIBRARY "libtestinstr.so"
+
+/* What is the name of the function to fuzz */
+#define TARGET_FUNCTION "testinstr"
+
+/* here you need to specify the parameter for the target function */
+static void *(*o_function)(uint8_t *, int);
+
+// END STEP 1
+
+#include "frida-gum.h"
+
+G_BEGIN_DECLS
+
+#define GUM_TYPE_FAKE_EVENT_SINK (gum_fake_event_sink_get_type())
+G_DECLARE_FINAL_TYPE(GumFakeEventSink, gum_fake_event_sink, GUM,
+                     FAKE_EVENT_SINK, GObject)
+
+struct _GumFakeEventSink {
+
+  GObject      parent;
+  GumEventType mask;
+
+};
+
+GumEventSink *gum_fake_event_sink_new(void);
+void          gum_fake_event_sink_reset(GumFakeEventSink *self);
+
+G_END_DECLS
+
+static void         gum_fake_event_sink_iface_init(gpointer g_iface,
+                                                   gpointer iface_data);
+static void         gum_fake_event_sink_finalize(GObject *obj);
+static GumEventType gum_fake_event_sink_query_mask(GumEventSink *sink);
+static void gum_fake_event_sink_process(GumEventSink *sink, const GumEvent *ev);
+void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output,
+                       gpointer user_data);
+void afl_setup(void);
+void afl_start_forkserver(void);
+int  __afl_persistent_loop(unsigned int max_cnt);
+
+static void gum_fake_event_sink_class_init(GumFakeEventSinkClass *klass) {
+
+  GObjectClass *object_class = G_OBJECT_CLASS(klass);
+  object_class->finalize = gum_fake_event_sink_finalize;
+
+}
+
+static void gum_fake_event_sink_iface_init(gpointer g_iface,
+                                           gpointer iface_data) {
+
+  GumEventSinkInterface *iface = (GumEventSinkInterface *)g_iface;
+  iface->query_mask = gum_fake_event_sink_query_mask;
+  iface->process = gum_fake_event_sink_process;
+
+}
+
+G_DEFINE_TYPE_EXTENDED(GumFakeEventSink, gum_fake_event_sink, G_TYPE_OBJECT, 0,
+                       G_IMPLEMENT_INTERFACE(GUM_TYPE_EVENT_SINK,
+                                             gum_fake_event_sink_iface_init))
+
+#include "../../config.h"
+
+// Shared memory fuzzing.
+int                   __afl_sharedmem_fuzzing = 1;
+extern unsigned int * __afl_fuzz_len;
+extern unsigned char *__afl_fuzz_ptr;
+
+// Notify AFL about persistent mode.
+static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
+int                  __afl_persistent_loop(unsigned int);
+
+// Notify AFL about deferred forkserver.
+static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
+void                 __afl_manual_init();
+
+// Because we do our own logging.
+extern uint8_t *        __afl_area_ptr;
+static __thread guint64 previous_pc;
+
+// Frida stuff below.
+typedef struct {
+
+  GumAddress base_address;
+  guint64    code_start, code_end;
+
+} range_t;
+
+inline static void afl_maybe_log(guint64 current_pc) {
+
+  // fprintf(stderr, "PC: %p ^ %p\n", current_pc, previous_pc);
+
+  current_pc = (current_pc >> 4) ^ (current_pc << 8);
+  current_pc &= MAP_SIZE - 1;
+
+  __afl_area_ptr[current_pc ^ previous_pc]++;
+  previous_pc = current_pc >> 1;
+
+}
+
+static void on_basic_block(GumCpuContext *context, gpointer user_data) {
+
+  afl_maybe_log((guint64)user_data);
+
+}
+
+void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output,
+                       gpointer user_data) {
+
+  range_t *range = (range_t *)user_data;
+
+  const cs_insn *instr;
+  gboolean       begin = TRUE;
+  while (gum_stalker_iterator_next(iterator, &instr)) {
+
+    if (begin) {
+
+      if (instr->address >= range->code_start &&
+          instr->address <= range->code_end) {
+
+        gum_stalker_iterator_put_callout(iterator, on_basic_block,
+                                         (gpointer)instr->address, NULL);
+        begin = FALSE;
+
+      }
+
+    }
+
+    gum_stalker_iterator_keep(iterator);
+
+  }
+
+}
+
+static void gum_fake_event_sink_init(GumFakeEventSink *self) {
+
+}
+
+static void gum_fake_event_sink_finalize(GObject *obj) {
+
+  G_OBJECT_CLASS(gum_fake_event_sink_parent_class)->finalize(obj);
+
+}
+
+GumEventSink *gum_fake_event_sink_new(void) {
+
+  GumFakeEventSink *sink;
+  sink = (GumFakeEventSink *)g_object_new(GUM_TYPE_FAKE_EVENT_SINK, NULL);
+  return GUM_EVENT_SINK(sink);
+
+}
+
+void gum_fake_event_sink_reset(GumFakeEventSink *self) {
+
+}
+
+static GumEventType gum_fake_event_sink_query_mask(GumEventSink *sink) {
+
+  return 0;
+
+}
+
+typedef struct library_list {
+
+  uint8_t *name;
+  uint64_t addr_start, addr_end;
+
+} library_list_t;
+
+#define MAX_LIB_COUNT 256
+static library_list_t liblist[MAX_LIB_COUNT];
+static u32            liblist_cnt;
+
+void read_library_information() {
+
+#if defined(__linux__)
+  FILE *f;
+  u8    buf[1024], *b, *m, *e, *n;
+
+  if ((f = fopen("/proc/self/maps", "r")) == NULL) {
+
+    fprintf(stderr, "Error: cannot open /proc/self/maps\n");
+    exit(-1);
+
+  }
+
+  if (debug) fprintf(stderr, "Library list:\n");
+  while (fgets(buf, sizeof(buf), f)) {
+
+    if (strstr(buf, " r-x")) {
+
+      if (liblist_cnt >= MAX_LIB_COUNT) {
+
+        fprintf(
+            stderr,
+            "Warning: too many libraries to old, maximum count of %d reached\n",
+            liblist_cnt);
+        return;
+
+      }
+
+      b = buf;
+      m = index(buf, '-');
+      e = index(buf, ' ');
+      if ((n = rindex(buf, '/')) == NULL) n = rindex(buf, ' ');
+      if (n &&
+          ((*n >= '0' && *n <= '9') || *n == '[' || *n == '{' || *n == '('))
+        n = NULL;
+      else
+        n++;
+      if (b && m && e && n && *n) {
+
+        *m++ = 0;
+        *e = 0;
+        if (n[strlen(n) - 1] == '\n') n[strlen(n) - 1] = 0;
+
+        if (rindex(n, '/') != NULL) {
+
+          n = rindex(n, '/');
+          n++;
+
+        }
+
+        liblist[liblist_cnt].name = strdup(n);
+        liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16);
+        liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16);
+        if (debug)
+          fprintf(
+              stderr, "%s:%llx (%llx-%llx)\n", liblist[liblist_cnt].name,
+              liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
+              liblist[liblist_cnt].addr_start,
+              liblist[liblist_cnt].addr_end - 1);
+        liblist_cnt++;
+
+      }
+
+    }
+
+  }
+
+  if (debug) fprintf(stderr, "\n");
+
+#elif defined(__FreeBSD__)
+  int    mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()};
+  char * buf, *start, *end;
+  size_t miblen = sizeof(mib) / sizeof(mib[0]);
+  size_t len;
+
+  if (debug) fprintf(stderr, "Library list:\n");
+  if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) { return; }
+
+  len = len * 4 / 3;
+
+  buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+  if (buf == MAP_FAILED) { return; }
+  if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) {
+
+    munmap(buf, len);
+    return;
+
+  }
+
+  start = buf;
+  end = buf + len;
+
+  while (start < end) {
+
+    struct kinfo_vmentry *region = (struct kinfo_vmentry *)start;
+    size_t                size = region->kve_structsize;
+
+    if (size == 0) { break; }
+
+    if ((region->kve_protection & KVME_PROT_READ) &&
+        !(region->kve_protection & KVME_PROT_EXEC)) {
+
+      liblist[liblist_cnt].name =
+          region->kve_path[0] != '\0' ? strdup(region->kve_path) : 0;
+      liblist[liblist_cnt].addr_start = region->kve_start;
+      liblist[liblist_cnt].addr_end = region->kve_end;
+
+      if (debug) {
+
+        fprintf(stderr, "%s:%x (%lx-%lx)\n", liblist[liblist_cnt].name,
+                liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start,
+                liblist[liblist_cnt].addr_start,
+                liblist[liblist_cnt].addr_end - 1);
+
+      }
+
+      liblist_cnt++;
+
+    }
+
+    start += size;
+
+  }
+
+#endif
+
+}
+
+library_list_t *find_library(char *name) {
+
+  char *filename = rindex(name, '/');
+
+  if (filename)
+    filename++;
+  else
+    filename = name;
+
+#if defined(__linux__)
+  u32 i;
+  for (i = 0; i < liblist_cnt; i++)
+    if (strcmp(liblist[i].name, filename) == 0) return &liblist[i];
+#elif defined(__APPLE__) && defined(__LP64__)
+  kern_return_t         err;
+  static library_list_t lib;
+
+  // get the list of all loaded modules from dyld
+  // the task_info mach API will get the address of the dyld all_image_info
+  // struct for the given task from which we can get the names and load
+  // addresses of all modules
+  task_dyld_info_data_t  task_dyld_info;
+  mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+  err = task_info(mach_task_self(), TASK_DYLD_INFO,
+                  (task_info_t)&task_dyld_info, &count);
+
+  const struct dyld_all_image_infos *all_image_infos =
+      (const struct dyld_all_image_infos *)task_dyld_info.all_image_info_addr;
+  const struct dyld_image_info *image_infos = all_image_infos->infoArray;
+
+  for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) {
+
+    const char *      image_name = image_infos[i].imageFilePath;
+    mach_vm_address_t image_load_address =
+        (mach_vm_address_t)image_infos[i].imageLoadAddress;
+    if (strstr(image_name, name)) {
+
+      lib.name = name;
+      lib.addr_start = (u64)image_load_address;
+      lib.addr_end = 0;
+      return &lib;
+
+    }
+
+  }
+
+#endif
+
+  return NULL;
+
+}
+
+static void gum_fake_event_sink_process(GumEventSink *  sink,
+                                        const GumEvent *ev) {
+
+}
+
+/* Because this CAN be called more than once, it will return the LAST range */
+static int enumerate_ranges(const GumRangeDetails *details,
+                            gpointer               user_data) {
+
+  GumMemoryRange *code_range = (GumMemoryRange *)user_data;
+  memcpy(code_range, details->range, sizeof(*code_range));
+  return 0;
+
+}
+
+int main() {
+
+#ifndef __APPLE__
+  (void)personality(ADDR_NO_RANDOMIZE);  // disable ASLR
+#endif
+
+  // STEP 2: load the library you want to fuzz and lookup the functions,
+  //         inclusive of the cleanup functions.
+  //         If there is just one function, then there is nothing to change
+  //         or add here.
+
+  void *dl = dlopen(TARGET_LIBRARY, RTLD_LAZY);
+  if (!dl) {
+
+    fprintf(stderr, "Could not load %s\n", TARGET_LIBRARY);
+    exit(-1);
+
+  }
+
+  if (!(o_function = dlsym(dl, TARGET_FUNCTION))) {
+
+    fprintf(stderr, "Could not find function %s\n", TARGET_FUNCTION);
+    exit(-1);
+
+  }
+
+  // END STEP 2
+
+  read_library_information();
+  library_list_t *lib = find_library(TARGET_LIBRARY);
+
+  if (lib == NULL) {
+
+    fprintf(stderr, "Could not find target library\n");
+    exit(-1);
+
+  }
+
+  gum_init_embedded();
+  if (!gum_stalker_is_supported()) {
+
+    gum_deinit_embedded();
+    return 1;
+
+  }
+
+  GumStalker *stalker = gum_stalker_new();
+
+  /*
+  This does not work here as we load a shared library. pretty sure this
+  would also be easily solvable with frida gum, but I already have all the
+  code I need from afl-untracer
+
+  GumAddress base_address = gum_module_find_base_address(TARGET_LIBRARY);
+  GumMemoryRange code_range;
+  gum_module_enumerate_ranges(TARGET_LIBRARY, GUM_PAGE_RX, enumerate_ranges,
+                              &code_range);
+  guint64 code_start = code_range.base_address - base_address;
+  guint64 code_end = (code_range.base_address + code_range.size) - base_address;
+  range_t instr_range = {base_address, code_start, code_end};
+  */
+  range_t instr_range = {0, lib->addr_start, lib->addr_end};
+
+  GumStalkerTransformer *transformer =
+      gum_stalker_transformer_make_from_callback(instr_basic_block,
+                                                 &instr_range, NULL);
+
+  GumEventSink *event_sink = gum_fake_event_sink_new();
+
+  // to ensure that the signatures are not optimized out
+  memcpy(__afl_area_ptr, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT) + 1);
+  memcpy(__afl_area_ptr + 32, (void *)AFL_DEFER_FORKSVR,
+         sizeof(AFL_DEFER_FORKSVR) + 1);
+  __afl_manual_init();
+
+  //
+  // any expensive target library initialization that has to be done just once
+  // - put that here
+  //
+
+  gum_stalker_follow_me(stalker, transformer, event_sink);
+
+  while (__afl_persistent_loop(UINT32_MAX) != 0) {
+
+    previous_pc = 0;  // Required!
+
+#ifdef _DEBUG
+    fprintf(stderr, "CLIENT crc: %016llx len: %u\n", hash64(__afl_fuzz_ptr, *__a
+    fprintf(stderr, "RECV:");
+    for (int i = 0; i < *__afl_fuzz_len; i++)
+      fprintf(stderr, "%02x", __afl_fuzz_ptr[i]);
+    fprintf(stderr,"\n");
+#endif
+
+    // STEP 3: ensure the minimum length is present and setup the target
+    //         function to fuzz.
+
+    if (*__afl_fuzz_len > 0) {
+
+      __afl_fuzz_ptr[*__afl_fuzz_len] = 0;  // if you need to null terminate
+      (*o_function)(__afl_fuzz_ptr, *__afl_fuzz_len);
+
+    }
+
+    // END STEP 3
+
+  }
+
+  gum_stalker_unfollow_me(stalker);
+
+  while (gum_stalker_garbage_collect(stalker))
+    g_usleep(10000);
+
+  g_object_unref(stalker);
+  g_object_unref(transformer);
+  g_object_unref(event_sink);
+  gum_deinit_embedded();
+
+  return 0;
+
+}
+
diff --git a/examples/afl_frida/afl-frida.h b/examples/afl_frida/afl-frida.h
new file mode 100644
index 00000000..efa3440f
--- /dev/null
+++ b/examples/afl_frida/afl-frida.h
@@ -0,0 +1,53 @@
+extern int is_persistent;
+
+G_BEGIN_DECLS
+
+#define GUM_TYPE_FAKE_EVENT_SINK (gum_fake_event_sink_get_type())
+
+G_DECLARE_FINAL_TYPE(GumFakeEventSink, gum_fake_event_sink, GUM,
+                     FAKE_EVENT_SINK, GObject)
+
+struct _GumFakeEventSink {
+
+  GObject      parent;
+  GumEventType mask;
+
+};
+
+GumEventSink *gum_fake_event_sink_new(void);
+void          gum_fake_event_sink_reset(GumFakeEventSink *self);
+
+G_END_DECLS
+
+typedef struct {
+
+  GumAddress base_address;
+  guint64    code_start, code_end;
+
+} range_t;
+
+void instr_basic_block(GumStalkerIterator *iterator, GumStalkerOutput *output,
+                       gpointer user_data);
+#pragma once
+
+void afl_setup(void);
+void afl_start_forkserver(void);
+int  __afl_persistent_loop(unsigned int max_cnt);
+
+inline static inline void afl_maybe_log(guint64 current_pc) {
+
+  extern unsigned int afl_instr_rms;
+  extern uint8_t *    afl_area_ptr;
+
+  static __thread guint64 previous_pc;
+
+  current_pc = (current_pc >> 4) ^ (current_pc << 8);
+  current_pc &= MAP_SIZE - 1;
+
+  if (current_pc >= afl_instr_rms) return;
+
+  afl_area_ptr[current_pc ^ previous_pc]++;
+  previous_pc = current_pc >> 1;
+
+}
+
diff --git a/examples/afl_frida/libtestinstr.c b/examples/afl_frida/libtestinstr.c
new file mode 100644
index 00000000..96b1cf21
--- /dev/null
+++ b/examples/afl_frida/libtestinstr.c
@@ -0,0 +1,35 @@
+/*
+   american fuzzy lop++ - a trivial program to test the build
+   --------------------------------------------------------
+   Originally written by Michal Zalewski
+   Copyright 2014 Google Inc. All rights reserved.
+   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at:
+     http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+void testinstr(char *buf, int len) {
+
+  if (len < 1) return;
+  buf[len] = 0;
+
+  // we support three input cases
+  if (buf[0] == '0')
+    printf("Looks like a zero to me!\n");
+  else if (buf[0] == '1')
+    printf("Pretty sure that is a one!\n");
+  else
+    printf("Neither one or zero? How quaint!\n");
+
+}
+
diff --git a/examples/afl_network_proxy/afl-network-client.c b/examples/afl_network_proxy/afl-network-client.c
index 5af41055..a2451fdc 100644
--- a/examples/afl_network_proxy/afl-network-client.c
+++ b/examples/afl_network_proxy/afl-network-client.c
@@ -34,7 +34,9 @@
 #include <netinet/ip6.h>
 #include <arpa/inet.h>
 #include <sys/mman.h>
-#include <sys/shm.h>
+#ifndef USEMMAP
+  #include <sys/shm.h>
+#endif
 #include <sys/wait.h>
 #include <sys/types.h>
 #include <sys/socket.h>
diff --git a/examples/afl_untracer/README.md b/examples/afl_untracer/README.md
index e59792cb..ada0c916 100644
--- a/examples/afl_untracer/README.md
+++ b/examples/afl_untracer/README.md
@@ -32,13 +32,14 @@ To easily run the scripts without needing to run the GUI with Ghidra:
 /opt/ghidra/support/analyzeHeadless /tmp/ tmp$$ -import libtestinstr.so -postscript ./ghidra_get_patchpoints.java
 rm -rf /tmp/tmp$$
 ```
+The file is created at `~/Desktop/patches.txt`
 
 ### Fuzzing
 
 Example (after modifying afl-untracer.c to your needs, compiling and creating
 patches.txt):
 ```
-AFL_UNTRACER_FILE=./patches.txt afl-fuzz -i in -o out -- ./afl-untracer
+LD_LIBRARY_PATH=/path/to/target/library AFL_UNTRACER_FILE=./patches.txt afl-fuzz -i in -o out -- ./afl-untracer
 ```
 (or even remote via afl-network-proxy).
 
diff --git a/examples/afl_untracer/TODO b/examples/afl_untracer/TODO
new file mode 100644
index 00000000..fffffacf
--- /dev/null
+++ b/examples/afl_untracer/TODO
@@ -0,0 +1,2 @@
+ * add shmem fuzzing
+ * add snapshot feature?
diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c
index 664e691c..68658bfd 100644
--- a/examples/afl_untracer/afl-untracer.c
+++ b/examples/afl_untracer/afl-untracer.c
@@ -56,6 +56,7 @@
 #include <sys/shm.h>
 #include <sys/wait.h>
 #include <sys/types.h>
+#include <sys/personality.h>
 
 #if defined(__linux__)
   #include <sys/ucontext.h>
@@ -73,6 +74,9 @@
 
 // STEP 1:
 
+/* here you need to specify the parameter for the target function */
+static void *(*o_function)(u8 *buf, int len);
+
 /* use stdin (1) or a file on the commandline (0) */
 static u32 use_stdin = 1;
 
@@ -395,7 +399,7 @@ static void __afl_map_shm(void) {
 }
 
 /* Fork server logic. */
-static void __afl_start_forkserver(void) {
+inline static void __afl_start_forkserver(void) {
 
   u8  tmp[4] = {0, 0, 0, 0};
   u32 status = 0;
@@ -411,7 +415,7 @@ static void __afl_start_forkserver(void) {
 
 }
 
-static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
+inline static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
 
   s32 status;
 
@@ -437,7 +441,7 @@ static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
 
 }
 
-static void __afl_end_testcase(int status) {
+inline static void __afl_end_testcase(int status) {
 
   if (write(FORKSRV_FD + 1, &status, 4) != 4) do_exit = 1;
   // fprintf(stderr, "write2 %d\n", do_exit);
@@ -667,12 +671,11 @@ static void sigtrap_handler(int signum, siginfo_t *si, void *context) {
 
 }
 
-/* here you need to specify the parameter for the target function */
-static void *(*o_function)(u8 *buf, int len);
-
 /* the MAIN function */
 int main(int argc, char *argv[]) {
 
+  (void)personality(ADDR_NO_RANDOMIZE);  // disable ASLR
+
   pid = getpid();
   if (getenv("AFL_DEBUG")) debug = 1;
 
@@ -706,6 +709,9 @@ int main(int argc, char *argv[]) {
 
   while (1) {
 
+    // instead of fork() we could also use the snapshot lkm or do our own mini
+    // snapshot feature like in https://github.com/marcinguy/fuzzer
+    // -> snapshot.c
     if ((pid = fork()) == -1) PFATAL("fork failed");
 
     if (pid) {
@@ -738,7 +744,11 @@ int main(int argc, char *argv[]) {
 
 }
 
-static void fuzz() {
+#ifndef _DEBUG
+inline
+#endif
+    static void
+    fuzz() {
 
   // STEP 3: call the function to fuzz, also the functions you might
   //         need to call to prepare the function and - important! -
diff --git a/examples/custom_mutators/post_library_gif.so.c b/examples/custom_mutators/post_library_gif.so.c
index 9b76ead5..2d72400c 100644
--- a/examples/custom_mutators/post_library_gif.so.c
+++ b/examples/custom_mutators/post_library_gif.so.c
@@ -83,7 +83,7 @@ typedef struct post_state {
 
 } post_state_t;
 
-void *afl afl_custom_init(void *afl) {
+void *afl_custom_init(void *afl) {
 
   post_state_t *state = malloc(sizeof(post_state_t));
   if (!state) {
diff --git a/examples/defork/Makefile b/examples/defork/Makefile
new file mode 100644
index 00000000..e8240dba
--- /dev/null
+++ b/examples/defork/Makefile
@@ -0,0 +1,64 @@
+#
+# american fuzzy lop++ - defork
+# ----------------------------------
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+
+.PHONY: all install clean
+
+PREFIX     ?= /usr/local
+BIN_PATH    = $(PREFIX)/bin
+HELPER_PATH = $(PREFIX)/lib/afl
+
+CFLAGS = -fPIC -Wall -Wextra
+LDFLAGS = -shared
+
+UNAME_SAYS_LINUX=$(shell uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?)
+UNAME_SAYS_LINUX:sh=uname | grep -E '^Linux|^GNU' >/dev/null; echo $$?
+
+_LDFLAGS_ADD=$(UNAME_SAYS_LINUX:1=)
+LDFLAGS_ADD=$(_LDFLAGS_ADD:0=-ldl)
+LDFLAGS  += $(LDFLAGS_ADD)
+
+# on gcc for arm there is no -m32, but -mbe32
+M32FLAG = -m32
+M64FLAG = -m64
+
+CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep -q gcc; echo $$?)
+CC_IS_GCC:sh=$(CC) --version 2>/dev/null | grep -q gcc; echo $$?
+CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?)
+CC_IS_ARMCOMPILER:sh=$(CC) -v 2>&1 >/dev/null | grep -q arm; echo $$?
+
+_M32FLAG=$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)
+__M32FLAG=$(_M32FLAG:00=-mbe32)
+___M32FLAG=$(__M32FLAG:$(CC_IS_GCC)$(CC_IS_ARMCOMPILER)=-m32)
+M32FLAG=$(___M32FLAG)
+#ifeq "$(findstring clang, $(shell $(CC) --version 2>/dev/null))" ""
+# ifneq (,$(findstring arm, "$(shell $(CC) -v 2>&1 >/dev/null)"))
+#  M32FLAG = -mbe32
+# endif
+#endif
+
+all: defork32.so defork64.so
+
+defork32.so: defork.c
+	-@$(CC) $(M32FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "defork32 build failure (that's fine)"
+
+defork64.so: defork.c
+	-@$(CC) $(M64FLAG) $(CFLAGS) $^ $(LDFLAGS) -o $@ 2>/dev/null || echo "defork64 build failure (that's fine)"
+
+install: defork32.so defork64.so
+	install -d -m 755 $(DESTDIR)$(HELPER_PATH)/
+	if [ -f defork32.so ]; then set -e; install -m 755 defork32.so $(DESTDIR)$(HELPER_PATH)/; fi
+	if [ -f defork64.so ]; then set -e; install -m 755 defork64.so $(DESTDIR)$(HELPER_PATH)/; fi
+
+target:
+	../../afl-clang forking_target.c -o forking_target -Wall -Wextra -Werror
+
+clean:
+	rm -f defork32.so defork64.so forking_target
diff --git a/examples/defork/README.md b/examples/defork/README.md
new file mode 100644
index 00000000..7e950323
--- /dev/null
+++ b/examples/defork/README.md
@@ -0,0 +1,11 @@
+# defork
+
+when the target forks, this breaks all normal fuzzing runs.
+Sometimes, though, it is enough to just run the child process.
+If this is the case, then this LD_PRELOAD library will always return 0 on fork,
+the target will belive it is running as the child, post-fork.
+
+This is defork.c from the amazing preeny project
+https://github.com/zardus/preeny
+
+It is altered for afl++ to work with its fork-server: the initial fork will go through, the second fork will be blocked.
diff --git a/examples/defork/defork.c b/examples/defork/defork.c
new file mode 100644
index 00000000..f71d1124
--- /dev/null
+++ b/examples/defork/defork.c
@@ -0,0 +1,50 @@
+#define __GNU_SOURCE
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+#include "../../include/config.h"
+
+/* we want to fork once (for the afl++ forkserver),
+   then immediately return as child on subsequent forks. */
+static bool forked = 0;
+
+pid_t (*original_fork)(void);
+
+/* In case we are not running in afl, we use a dummy original_fork */
+static pid_t nop(void) {
+
+  return 0;
+
+}
+
+__attribute__((constructor)) void preeny_fork_orig() {
+
+  if (getenv(SHM_ENV_VAR)) {
+
+    printf("defork: running in AFL++. Allowing forkserver.\n");
+    original_fork = dlsym(RTLD_NEXT, "socket");
+
+  } else {
+
+    printf("defork: no AFL++ detected. Disabling fork from the start.\n");
+    original_fork = &nop;
+
+  }
+
+}
+
+pid_t fork(void) {
+
+  /* If we forked before, or if we're in the child (pid==0),
+    we don't want to fork anymore, else, we are still in the forkserver.
+    The forkserver parent needs to fork infinite times, each child should never
+    fork again. This can be written without branches and I hate myself for it.
+  */
+  pid_t ret = !forked && original_fork();
+  forked = !ret;
+  return ret;
+
+}
+
diff --git a/examples/defork/forking_target b/examples/defork/forking_target
new file mode 100755
index 00000000..0f7a04fc
--- /dev/null
+++ b/examples/defork/forking_target
Binary files differdiff --git a/examples/defork/forking_target.c b/examples/defork/forking_target.c
new file mode 100644
index 00000000..98f6365a
--- /dev/null
+++ b/examples/defork/forking_target.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+/* This is an example target for defork.c - fuzz using
+```
+mkdir in; echo a > ./in/a
+AFL_PRELOAD=./defork64.so ../../afl-fuzz -i in -o out -- ./forking_target @@
+```
+*/
+
+int main(int argc, char **argv) {
+
+  if (argc < 2) {
+
+    printf("Example tool to test defork.\nUsage ./forking_target <input>\n");
+    return -1;
+
+  }
+
+  pid_t pid = fork();
+  if (pid == 0) {
+
+    printf("We're in the child.\n");
+    FILE *f = fopen(argv[1], "r");
+    char  buf[4096];
+    fread(buf, 1, 4096, f);
+    uint32_t offset = buf[100] + (buf[101] << 8);
+    char     test_val = buf[offset];
+    return test_val < 100;
+
+  } else if (pid < 0) {
+
+    perror("fork");
+    return -1;
+
+  } else {
+
+    printf("We are in the parent - defork didn't work! :( (pid=%d)\n",
+           (int)pid);
+
+  }
+
+  return 0;
+
+}
+
diff --git a/gcc_plugin/GNUmakefile b/gcc_plugin/GNUmakefile
index bf5c53e0..4a4f0dcd 100644
--- a/gcc_plugin/GNUmakefile
+++ b/gcc_plugin/GNUmakefile
@@ -70,9 +70,16 @@ ifeq "$(TEST_MMAP)" "1"
 endif
 
 ifneq "$(shell uname -s)" "Haiku"
-	LDFLAGS += -lrt
+  	LDFLAGS += -lrt
+else
+	CFLAGS_SAFE += -DUSEMMAP=1
+endif
+
+ifeq "$(shell uname -s)" "SunOS"
+  	PLUGIN_FLAGS += -I/usr/include/gmp
 endif
 
+
 PROGS        = ../afl-gcc-fast ../afl-gcc-pass.so ../afl-gcc-rt.o
 
 
diff --git a/gcc_plugin/afl-gcc-fast.c b/gcc_plugin/afl-gcc-fast.c
index af0beca7..b1bacfbd 100644
--- a/gcc_plugin/afl-gcc-fast.c
+++ b/gcc_plugin/afl-gcc-fast.c
@@ -379,7 +379,7 @@ int main(int argc, char **argv, char **envp) {
 
     u32 map_size = atoi(ptr);
     if (map_size != MAP_SIZE)
-      FATAL("AFL_MAP_SIZE is not supported by afl-gcc-fast");
+      WARNF("AFL_MAP_SIZE is not supported by afl-gcc-fast");
 
   }
 
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index c9f84c61..c0c4cfd5 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -347,6 +347,13 @@ struct afl_pass_stat {
 
 };
 
+struct foreign_sync {
+
+  u8 *   dir;
+  time_t ctime;
+
+};
+
 typedef struct afl_state {
 
   /* Position of this state in the global states list */
@@ -574,6 +581,15 @@ typedef struct afl_state {
   u8 describe_op_buf_256[256]; /* describe_op will use this to return a string
                                   up to 256 */
 
+  unsigned long long int last_avg_exec_update;
+  u32                    last_avg_execs;
+  float                  last_avg_execs_saved;
+
+/* foreign sync */
+#define FOREIGN_SYNCS_MAX 32
+  u8                  foreign_sync_cnt;
+  struct foreign_sync foreign_syncs[FOREIGN_SYNCS_MAX];
+
 #ifdef _AFL_DOCUMENT_MUTATIONS
   u8  do_document;
   u32 document_counter;
@@ -937,6 +953,7 @@ void   fix_up_banner(afl_state_t *, u8 *);
 void   check_if_tty(afl_state_t *);
 void   setup_signal_handlers(void);
 void   save_cmdline(afl_state_t *, u32, char **);
+void   read_foreign_testcases(afl_state_t *, int);
 
 /* CmpLog */
 
diff --git a/include/config.h b/include/config.h
index e8f52f45..4503c3e9 100644
--- a/include/config.h
+++ b/include/config.h
@@ -28,7 +28,7 @@
 /* Version string: */
 
 // c = release, d = volatile github dev, e = experimental branch
-#define VERSION "++2.66c"
+#define VERSION "++2.66d"
 
 /******************************************************
  *                                                    *
@@ -380,6 +380,10 @@
 
 #define CMPLOG_SHM_ENV_VAR "__AFL_CMPLOG_SHM_ID"
 
+/* CPU Affinity lockfile env var */
+
+#define CPU_AFFINITY_ENV_VAR "__AFL_LOCKFILE"
+
 /* Uncomment this to use inferior block-coverage-based instrumentation. Note
    that you need to recompile the target binary for this to have any effect: */
 
diff --git a/libdislocator/libdislocator.so.c b/libdislocator/libdislocator.so.c
index 7a70fd15..2324e390 100644
--- a/libdislocator/libdislocator.so.c
+++ b/libdislocator/libdislocator.so.c
@@ -166,7 +166,7 @@ static u32          alloc_canary;
 
 static void *__dislocator_alloc(size_t len) {
 
-  u8 *   ret;
+  u8 *   ret, *base;
   size_t tlen;
   int    flags, fd, sp;
 
@@ -189,6 +189,7 @@ static void *__dislocator_alloc(size_t len) {
   /* We will also store buffer length and a canary below the actual buffer, so
      let's add 8 bytes for that. */
 
+  base = NULL;
   tlen = (1 + PG_COUNT(rlen + 8)) * PAGE_SIZE;
   flags = MAP_PRIVATE | MAP_ANONYMOUS;
   fd = -1;
@@ -201,12 +202,20 @@ static void *__dislocator_alloc(size_t len) {
   if (sp) flags |= MAP_HUGETLB;
   #elif defined(__FreeBSD__)
   if (sp) flags |= MAP_ALIGNED_SUPER;
+  #elif defined(__sun)
+  if (sp) {
+
+    base = (void *)(caddr_t)(1 << 21);
+    flags |= MAP_ALIGN;
+
+  }
+
   #endif
 #else
   (void)sp;
 #endif
 
-  ret = (u8 *)mmap(NULL, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
+  ret = (u8 *)mmap(base, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
 #if defined(USEHUGEPAGE)
   /* We try one more time with regular call */
   if (ret == MAP_FAILED) {
@@ -217,6 +226,8 @@ static void *__dislocator_alloc(size_t len) {
     flags &= -MAP_HUGETLB;
   #elif defined(__FreeBSD__)
     flags &= -MAP_ALIGNED_SUPER;
+  #elif defined(__sun)
+    flags &= -MAP_ALIGN;
   #endif
     ret = (u8 *)mmap(NULL, tlen, PROT_READ | PROT_WRITE, flags, fd, 0);
 
diff --git a/libtokencap/Makefile b/libtokencap/Makefile
index 63b87bb0..8bdfa5ac 100644
--- a/libtokencap/Makefile
+++ b/libtokencap/Makefile
@@ -35,13 +35,14 @@ _UNIQ=_QINU_
  _____OS_DL =  $(____OS_DL:$(_UNIQ)$(UNAME_S)=)
 ______OS_DL = $(_____OS_DL:$(_UNIQ)="-ldl")
 
-    _OS_TARGET = $(____OS_DL:$(_UNIQ)FreeBSD=$(_UNIQ))
-   __OS_TARGET =    $(_OS_TARGET:$(_UNIQ)OpenBSD=$(_UNIQ))
-  ___OS_TARGET =   $(__OS_TARGET:$(_UNIQ)NetBSD=$(_UNIQ))
- ____OS_TARGET =  $(___OS_TARGET:$(_UNIQ)Haiku=$(_UNIQ))
-_____OS_TARGET = $(___OS_TARGET:$(_UNIQ)$(UNAME_S)=)
+     _OS_TARGET = $(____OS_DL:$(_UNIQ)FreeBSD=$(_UNIQ))
+    __OS_TARGET =     $(_OS_TARGET:$(_UNIQ)OpenBSD=$(_UNIQ))
+   ___OS_TARGET =    $(__OS_TARGET:$(_UNIQ)NetBSD=$(_UNIQ))
+  ____OS_TARGET =   $(___OS_TARGET:$(_UNIQ)Haiku=$(_UNIQ))
+ _____OS_TARGET =  $(____OS_TARGET:$(_UNIQ)SunOS=$(_UNIQ))
+______OS_TARGET =  $(____OS_TARGET:$(_UNIQ)$(UNAME_S)=)
 
-TARGETS       = $(____OS_TARGET:$(_UNIQ)=libtokencap.so)
+TARGETS       =  $(_____OS_TARGET:$(_UNIQ)=libtokencap.so)
 
 LDFLAGS     += $(______OS_DL)
 
diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c
index 600d2a5d..21bac082 100644
--- a/libtokencap/libtokencap.so.c
+++ b/libtokencap/libtokencap.so.c
@@ -35,7 +35,7 @@
 
 #if !defined __linux__ && !defined __APPLE__ && !defined __FreeBSD__ &&      \
     !defined __OpenBSD__ && !defined __NetBSD__ && !defined __DragonFly__ && \
-    !defined(__HAIKU__)
+    !defined(__HAIKU__) && !defined(__sun)
   #error "Sorry, this library is unsupported in this platform for now!"
 #endif /* !__linux__ && !__APPLE__ && ! __FreeBSD__ && ! __OpenBSD__ && \
           !__NetBSD__*/
@@ -52,6 +52,10 @@
   #include <sys/mman.h>
 #elif defined __HAIKU__
   #include <kernel/image.h>
+#elif defined __sun
+  /* For map addresses the old struct is enough */
+  #include <sys/procfs.h>
+  #include <limits.h>
 #endif
 
 #include <dlfcn.h>
@@ -237,6 +241,8 @@ static void __tokencap_load_mappings(void) {
   image_info ii;
   int32_t    group = 0;
 
+  __tokencap_ro_loaded = 1;
+
   while (get_next_image_info(0, &group, &ii) == B_OK) {
 
     __tokencap_ro[__tokencap_ro_cnt].st = ii.text;
@@ -246,6 +252,38 @@ static void __tokencap_load_mappings(void) {
 
   }
 
+#elif defined __sun
+  prmap_t *c, *map;
+  char     path[PATH_MAX];
+  ssize_t  r;
+  size_t   hint;
+  int      fd;
+
+  snprintf(path, sizeof(path), "/proc/%ld/map", getpid());
+  fd = open(path, O_RDONLY);
+  hint = (1 << 20);
+  map = malloc(hint);
+
+  __tokencap_ro_loaded = 1;
+
+  for (; (r = pread(fd, map, hint, 0)) == hint;) {
+
+    hint <<= 1;
+    map = realloc(map, hint);
+
+  }
+
+  for (c = map; r > 0; c++, r -= sizeof(prmap_t)) {
+
+    __tokencap_ro[__tokencap_ro_cnt].st = c->pr_vaddr;
+    __tokencap_ro[__tokencap_ro_cnt].en = c->pr_vaddr + c->pr_size;
+
+    if (++__tokencap_ro_cnt == MAX_MAPPINGS) break;
+
+  }
+
+  free(map);
+  close(fd);
 #endif
 
 }
diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile
index b5d026ef..443322d7 100644
--- a/llvm_mode/GNUmakefile
+++ b/llvm_mode/GNUmakefile
@@ -32,15 +32,16 @@ ifeq "$(shell uname)" "OpenBSD"
   LLVM_CONFIG ?= $(BIN_PATH)/llvm-config
   HAS_OPT = $(shell test -x $(BIN_PATH)/opt && echo 0 || echo 1)
   ifeq "$(HAS_OPT)" "1"
-    $(error llvm_mode needs a complete llvm installation (versions 3.4 up to 11) -> e.g. "pkg_add llvm-7.0.1p9")
+    $(error llvm_mode needs a complete llvm installation (versions 3.4 up to 12) -> e.g. "pkg_add llvm-7.0.1p9")
   endif
 else
   LLVM_CONFIG ?= llvm-config
 endif
 
 LLVMVER  = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/git//' )
-LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^1[2-9]' && echo 1 || echo 0 )
+LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^3\.[0-3]|^1[3-9]' && echo 1 || echo 0 )
 LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[0-9]' && echo 1 || echo 0 )
+LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | egrep -q '^1[1-9]' && echo 1 || echo 0 )
 LLVM_MAJOR = $(shell $(LLVM_CONFIG) --version 2>/dev/null | sed 's/\..*//')
 LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
 LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
@@ -53,7 +54,7 @@ ifeq "$(LLVMVER)" ""
 endif
 
 ifeq "$(LLVM_UNSUPPORTED)" "1"
-  $(warning llvm_mode only supports llvm versions 3.4 up to 11)
+  $(warning llvm_mode only supports llvm versions 3.4 up to 12)
 endif
 
 ifeq "$(LLVM_MAJOR)" "9"
@@ -65,8 +66,8 @@ ifeq "$(LLVM_NEW_API)" "1"
   LLVM_STDCXX = c++14
 endif
 
-ifeq "$(LLVM_MAJOR)" "11"
-  $(info [+] llvm_mode detected llvm 11, enabling afl-clang-lto LTO implementation)
+ifeq "$(LLVM_HAVE_LTO)" "1"
+  $(info [+] llvm_mode detected llvm 11+, enabling afl-clang-lto LTO implementation)
   LLVM_LTO = 1
   #TEST_MMAP = 1
 endif
diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md
index 4641fa89..d54d4ee0 100644
--- a/llvm_mode/README.lto.md
+++ b/llvm_mode/README.lto.md
@@ -2,7 +2,7 @@
 
 ## TLDR;
 
-This version requires a current llvm 11 compiled from the github master.
+This version requires a current llvm 11+ compiled from the github master.
 
 1. Use afl-clang-lto/afl-clang-lto++ because it is faster and gives better
    coverage than anything else that is out there in the AFL world
@@ -10,7 +10,7 @@ This version requires a current llvm 11 compiled from the github master.
 2. You can use it together with llvm_mode: laf-intel and the instrument file listing
    features and can be combined with cmplog/Redqueen
 
-3. It only works with llvm 11 (current github master state)
+3. It only works with llvm 11+
 
 4. AUTODICTIONARY feature! see below
 
@@ -61,9 +61,9 @@ AUTODICTIONARY: 11 strings found
 [+] Instrumented 12071 locations with no collisions (on average 1046 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode).
 ```
 
-## Getting llvm 11
+## Getting llvm 11+
 
-### Installing llvm 11 from the llvm repository
+### Installing llvm from the llvm repository (version 11)
 
 Installing the llvm snapshot builds is easy and mostly painless:
 
@@ -83,7 +83,7 @@ apt-get install -y clang-11 clang-tools-11 libc++1-11 libc++-11-dev \
     libomp5-11 lld-11 lldb-11 llvm-11 llvm-11-dev llvm-11-runtime llvm-11-tools
 ```
 
-### Building llvm 11 yourself
+### Building llvm yourself (version 12)
 
 Building llvm from github takes quite some long time and is not painless:
 ```
@@ -125,10 +125,9 @@ NOTE: some targets also need to set the linker, try both `afl-clang-lto` and
 
 ## AUTODICTIONARY feature
 
-Setting `AFL_LLVM_LTO_AUTODICTIONARY` will generate a dictionary in the
-target binary based on string compare and memory compare functions.
-afl-fuzz will automatically get these transmitted when starting to fuzz.
-This improves coverage on a lot of targets.
+While compiling, automatically a dictionary based on string comparisons is
+generated put into the target binary. This dictionary is transfered to afl-fuzz
+on start. This improves coverage statistically by 5-10% :)
 
 ## Fixed memory map
 
@@ -147,6 +146,8 @@ Some targets are difficult because the configure script does unusual stuff that
 is unexpected for afl. See the next chapter `Potential issues` how to solve
 these.
 
+### Example: ffmpeg
+
 An example of a hard to solve target is ffmpeg. Here is how to successfully
 instrument it:
 
@@ -186,6 +187,31 @@ instrument it:
 
 4. Then type make, wait for a long time and you are done :)
 
+### Example: WebKit jsc
+
+Building jsc is difficult as the build script has bugs.
+
+1. checkout Webkit: 
+```
+svn checkout https://svn.webkit.org/repository/webkit/trunk WebKit
+cd WebKit
+```
+
+2. Fix the build environment:
+```
+mkdir -p WebKitBuild/Release
+cd WebKitBuild/Release
+ln -s ../../../../../usr/bin/llvm-ar-12 llvm-ar-12
+ln -s ../../../../../usr/bin/llvm-ranlib-12 llvm-ranlib-12
+cd ../..
+```
+
+3. Build :)
+
+```
+Tools/Scripts/build-jsc --jsc-only --cli --cmakeargs="-DCMAKE_AR='llvm-ar-12' -DCMAKE_RANLIB='llvm-ranlib-12' -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_CC_FLAGS='-O3 -lrt' -DCMAKE_CXX_FLAGS='-O3 -lrt' -DIMPORTED_LOCATION='/lib/x86_64-linux-gnu/' -DCMAKE_CC=afl-clang-lto -DCMAKE_CXX=afl-clang-lto++ -DENABLE_STATIC_JSC=ON"
+```
+
 ## Potential issues
 
 ### compiling libraries fails
@@ -220,17 +246,17 @@ AS=llvm-as  ...
 afl-clang-lto is still work in progress.
 
 Known issues:
-  * Anything that llvm 11 cannot compile, afl-clang-lto can not compile either - obviously
+  * Anything that llvm 11+ cannot compile, afl-clang-lto can not compile either - obviously
   * Anything that does not compile with LTO, afl-clang-lto can not compile either - obviously
 
-Hence if building a target with afl-clang-lto fails try to build it with llvm11
-and LTO enabled (`CC=clang-11` `CXX=clang++-11` `CFLAGS=-flto=full` and
+Hence if building a target with afl-clang-lto fails try to build it with llvm12
+and LTO enabled (`CC=clang-12` `CXX=clang++-12` `CFLAGS=-flto=full` and
 `CXXFLAGS=-flto=full`).
 
 If this succeeeds then there is an issue with afl-clang-lto. Please report at
 [https://github.com/AFLplusplus/AFLplusplus/issues/226](https://github.com/AFLplusplus/AFLplusplus/issues/226)
 
-Even some targets where clang-11 fails can be build if the fail is just in
+Even some targets where clang-12 fails can be build if the fail is just in
 `./configure`, see `Solving difficult targets` above.
 
 ### Target crashes immediately
@@ -270,7 +296,7 @@ Still more problems came up though as this only works without bugs from
 llvm 9 onwards, and with high optimization the link optimization ruins
 the instrumented control flow graph.
 
-This is all now fixed with llvm 11. The llvm's own linker is now able to
+This is all now fixed with llvm 11+. The llvm's own linker is now able to
 load passes and this bypasses all problems we had.
 
 Happy end :)
diff --git a/llvm_mode/README.md b/llvm_mode/README.md
index e2e22751..22088dfd 100644
--- a/llvm_mode/README.md
+++ b/llvm_mode/README.md
@@ -6,7 +6,7 @@
 
 ## 1) Introduction
 
-! llvm_mode works with llvm versions 3.4 up to 11 !
+! llvm_mode works with llvm versions 3.4 up to 12 !
 
 The code in this directory allows you to instrument programs for AFL using
 true compiler-level instrumentation, instead of the more crude
@@ -183,4 +183,4 @@ AFL_LLVM_INSTRUMENT=PCGUARD  make
 ```
 
 Note that this us currently the default, as it is the best mode.
-If you have llvm 11 and compiled afl-clang-lto - this is the only better mode.
+If you have llvm 11+ and compiled afl-clang-lto - this is the only better mode.
diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c
index f1b03682..4d01e740 100644
--- a/llvm_mode/afl-clang-fast.c
+++ b/llvm_mode/afl-clang-fast.c
@@ -311,12 +311,15 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
     cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", AFL_REAL_LD);
     cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
-    if (instrument_mode == INSTRUMENT_CFG)
-      cc_params[cc_par_cnt++] =
-          alloc_printf("-Wl,-mllvm=-load=%s/afl-llvm-lto-instrim.so", obj_path);
-    else
-      cc_params[cc_par_cnt++] = alloc_printf(
-          "-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path);
+    /*
+        The current LTO instrim mode is not good, so we disable it
+        if (instrument_mode == INSTRUMENT_CFG)
+          cc_params[cc_par_cnt++] =
+              alloc_printf("-Wl,-mllvm=-load=%s/afl-llvm-lto-instrim.so",
+       obj_path); else
+    */
+    cc_params[cc_par_cnt++] = alloc_printf(
+        "-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path);
     cc_params[cc_par_cnt++] = lto_flag;
 
   } else {
@@ -379,6 +382,8 @@ static void edit_params(u32 argc, char **argv, char **envp) {
     if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined"))
       continue;
 
+    if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue;
+
     cc_params[cc_par_cnt++] = cur;
 
   }
@@ -660,7 +665,7 @@ int main(int argc, char **argv, char **envp) {
       }
 
       if (strncasecmp(ptr, "pc-guard", strlen("pc-guard")) == 0 ||
-          strncasecmp(ptr, "pcguard", strlen("pcgard")) == 0) {
+          strncasecmp(ptr, "pcguard", strlen("pcguard")) == 0) {
 
         if (!instrument_mode || instrument_mode == INSTRUMENT_PCGUARD)
           instrument_mode = INSTRUMENT_PCGUARD;
@@ -763,9 +768,19 @@ int main(int argc, char **argv, char **envp) {
 #if LLVM_VERSION_MAJOR <= 6
     instrument_mode = INSTRUMENT_AFL;
 #else
-    if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST"))
+    if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST")) {
+
       instrument_mode = INSTRUMENT_AFL;
-    else
+      WARNF(
+          "switching to classic instrumentation because "
+          "AFL_LLVM_INSTRUMENT_FILE does not work with PCGUARD. Use "
+          "-fsanitize-coverage-allowlist=allowlist.txt if you want to use "
+          "PCGUARD. See "
+          "https://clang.llvm.org/docs/"
+          "SanitizerCoverage.html#partially-disabling-instrumentation");
+
+    } else
+
       instrument_mode = INSTRUMENT_PCGUARD;
 #endif
 
@@ -813,9 +828,12 @@ int main(int argc, char **argv, char **envp) {
 
   if (instrument_mode == INSTRUMENT_PCGUARD &&
       (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST")))
-    WARNF(
+    FATAL(
         "Instrumentation type PCGUARD does not support "
-        "AFL_LLVM_INSTRUMENT_FILE!");
+        "AFL_LLVM_INSTRUMENT_FILE! Use "
+        "-fsanitize-coverage-allowlist=allowlist.txt instead, see "
+        "https://clang.llvm.org/docs/"
+        "SanitizerCoverage.html#partially-disabling-instrumentation");
 
   if (argc < 2 || strcmp(argv[1], "-h") == 0) {
 
@@ -939,7 +957,7 @@ int main(int argc, char **argv, char **envp) {
 
     u32 map_size = atoi(ptr2);
     if (map_size != MAP_SIZE)
-      FATAL("AFL_MAP_SIZE is not supported by afl-clang-fast");
+      WARNF("AFL_MAP_SIZE is not supported by afl-clang-fast");
 
   }
 
diff --git a/llvm_mode/afl-llvm-lto-instrim.so.cc b/llvm_mode/afl-llvm-lto-instrim.so.cc
index ca2b5886..880963ac 100644
--- a/llvm_mode/afl-llvm-lto-instrim.so.cc
+++ b/llvm_mode/afl-llvm-lto-instrim.so.cc
@@ -73,7 +73,7 @@ struct InsTrimLTO : public ModulePass {
  protected:
   uint32_t function_minimum_size = 1;
   char *   skip_nozero = NULL;
-  int      afl_global_id = 1, debug = 0, autodictionary = 0;
+  int      afl_global_id = 1, debug = 0, autodictionary = 1;
   uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0;
   uint64_t map_addr = 0x10000;
 
@@ -127,10 +127,6 @@ struct InsTrimLTO : public ModulePass {
 
     /* Process environment variables */
 
-    if (getenv("AFL_LLVM_AUTODICTIONARY") ||
-        getenv("AFL_LLVM_LTO_AUTODICTIONARY"))
-      autodictionary = 1;
-
     if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0;
 
     if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) {
diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc
index af2db3ff..3c1d3565 100644
--- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc
+++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc
@@ -86,7 +86,7 @@ class AFLLTOPass : public ModulePass {
   bool runOnModule(Module &M) override;
 
  protected:
-  int      afl_global_id = 1, debug = 0, autodictionary = 0;
+  int      afl_global_id = 1, debug = 0, autodictionary = 1;
   uint32_t function_minimum_size = 1;
   uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0, total_instr = 0;
   uint64_t map_addr = 0x10000;
@@ -120,10 +120,6 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
     be_quiet = 1;
 
-  if (getenv("AFL_LLVM_AUTODICTIONARY") ||
-      getenv("AFL_LLVM_LTO_AUTODICTIONARY"))
-    autodictionary = 1;
-
   if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0;
 
   if (getenv("AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK") ||
diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c
index f81d13ee..a509a9f0 100644
--- a/llvm_mode/afl-llvm-rt.o.c
+++ b/llvm_mode/afl-llvm-rt.o.c
@@ -53,7 +53,11 @@
 #define CONST_PRIO 5
 
 #ifndef MAP_FIXED_NOREPLACE
-  #define MAP_FIXED_NOREPLACE MAP_FIXED
+  #ifdef MAP_EXCL
+    #define MAP_FIXED_NOREPLACE MAP_EXCL | MAP_FIXED
+  #else
+    #define MAP_FIXED_NOREPLACE MAP_FIXED
+  #endif
 #endif
 
 #include <sys/mman.h>
@@ -510,6 +514,8 @@ static void __afl_start_snapshots(void) {
 
       if (!child_pid) {
 
+        (void)nice(-20);
+
         signal(SIGCHLD, old_sigchld_handler);
 
         close(FORKSRV_FD);
@@ -713,6 +719,8 @@ static void __afl_start_forkserver(void) {
 
       if (!child_pid) {
 
+        (void)nice(-20);
+
         signal(SIGCHLD, old_sigchld_handler);
 
         close(FORKSRV_FD);
diff --git a/llvm_mode/compare-transform-pass.so.cc b/llvm_mode/compare-transform-pass.so.cc
index 2d1ab1cc..2f165ea6 100644
--- a/llvm_mode/compare-transform-pass.so.cc
+++ b/llvm_mode/compare-transform-pass.so.cc
@@ -474,8 +474,8 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
       if (cur_lenchk_bb) {
 
         IRBuilder<> cur_lenchk_IRB(&*(cur_lenchk_bb->getFirstInsertionPt()));
-        Value *     icmp = cur_lenchk_IRB.CreateICmpEQ(sizedValue,
-                                                  ConstantInt::get(Int64Ty, i));
+        Value *     icmp = cur_lenchk_IRB.CreateICmpEQ(
+            sizedValue, ConstantInt::get(sizedValue->getType(), i));
         cur_lenchk_IRB.CreateCondBr(icmp, end_bb, cur_cmp_bb);
         cur_lenchk_bb->getTerminator()->eraseFromParent();
 
diff --git a/llvm_mode/split-compares-pass.so.cc b/llvm_mode/split-compares-pass.so.cc
index 651fa5b4..55128ca2 100644
--- a/llvm_mode/split-compares-pass.so.cc
+++ b/llvm_mode/split-compares-pass.so.cc
@@ -80,6 +80,7 @@ class SplitComparesTransform : public ModulePass {
   size_t splitIntCompares(Module &M, unsigned bitw);
   size_t splitFPCompares(Module &M);
   bool   simplifyCompares(Module &M);
+  bool   simplifyFPCompares(Module &M);
   bool   simplifyIntSignedness(Module &M);
   size_t nextPowerOfTwo(size_t in);
 
@@ -89,12 +90,11 @@ class SplitComparesTransform : public ModulePass {
 
 char SplitComparesTransform::ID = 0;
 
-/* This function splits ICMP instructions with xGE or xLE predicates into two
- * ICMP instructions with predicate xGT or xLT and EQ */
-bool SplitComparesTransform::simplifyCompares(Module &M) {
+/* This function splits FCMP instructions with xGE or xLE predicates into two
+ * FCMP instructions with predicate xGT or xLT and EQ */
+bool SplitComparesTransform::simplifyFPCompares(Module &M) {
 
   LLVMContext &              C = M.getContext();
-  std::vector<Instruction *> icomps;
   std::vector<Instruction *> fcomps;
   IntegerType *              Int1Ty = IntegerType::getInt1Ty(C);
 
@@ -112,24 +112,6 @@ bool SplitComparesTransform::simplifyCompares(Module &M) {
 
         if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
 
-          if (selectcmpInst->getPredicate() == CmpInst::ICMP_UGE ||
-              selectcmpInst->getPredicate() == CmpInst::ICMP_SGE ||
-              selectcmpInst->getPredicate() == CmpInst::ICMP_ULE ||
-              selectcmpInst->getPredicate() == CmpInst::ICMP_SLE) {
-
-            auto op0 = selectcmpInst->getOperand(0);
-            auto op1 = selectcmpInst->getOperand(1);
-
-            IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
-            IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType());
-
-            /* this is probably not needed but we do it anyway */
-            if (!intTyOp0 || !intTyOp1) { continue; }
-
-            icomps.push_back(selectcmpInst);
-
-          }
-
           if (enableFPSplit &&
               (selectcmpInst->getPredicate() == CmpInst::FCMP_OGE ||
                selectcmpInst->getPredicate() == CmpInst::FCMP_UGE ||
@@ -159,105 +141,159 @@ bool SplitComparesTransform::simplifyCompares(Module &M) {
 
   }
 
-  if (!icomps.size() && !fcomps.size()) { return false; }
+  if (!fcomps.size()) { return false; }
 
-  for (auto &IcmpInst : icomps) {
+  /* transform for floating point */
+  for (auto &FcmpInst : fcomps) {
 
-    BasicBlock *bb = IcmpInst->getParent();
+    BasicBlock *bb = FcmpInst->getParent();
 
-    auto op0 = IcmpInst->getOperand(0);
-    auto op1 = IcmpInst->getOperand(1);
+    auto op0 = FcmpInst->getOperand(0);
+    auto op1 = FcmpInst->getOperand(1);
 
     /* find out what the new predicate is going to be */
-    auto               pred = dyn_cast<CmpInst>(IcmpInst)->getPredicate();
+    auto               pred = dyn_cast<CmpInst>(FcmpInst)->getPredicate();
     CmpInst::Predicate new_pred;
     switch (pred) {
 
-      case CmpInst::ICMP_UGE:
-        new_pred = CmpInst::ICMP_UGT;
+      case CmpInst::FCMP_UGE:
+        new_pred = CmpInst::FCMP_UGT;
         break;
-      case CmpInst::ICMP_SGE:
-        new_pred = CmpInst::ICMP_SGT;
+      case CmpInst::FCMP_OGE:
+        new_pred = CmpInst::FCMP_OGT;
         break;
-      case CmpInst::ICMP_ULE:
-        new_pred = CmpInst::ICMP_ULT;
+      case CmpInst::FCMP_ULE:
+        new_pred = CmpInst::FCMP_ULT;
         break;
-      case CmpInst::ICMP_SLE:
-        new_pred = CmpInst::ICMP_SLT;
+      case CmpInst::FCMP_OLE:
+        new_pred = CmpInst::FCMP_OLT;
         break;
       default:  // keep the compiler happy
         continue;
 
     }
 
-    /* split before the icmp instruction */
-    BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst));
+    /* split before the fcmp instruction */
+    BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(FcmpInst));
 
     /* the old bb now contains a unconditional jump to the new one (end_bb)
      * we need to delete it later */
 
-    /* create the ICMP instruction with new_pred and add it to the old basic
-     * block bb it is now at the position where the old IcmpInst was */
-    Instruction *icmp_np;
-    icmp_np = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1);
+    /* create the FCMP instruction with new_pred and add it to the old basic
+     * block bb it is now at the position where the old FcmpInst was */
+    Instruction *fcmp_np;
+    fcmp_np = CmpInst::Create(Instruction::FCmp, new_pred, op0, op1);
     bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
-                             icmp_np);
+                             fcmp_np);
 
-    /* create a new basic block which holds the new EQ icmp */
-    Instruction *icmp_eq;
+    /* create a new basic block which holds the new EQ fcmp */
+    Instruction *fcmp_eq;
     /* insert middle_bb before end_bb */
     BasicBlock *middle_bb =
         BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
-    icmp_eq = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, op0, op1);
-    middle_bb->getInstList().push_back(icmp_eq);
+    fcmp_eq = CmpInst::Create(Instruction::FCmp, CmpInst::FCMP_OEQ, op0, op1);
+    middle_bb->getInstList().push_back(fcmp_eq);
     /* add an unconditional branch to the end of middle_bb with destination
      * end_bb */
     BranchInst::Create(end_bb, middle_bb);
 
     /* replace the uncond branch with a conditional one, which depends on the
-     * new_pred icmp. True goes to end, false to the middle (injected) bb */
+     * new_pred fcmp. True goes to end, false to the middle (injected) bb */
     auto term = bb->getTerminator();
-    BranchInst::Create(end_bb, middle_bb, icmp_np, bb);
+    BranchInst::Create(end_bb, middle_bb, fcmp_np, bb);
     term->eraseFromParent();
 
-    /* replace the old IcmpInst (which is the first inst in end_bb) with a PHI
+    /* replace the old FcmpInst (which is the first inst in end_bb) with a PHI
      * inst to wire up the loose ends */
     PHINode *PN = PHINode::Create(Int1Ty, 2, "");
-    /* the first result depends on the outcome of icmp_eq */
-    PN->addIncoming(icmp_eq, middle_bb);
-    /* if the source was the original bb we know that the icmp_np yielded true
+    /* the first result depends on the outcome of fcmp_eq */
+    PN->addIncoming(fcmp_eq, middle_bb);
+    /* if the source was the original bb we know that the fcmp_np yielded true
      * hence we can hardcode this value */
     PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb);
-    /* replace the old IcmpInst with our new and shiny PHI inst */
-    BasicBlock::iterator ii(IcmpInst);
-    ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN);
+    /* replace the old FcmpInst with our new and shiny PHI inst */
+    BasicBlock::iterator ii(FcmpInst);
+    ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN);
 
   }
 
-  /* now for floating point */
-  for (auto &FcmpInst : fcomps) {
+  return true;
 
-    BasicBlock *bb = FcmpInst->getParent();
+}
 
-    auto op0 = FcmpInst->getOperand(0);
-    auto op1 = FcmpInst->getOperand(1);
+/* This function splits ICMP instructions with xGE or xLE predicates into two
+ * ICMP instructions with predicate xGT or xLT and EQ */
+bool SplitComparesTransform::simplifyCompares(Module &M) {
+
+  LLVMContext &              C = M.getContext();
+  std::vector<Instruction *> icomps;
+  IntegerType *              Int1Ty = IntegerType::getInt1Ty(C);
+
+  /* iterate over all functions, bbs and instruction and add
+   * all integer comparisons with >= and <= predicates to the icomps vector */
+  for (auto &F : M) {
+
+    if (!isInInstrumentList(&F)) continue;
+
+    for (auto &BB : F) {
+
+      for (auto &IN : BB) {
+
+        CmpInst *selectcmpInst = nullptr;
+
+        if ((selectcmpInst = dyn_cast<CmpInst>(&IN))) {
+
+          if (selectcmpInst->getPredicate() == CmpInst::ICMP_UGE ||
+              selectcmpInst->getPredicate() == CmpInst::ICMP_SGE ||
+              selectcmpInst->getPredicate() == CmpInst::ICMP_ULE ||
+              selectcmpInst->getPredicate() == CmpInst::ICMP_SLE) {
+
+            auto op0 = selectcmpInst->getOperand(0);
+            auto op1 = selectcmpInst->getOperand(1);
+
+            IntegerType *intTyOp0 = dyn_cast<IntegerType>(op0->getType());
+            IntegerType *intTyOp1 = dyn_cast<IntegerType>(op1->getType());
+
+            /* this is probably not needed but we do it anyway */
+            if (!intTyOp0 || !intTyOp1) { continue; }
+
+            icomps.push_back(selectcmpInst);
+
+          }
+
+        }
+
+      }
+
+    }
+
+  }
+
+  if (!icomps.size()) { return false; }
+
+  for (auto &IcmpInst : icomps) {
+
+    BasicBlock *bb = IcmpInst->getParent();
+
+    auto op0 = IcmpInst->getOperand(0);
+    auto op1 = IcmpInst->getOperand(1);
 
     /* find out what the new predicate is going to be */
-    auto               pred = dyn_cast<CmpInst>(FcmpInst)->getPredicate();
+    auto               pred = dyn_cast<CmpInst>(IcmpInst)->getPredicate();
     CmpInst::Predicate new_pred;
     switch (pred) {
 
-      case CmpInst::FCMP_UGE:
-        new_pred = CmpInst::FCMP_UGT;
+      case CmpInst::ICMP_UGE:
+        new_pred = CmpInst::ICMP_UGT;
         break;
-      case CmpInst::FCMP_OGE:
-        new_pred = CmpInst::FCMP_OGT;
+      case CmpInst::ICMP_SGE:
+        new_pred = CmpInst::ICMP_SGT;
         break;
-      case CmpInst::FCMP_ULE:
-        new_pred = CmpInst::FCMP_ULT;
+      case CmpInst::ICMP_ULE:
+        new_pred = CmpInst::ICMP_ULT;
         break;
-      case CmpInst::FCMP_OLE:
-        new_pred = CmpInst::FCMP_OLT;
+      case CmpInst::ICMP_SLE:
+        new_pred = CmpInst::ICMP_SLT;
         break;
       default:  // keep the compiler happy
         continue;
@@ -265,25 +301,25 @@ bool SplitComparesTransform::simplifyCompares(Module &M) {
     }
 
     /* split before the icmp instruction */
-    BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(FcmpInst));
+    BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst));
 
     /* the old bb now contains a unconditional jump to the new one (end_bb)
      * we need to delete it later */
 
     /* create the ICMP instruction with new_pred and add it to the old basic
      * block bb it is now at the position where the old IcmpInst was */
-    Instruction *fcmp_np;
-    fcmp_np = CmpInst::Create(Instruction::FCmp, new_pred, op0, op1);
+    Instruction *icmp_np;
+    icmp_np = CmpInst::Create(Instruction::ICmp, new_pred, op0, op1);
     bb->getInstList().insert(BasicBlock::iterator(bb->getTerminator()),
-                             fcmp_np);
+                             icmp_np);
 
-    /* create a new basic block which holds the new EQ fcmp */
-    Instruction *fcmp_eq;
+    /* create a new basic block which holds the new EQ icmp */
+    Instruction *icmp_eq;
     /* insert middle_bb before end_bb */
     BasicBlock *middle_bb =
         BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
-    fcmp_eq = CmpInst::Create(Instruction::FCmp, CmpInst::FCMP_OEQ, op0, op1);
-    middle_bb->getInstList().push_back(fcmp_eq);
+    icmp_eq = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, op0, op1);
+    middle_bb->getInstList().push_back(icmp_eq);
     /* add an unconditional branch to the end of middle_bb with destination
      * end_bb */
     BranchInst::Create(end_bb, middle_bb);
@@ -291,20 +327,20 @@ bool SplitComparesTransform::simplifyCompares(Module &M) {
     /* replace the uncond branch with a conditional one, which depends on the
      * new_pred icmp. True goes to end, false to the middle (injected) bb */
     auto term = bb->getTerminator();
-    BranchInst::Create(end_bb, middle_bb, fcmp_np, bb);
+    BranchInst::Create(end_bb, middle_bb, icmp_np, bb);
     term->eraseFromParent();
 
     /* replace the old IcmpInst (which is the first inst in end_bb) with a PHI
      * inst to wire up the loose ends */
     PHINode *PN = PHINode::Create(Int1Ty, 2, "");
     /* the first result depends on the outcome of icmp_eq */
-    PN->addIncoming(fcmp_eq, middle_bb);
+    PN->addIncoming(icmp_eq, middle_bb);
     /* if the source was the original bb we know that the icmp_np yielded true
      * hence we can hardcode this value */
     PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb);
     /* replace the old IcmpInst with our new and shiny PHI inst */
-    BasicBlock::iterator ii(FcmpInst);
-    ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN);
+    BasicBlock::iterator ii(IcmpInst);
+    ReplaceInstWithInst(IcmpInst->getParent()->getInstList(), ii, PN);
 
   }
 
@@ -640,7 +676,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
 
     BranchInst::Create(end_bb, signequal_bb);
 
-    /* create a new bb which is executed if exponents are equal */
+    /* create a new bb which is executed if exponents are satisfying the compare
+     */
     BasicBlock *middle_bb =
         BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb);
 
@@ -695,7 +732,9 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
     }
 
     /* compare the exponents of the operands */
+    Instruction *icmp_exponents_equal;
     Instruction *icmp_exponent_result;
+    BasicBlock * signequal2_bb = signequal_bb;
     switch (FcmpInst->getPredicate()) {
 
       case CmpInst::FCMP_OEQ:
@@ -707,22 +746,60 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
         icmp_exponent_result =
             CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_NE, m_e0, m_e1);
         break;
+      /* compare the exponents of the operands (signs are equal)
+       * if exponents are equal -> proceed to mantissa comparison
+       * else get result depending on sign
+       */
       case CmpInst::FCMP_OGT:
       case CmpInst::FCMP_UGT:
         Instruction *icmp_exponent;
+        icmp_exponents_equal =
+            CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1);
+        signequal_bb->getInstList().insert(
+            BasicBlock::iterator(signequal_bb->getTerminator()),
+            icmp_exponents_equal);
+
+        // shortcut for unequal exponents
+        signequal2_bb = signequal_bb->splitBasicBlock(
+            BasicBlock::iterator(signequal_bb->getTerminator()));
+
+        /* if the exponents are equal goto middle_bb else to signequal2_bb */
+        term = signequal_bb->getTerminator();
+        BranchInst::Create(middle_bb, signequal2_bb, icmp_exponents_equal,
+                           signequal_bb);
+        term->eraseFromParent();
+
         icmp_exponent =
             CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, m_e0, m_e1);
-        signequal_bb->getInstList().insert(
-            BasicBlock::iterator(signequal_bb->getTerminator()), icmp_exponent);
+        signequal2_bb->getInstList().insert(
+            BasicBlock::iterator(signequal2_bb->getTerminator()),
+            icmp_exponent);
         icmp_exponent_result =
             BinaryOperator::Create(Instruction::Xor, icmp_exponent, t_s0);
         break;
       case CmpInst::FCMP_OLT:
       case CmpInst::FCMP_ULT:
+        icmp_exponents_equal =
+            CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1);
+        signequal_bb->getInstList().insert(
+            BasicBlock::iterator(signequal_bb->getTerminator()),
+            icmp_exponents_equal);
+
+        // shortcut for unequal exponents
+        signequal2_bb = signequal_bb->splitBasicBlock(
+            BasicBlock::iterator(signequal_bb->getTerminator()));
+
+        /* if the exponents are equal goto middle_bb else to signequal2_bb */
+        term = signequal_bb->getTerminator();
+        BranchInst::Create(middle_bb, signequal2_bb, icmp_exponents_equal,
+                           signequal_bb);
+        term->eraseFromParent();
+
         icmp_exponent =
             CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, m_e0, m_e1);
-        signequal_bb->getInstList().insert(
-            BasicBlock::iterator(signequal_bb->getTerminator()), icmp_exponent);
+        signequal2_bb->getInstList().insert(
+            BasicBlock::iterator(signequal2_bb->getTerminator()),
+            icmp_exponent);
         icmp_exponent_result =
             BinaryOperator::Create(Instruction::Xor, icmp_exponent, t_s0);
         break;
@@ -731,15 +808,40 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
 
     }
 
-    signequal_bb->getInstList().insert(
-        BasicBlock::iterator(signequal_bb->getTerminator()),
+    signequal2_bb->getInstList().insert(
+        BasicBlock::iterator(signequal2_bb->getTerminator()),
         icmp_exponent_result);
 
     {
 
-      auto term = signequal_bb->getTerminator();
-      /* if the exponents are different do a fraction cmp */
-      BranchInst::Create(middle_bb, end_bb, icmp_exponent_result, signequal_bb);
+      term = signequal2_bb->getTerminator();
+
+      switch (FcmpInst->getPredicate()) {
+
+        case CmpInst::FCMP_OEQ:
+          /* if the exponents are satifying the compare do a fraction cmp in
+           * middle_bb */
+          BranchInst::Create(middle_bb, end_bb, icmp_exponent_result,
+                             signequal2_bb);
+          break;
+        case CmpInst::FCMP_ONE:
+        case CmpInst::FCMP_UNE:
+          /* if the exponents are satifying the compare do a fraction cmp in
+           * middle_bb */
+          BranchInst::Create(end_bb, middle_bb, icmp_exponent_result,
+                             signequal2_bb);
+          break;
+        case CmpInst::FCMP_OGT:
+        case CmpInst::FCMP_UGT:
+        case CmpInst::FCMP_OLT:
+        case CmpInst::FCMP_ULT:
+          BranchInst::Create(end_bb, signequal2_bb);
+          break;
+        default:
+          continue;
+
+      }
+
       term->eraseFromParent();
 
     }
@@ -800,44 +902,82 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
 
     /* compare the fractions of the operands */
     Instruction *icmp_fraction_result;
+    Instruction *icmp_fraction_result2;
+    BasicBlock * middle2_bb = middle_bb;
+    PHINode *    PN2 = nullptr;
     switch (FcmpInst->getPredicate()) {
 
       case CmpInst::FCMP_OEQ:
         icmp_fraction_result =
             CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_f0, t_f1);
+        middle2_bb->getInstList().insert(
+            BasicBlock::iterator(middle2_bb->getTerminator()),
+            icmp_fraction_result);
+
         break;
       case CmpInst::FCMP_UNE:
       case CmpInst::FCMP_ONE:
         icmp_fraction_result =
             CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_NE, t_f0, t_f1);
+        middle2_bb->getInstList().insert(
+            BasicBlock::iterator(middle2_bb->getTerminator()),
+            icmp_fraction_result);
+
         break;
       case CmpInst::FCMP_OGT:
       case CmpInst::FCMP_UGT:
-        Instruction *icmp_fraction;
-        icmp_fraction =
-            CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1);
-        middle_bb->getInstList().insert(
-            BasicBlock::iterator(middle_bb->getTerminator()), icmp_fraction);
-        icmp_fraction_result =
-            BinaryOperator::Create(Instruction::Xor, icmp_fraction, t_s0);
-        break;
       case CmpInst::FCMP_OLT:
-      case CmpInst::FCMP_ULT:
-        icmp_fraction =
-            CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1);
-        middle_bb->getInstList().insert(
-            BasicBlock::iterator(middle_bb->getTerminator()), icmp_fraction);
-        icmp_fraction_result =
-            BinaryOperator::Create(Instruction::Xor, icmp_fraction, t_s0);
-        break;
+      case CmpInst::FCMP_ULT: {
+
+        middle2_bb = middle_bb->splitBasicBlock(
+            BasicBlock::iterator(middle_bb->getTerminator()));
+
+        BasicBlock *negative_bb = BasicBlock::Create(
+            C, "negative_value", middle2_bb->getParent(), middle2_bb);
+        BasicBlock *positive_bb = BasicBlock::Create(
+            C, "positive_value", negative_bb->getParent(), negative_bb);
+
+        if (FcmpInst->getPredicate() == CmpInst::FCMP_OGT ||
+            FcmpInst->getPredicate() == CmpInst::FCMP_UGT) {
+
+          negative_bb->getInstList().push_back(
+              icmp_fraction_result = CmpInst::Create(
+                  Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1));
+          positive_bb->getInstList().push_back(
+              icmp_fraction_result2 = CmpInst::Create(
+                  Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1));
+
+        } else {
+
+          negative_bb->getInstList().push_back(
+              icmp_fraction_result = CmpInst::Create(
+                  Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1));
+          positive_bb->getInstList().push_back(
+              icmp_fraction_result2 = CmpInst::Create(
+                  Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1));
+
+        }
+
+        BranchInst::Create(middle2_bb, negative_bb);
+        BranchInst::Create(middle2_bb, positive_bb);
+
+        term = middle_bb->getTerminator();
+        BranchInst::Create(negative_bb, positive_bb, t_s0, middle_bb);
+        term->eraseFromParent();
+
+        PN2 = PHINode::Create(Int1Ty, 2, "");
+        PN2->addIncoming(icmp_fraction_result, negative_bb);
+        PN2->addIncoming(icmp_fraction_result2, positive_bb);
+        middle2_bb->getInstList().insert(
+            BasicBlock::iterator(middle2_bb->getTerminator()), PN2);
+
+      } break;
+
       default:
         continue;
 
     }
 
-    middle_bb->getInstList().insert(
-        BasicBlock::iterator(middle_bb->getTerminator()), icmp_fraction_result);
-
     PHINode *PN = PHINode::Create(Int1Ty, 3, "");
 
     switch (FcmpInst->getPredicate()) {
@@ -849,7 +989,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
         /* unequal exponents cannot be equal values, too */
         PN->addIncoming(ConstantInt::get(Int1Ty, 0), signequal_bb);
         /* fractions comparison */
-        PN->addIncoming(icmp_fraction_result, middle_bb);
+        PN->addIncoming(icmp_fraction_result, middle2_bb);
         break;
       case CmpInst::FCMP_ONE:
       case CmpInst::FCMP_UNE:
@@ -857,25 +997,25 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) {
         /* goto true branch */
         PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb);
         /* unequal exponents are unequal values, too */
-        PN->addIncoming(ConstantInt::get(Int1Ty, 1), signequal_bb);
+        PN->addIncoming(icmp_exponent_result, signequal_bb);
         /* fractions comparison */
-        PN->addIncoming(icmp_fraction_result, middle_bb);
+        PN->addIncoming(icmp_fraction_result, middle2_bb);
         break;
       case CmpInst::FCMP_OGT:
       case CmpInst::FCMP_UGT:
         /* if op1 is negative goto true branch,
            else go on comparing */
         PN->addIncoming(t_s1, bb);
-        PN->addIncoming(icmp_exponent_result, signequal_bb);
-        PN->addIncoming(icmp_fraction_result, middle_bb);
+        PN->addIncoming(icmp_exponent_result, signequal2_bb);
+        PN->addIncoming(PN2, middle2_bb);
         break;
       case CmpInst::FCMP_OLT:
       case CmpInst::FCMP_ULT:
         /* if op0 is negative goto true branch,
            else go on comparing */
         PN->addIncoming(t_s0, bb);
-        PN->addIncoming(icmp_exponent_result, signequal_bb);
-        PN->addIncoming(icmp_fraction_result, middle_bb);
+        PN->addIncoming(icmp_exponent_result, signequal2_bb);
+        PN->addIncoming(PN2, middle2_bb);
         break;
       default:
         continue;
@@ -1115,24 +1255,29 @@ bool SplitComparesTransform::runOnModule(Module &M) {
 
   enableFPSplit = getenv("AFL_LLVM_LAF_SPLIT_FLOATS") != NULL;
 
-  simplifyCompares(M);
-
-  simplifyIntSignedness(M);
-
   if ((isatty(2) && getenv("AFL_QUIET") == NULL) ||
       getenv("AFL_DEBUG") != NULL) {
 
     errs() << "Split-compare-pass by laf.intel@gmail.com, extended by "
               "heiko@hexco.de\n";
 
-    if (enableFPSplit)
+    if (enableFPSplit) {
+
       errs() << "Split-floatingpoint-compare-pass: " << splitFPCompares(M)
              << " FP comparisons splitted\n";
 
+    }
+
   } else
 
     be_quiet = 1;
 
+  if (enableFPSplit) simplifyFPCompares(M);
+
+  simplifyCompares(M);
+
+  simplifyIntSignedness(M);
+
   switch (bitw) {
 
     case 64:
diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h
index 5f579687..63b7581d 100644
--- a/qemu_mode/patches/afl-qemu-cpu-inl.h
+++ b/qemu_mode/patches/afl-qemu-cpu-inl.h
@@ -620,7 +620,13 @@ static void afl_wait_tsl(CPUState *cpu, int fd) {
 
         last_tb = tb_htable_lookup(cpu, c.last_tb.pc, c.last_tb.cs_base,
                                    c.last_tb.flags, c.cf_mask);
-        if (last_tb) { tb_add_jump(last_tb, c.tb_exit, tb); }
+#define TB_JMP_RESET_OFFSET_INVALID 0xffff
+        if (last_tb && (last_tb->jmp_reset_offset[c.tb_exit] !=
+                        TB_JMP_RESET_OFFSET_INVALID)) {
+
+          tb_add_jump(last_tb, c.tb_exit, tb);
+
+        }
 
       }
 
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index 56284f6f..e6dd0fca 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -772,15 +772,38 @@ static void set_up_environment(void) {
   setenv("ASAN_OPTIONS",
          "abort_on_error=1:"
          "detect_leaks=0:"
+         "allocator_may_return_null=1:"
          "symbolize=0:"
-         "allocator_may_return_null=1",
+         "handle_segv=0:"
+         "handle_sigbus=0:"
+         "handle_abort=0:"
+         "handle_sigfpe=0:"
+         "handle_sigill=0",
+         0);
+
+  setenv("UBSAN_OPTIONS",
+         "halt_on_error=1:"
+         "abort_on_error=1:"
+         "malloc_context_size=0:"
+         "allocator_may_return_null=1:"
+         "symbolize=0:"
+         "handle_segv=0:"
+         "handle_sigbus=0:"
+         "handle_abort=0:"
+         "handle_sigfpe=0:"
+         "handle_sigill=0",
          0);
 
   setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
-                         "symbolize=0:"
                          "abort_on_error=1:"
+                         "msan_track_origins=0"
                          "allocator_may_return_null=1:"
-                         "msan_track_origins=0", 0);
+                         "symbolize=0:"
+                         "handle_segv=0:"
+                         "handle_sigbus=0:"
+                         "handle_abort=0:"
+                         "handle_sigfpe=0:"
+                         "handle_sigill=0", 0);
 
   if (get_afl_env("AFL_PRELOAD")) {
 
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 419ce28e..47493eba 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -434,7 +434,27 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
            "detect_leaks=0:"
            "malloc_context_size=0:"
            "symbolize=0:"
-           "allocator_may_return_null=1",
+           "allocator_may_return_null=1:"
+           "handle_segv=0:"
+           "handle_sigbus=0:"
+           "handle_abort=0:"
+           "handle_sigfpe=0:"
+           "handle_sigill=0",
+           0);
+
+    /* Set sane defaults for UBSAN if nothing else specified. */
+
+    setenv("UBSAN_OPTIONS",
+           "halt_on_error=1:"
+           "abort_on_error=1:"
+           "malloc_context_size=0:"
+           "allocator_may_return_null=1:"
+           "symbolize=0:"
+           "handle_segv=0:"
+           "handle_sigbus=0:"
+           "handle_abort=0:"
+           "handle_sigfpe=0:"
+           "handle_sigill=0",
            0);
 
     /* MSAN is tricky, because it doesn't support abort_on_error=1 at this
@@ -446,7 +466,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
            "abort_on_error=1:"
            "malloc_context_size=0:"
            "allocator_may_return_null=1:"
-           "msan_track_origins=0",
+           "msan_track_origins=0:"
+           "handle_segv=0:"
+           "handle_sigbus=0:"
+           "handle_abort=0:"
+           "handle_sigfpe=0:"
+           "handle_sigill=0",
            0);
 
     fsrv->init_child_func(fsrv, argv);
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index a2e849dc..65ad0c9f 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -36,14 +36,11 @@ void bind_to_free_cpu(afl_state_t *afl) {
   #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
   cpu_set_t c;
   #elif defined(__NetBSD__)
-  cpuset_t *         c;
+  cpuset_t *c;
   #elif defined(__sun)
-  psetid_t            c;
+  psetid_t c;
   #endif
 
-  u8  cpu_used[4096] = {0};
-  u32 i;
-
   if (afl->cpu_core_count < 2) { return; }
 
   if (afl->afl_env.afl_no_affinity) {
@@ -53,13 +50,46 @@ void bind_to_free_cpu(afl_state_t *afl) {
 
   }
 
+  u8  cpu_used[4096] = {0}, lockfile[PATH_MAX] = "";
+  u32 i;
+
+  if (afl->sync_id) {
+
+    s32 lockfd, first = 1;
+
+    snprintf(lockfile, sizeof(lockfile), "%s/.affinity_lock", afl->sync_dir);
+    setenv(CPU_AFFINITY_ENV_VAR, lockfile, 1);
+
+    do {
+
+      if ((lockfd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) {
+
+        if (first) {
+
+          WARNF("CPU affinity lock file present, waiting ...");
+          first = 0;
+
+        }
+
+        usleep(1000);
+
+      }
+
+    } while (lockfd < 0);
+
+    close(lockfd);
+
+  }
+
   #if defined(__linux__)
+
   DIR *          d;
   struct dirent *de;
   d = opendir("/proc");
 
   if (!d) {
 
+    if (lockfile[0]) unlink(lockfile);
     WARNF("Unable to access /proc - can't scan for free CPU cores.");
     return;
 
@@ -67,11 +97,6 @@ void bind_to_free_cpu(afl_state_t *afl) {
 
   ACTF("Checking CPU core loadout...");
 
-  /* Introduce some jitter, in case multiple AFL tasks are doing the same
-     thing at the same time... */
-
-  usleep(R(1000) * 250);
-
   /* Scan all /proc/<pid>/status entries, checking for Cpus_allowed_list.
      Flag all processes bound to a specific CPU using cpu_used[]. This will
      fail for some exotic binding setups, but is likely good enough in almost
@@ -114,20 +139,29 @@ void bind_to_free_cpu(afl_state_t *afl) {
   }
 
   closedir(d);
+
   #elif defined(__FreeBSD__) || defined(__DragonFly__)
+
   struct kinfo_proc *procs;
   size_t             nprocs;
   size_t             proccount;
   int                s_name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
   size_t             s_name_l = sizeof(s_name) / sizeof(s_name[0]);
 
-  if (sysctl(s_name, s_name_l, NULL, &nprocs, NULL, 0) != 0) return;
+  if (sysctl(s_name, s_name_l, NULL, &nprocs, NULL, 0) != 0) {
+
+    if (lockfile[0]) unlink(lockfile);
+    return;
+
+  }
+
   proccount = nprocs / sizeof(*procs);
   nprocs = nprocs * 4 / 3;
 
   procs = ck_alloc(nprocs);
   if (sysctl(s_name, s_name_l, procs, &nprocs, NULL, 0) != 0) {
 
+    if (lockfile[0]) unlink(lockfile);
     ck_free(procs);
     return;
 
@@ -136,6 +170,7 @@ void bind_to_free_cpu(afl_state_t *afl) {
   for (i = 0; i < proccount; i++) {
 
     #if defined(__FreeBSD__)
+
     if (!strcmp(procs[i].ki_comm, "idle")) continue;
 
     // fix when ki_oncpu = -1
@@ -145,16 +180,21 @@ void bind_to_free_cpu(afl_state_t *afl) {
 
     if (oncpu != -1 && oncpu < sizeof(cpu_used) && procs[i].ki_pctcpu > 60)
       cpu_used[oncpu] = 1;
+
     #elif defined(__DragonFly__)
+
     if (procs[i].kp_lwp.kl_cpuid < sizeof(cpu_used) &&
         procs[i].kp_lwp.kl_pctcpu > 10)
       cpu_used[procs[i].kp_lwp.kl_cpuid] = 1;
+
     #endif
 
   }
 
   ck_free(procs);
+
   #elif defined(__NetBSD__)
+
   struct kinfo_proc2 *procs;
   size_t              nprocs;
   size_t              proccount;
@@ -163,13 +203,20 @@ void bind_to_free_cpu(afl_state_t *afl) {
       CTL_KERN, KERN_PROC2, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), 0};
   size_t s_name_l = sizeof(s_name) / sizeof(s_name[0]);
 
-  if (sysctl(s_name, s_name_l, NULL, &nprocs, NULL, 0) != 0) return;
+  if (sysctl(s_name, s_name_l, NULL, &nprocs, NULL, 0) != 0) {
+
+    if (lockfile[0]) unlink(lockfile);
+    return;
+
+  }
+
   proccount = nprocs / sizeof(struct kinfo_proc2);
   procs = ck_alloc(nprocs * sizeof(struct kinfo_proc2));
   s_name[5] = proccount;
 
   if (sysctl(s_name, s_name_l, procs, &nprocs, NULL, 0) != 0) {
 
+    if (lockfile[0]) unlink(lockfile);
     ck_free(procs);
     return;
 
@@ -183,7 +230,9 @@ void bind_to_free_cpu(afl_state_t *afl) {
   }
 
   ck_free(procs);
+
   #elif defined(__sun)
+
   kstat_named_t *n;
   kstat_ctl_t *  m;
   kstat_t *      k;
@@ -198,6 +247,7 @@ void bind_to_free_cpu(afl_state_t *afl) {
 
   if (!k) {
 
+    if (lockfile[0]) unlink(lockfile);
     kstat_close(m);
     return;
 
@@ -205,6 +255,7 @@ void bind_to_free_cpu(afl_state_t *afl) {
 
   if (kstat_read(m, k, NULL)) {
 
+    if (lockfile[0]) unlink(lockfile);
     kstat_close(m);
     return;
 
@@ -220,6 +271,7 @@ void bind_to_free_cpu(afl_state_t *afl) {
     k = kstat_lookup(m, "cpu_stat", i, NULL);
     if (kstat_read(m, k, &cs)) {
 
+      if (lockfile[0]) unlink(lockfile);
       kstat_close(m);
       return;
 
@@ -233,6 +285,7 @@ void bind_to_free_cpu(afl_state_t *afl) {
   }
 
   kstat_close(m);
+
   #else
     #warning \
         "For this platform we do not have free CPU binding code yet. If possible, please supply a PR to https://github.com/AFLplusplus/AFLplusplus"
@@ -241,7 +294,9 @@ void bind_to_free_cpu(afl_state_t *afl) {
   size_t cpu_start = 0;
 
   try:
+
   #if !defined(__ANDROID__)
+
     for (i = cpu_start; i < afl->cpu_core_count; i++) {
 
       if (!cpu_used[i]) { break; }
@@ -251,6 +306,7 @@ void bind_to_free_cpu(afl_state_t *afl) {
   if (i == afl->cpu_core_count) {
 
   #else
+
     for (i = afl->cpu_core_count - cpu_start - 1; i > -1; i--)
       if (!cpu_used[i]) break;
   if (i == -1) {
@@ -274,18 +330,25 @@ void bind_to_free_cpu(afl_state_t *afl) {
   afl->cpu_aff = i;
 
   #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
+
   CPU_ZERO(&c);
   CPU_SET(i, &c);
+
   #elif defined(__NetBSD__)
+
   c = cpuset_create();
   if (c == NULL) PFATAL("cpuset_create failed");
   cpuset_set(i, c);
+
   #elif defined(__sun)
+
 pset_create(&c);
 if (pset_assign(c, i, NULL)) PFATAL("pset_assign failed");
+
   #endif
 
   #if defined(__linux__)
+
   if (sched_setaffinity(0, sizeof(c), &c)) {
 
     if (cpu_start == afl->cpu_core_count) {
@@ -302,6 +365,7 @@ if (pset_assign(c, i, NULL)) PFATAL("pset_assign failed");
   }
 
   #elif defined(__FreeBSD__) || defined(__DragonFly__)
+
   if (pthread_setaffinity_np(pthread_self(), sizeof(c), &c)) {
 
     if (cpu_start == afl->cpu_core_count)
@@ -314,6 +378,7 @@ if (pset_assign(c, i, NULL)) PFATAL("pset_assign failed");
   }
 
   #elif defined(__NetBSD__)
+
 if (pthread_setaffinity_np(pthread_self(), cpuset_size(c), c)) {
 
   if (cpu_start == afl->cpu_core_count)
@@ -326,12 +391,14 @@ if (pthread_setaffinity_np(pthread_self(), cpuset_size(c), c)) {
 }
 
 cpuset_destroy(c);
+
   #elif defined(__sun)
+
 if (pset_bind(c, P_PID, getpid(), NULL)) {
 
   if (cpu_start == afl->cpu_core_count)
     PFATAL("pset_bind failed for cpu %d, exit", i);
-  WARNF("pthread_setaffinity failed to CPU %d, trying next CPU", i);
+  WARNF("pset_bind failed to CPU %d, trying next CPU", i);
   cpu_start++;
   goto try
     ;
@@ -339,11 +406,17 @@ if (pset_bind(c, P_PID, getpid(), NULL)) {
 }
 
 pset_destroy(c);
+
   #else
+
   // this will need something for other platforms
   // TODO: Solaris/Illumos has processor_bind ... might worth a try
+
   #endif
 
+  if (lockfile[0]) unlink(lockfile);
+  // we leave the environment variable to ensure a cleanup for other processes
+
 }
 
 #endif                                                     /* HAVE_AFFINITY */
@@ -365,6 +438,159 @@ static void shuffle_ptrs(afl_state_t *afl, void **ptrs, u32 cnt) {
 
 }
 
+/* Read all testcases from foreign input directories, then queue them for
+   testing. Called at startup and at sync intervals.
+   Does not descend into subdirectories! */
+
+void read_foreign_testcases(afl_state_t *afl, int first) {
+
+  if (!afl->foreign_sync_cnt) return;
+
+  struct dirent **nl;
+  s32             nl_cnt;
+  u32             i, iter;
+
+  u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
+
+  for (iter = 0; iter < afl->foreign_sync_cnt; iter++) {
+
+    if (afl->foreign_syncs[iter].dir != NULL &&
+        afl->foreign_syncs[iter].dir[0] != 0) {
+
+      if (first) ACTF("Scanning '%s'...", afl->foreign_syncs[iter].dir);
+      time_t ctime_max = 0;
+
+      /* We use scandir() + alphasort() rather than readdir() because otherwise,
+         the ordering of test cases would vary somewhat randomly and would be
+         difficult to control. */
+
+      nl_cnt = scandir(afl->foreign_syncs[iter].dir, &nl, NULL, NULL);
+
+      if (nl_cnt < 0) {
+
+        if (first) {
+
+          WARNF("Unable to open directory '%s'", afl->foreign_syncs[iter].dir);
+          sleep(1);
+
+        }
+
+        continue;
+
+      }
+
+      if (nl_cnt == 0) {
+
+        if (first)
+          WARNF("directory %s is currently empty",
+                afl->foreign_syncs[iter].dir);
+        continue;
+
+      }
+
+      /* Show stats */
+
+      snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "foreign sync %u", iter);
+
+      afl->stage_name = afl->stage_name_buf;
+      afl->stage_cur = 0;
+      afl->stage_max = 0;
+
+      for (i = 0; i < nl_cnt; ++i) {
+
+        struct stat st;
+
+        u8 *fn2 =
+            alloc_printf("%s/%s", afl->foreign_syncs[iter].dir, nl[i]->d_name);
+
+        free(nl[i]);                                         /* not tracked */
+
+        if (unlikely(lstat(fn2, &st) || access(fn2, R_OK))) {
+
+          if (first) PFATAL("Unable to access '%s'", fn2);
+          continue;
+
+        }
+
+        /* we detect new files by their ctime */
+        if (likely(st.st_ctime <= afl->foreign_syncs[iter].ctime)) {
+
+          ck_free(fn2);
+          continue;
+
+        }
+
+        /* This also takes care of . and .. */
+
+        if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) {
+
+          ck_free(fn2);
+          continue;
+
+        }
+
+        if (st.st_size > MAX_FILE) {
+
+          if (first)
+            WARNF(
+                "Test case '%s' is too big (%s, limit is %s), skipping", fn2,
+                stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
+                stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
+          ck_free(fn2);
+          continue;
+
+        }
+
+        // lets do not use add_to_queue(afl, fn2, st.st_size, 0);
+        // as this could add duplicates of the startup input corpus
+
+        int fd = open(fn2, O_RDONLY);
+        if (fd < 0) {
+
+          ck_free(fn2);
+          continue;
+
+        }
+
+        u8  fault;
+        u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+        if (mem == MAP_FAILED) {
+
+          ck_free(fn2);
+          continue;
+
+        }
+
+        write_to_testcase(afl, mem, st.st_size);
+        fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
+        afl->syncing_party = "foreign";
+        afl->queued_imported +=
+            save_if_interesting(afl, mem, st.st_size, fault);
+        afl->syncing_party = 0;
+        munmap(mem, st.st_size);
+        close(fd);
+
+        if (st.st_ctime > ctime_max) ctime_max = st.st_ctime;
+
+      }
+
+      afl->foreign_syncs[iter].ctime = ctime_max;
+      free(nl);                                              /* not tracked */
+
+    }
+
+  }
+
+  if (first) {
+
+    afl->last_path_time = 0;
+    afl->queued_at_start = afl->queued_paths;
+
+  }
+
+}
+
 /* Read all testcases from the input directory, then queue them for testing.
    Called at startup. */
 
@@ -393,7 +619,7 @@ void read_testcases(afl_state_t *afl) {
   ACTF("Scanning '%s'...", afl->in_dir);
 
   /* We use scandir() + alphasort() rather than readdir() because otherwise,
-     the ordering  of test cases would vary somewhat randomly and would be
+     the ordering of test cases would vary somewhat randomly and would be
      difficult to control. */
 
   nl_cnt = scandir(afl->in_dir, &nl, NULL, alphasort);
@@ -454,9 +680,11 @@ void read_testcases(afl_state_t *afl) {
 
     if (st.st_size > MAX_FILE) {
 
-      FATAL("Test case '%s' is too big (%s, limit is %s)", fn2,
+      WARNF("Test case '%s' is too big (%s, limit is %s), skipping", fn2,
             stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
             stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
+      ck_free(fn2);
+      continue;
 
     }
 
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index 9fc77ffe..850266c2 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -168,7 +168,8 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
 
   /* "afl_custom_deinit", optional for backward compatibility */
   mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit");
-  if (!mutator->afl_custom_deinit) FATAL("Symbol 'afl_custom_init' not found.");
+  if (!mutator->afl_custom_deinit)
+    FATAL("Symbol 'afl_custom_deinit' not found.");
 
   /* "afl_custom_post_process", optional */
   mutator->afl_custom_post_process = dlsym(dh, "afl_custom_post_process");
@@ -282,9 +283,32 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
 
     } else if (unlikely(retlen > orig_len)) {
 
-      FATAL(
-          "Trimmed data returned by custom mutator is larger than original "
-          "data");
+      /* Do not exit the fuzzer, even if the trimmed data returned by the custom
+         mutator is larger than the original data. For some use cases, like the
+         grammar mutator, the definition of "size" may have different meanings.
+         For example, the trimming function in a grammar mutator aims at
+         reducing the objects in a grammar structure, but does not guarantee to
+         generate a smaller binary buffer.
+
+         Thus, we allow the custom mutator to generate the trimmed data that is
+         larger than the original data. */
+
+      if (afl->not_on_tty && afl->debug) {
+
+        WARNF(
+            "Trimmed data returned by custom mutator is larger than original "
+            "data");
+
+      }
+
+    } else if (unlikely(retlen == 0)) {
+
+      /* Do not run the empty test case on the target. To keep the custom
+         trimming function running, we simply treat the empty test case as an
+         unsuccessful trimming and skip it, instead of aborting the trimming. */
+
+      ++afl->trim_execs;
+      goto unsuccessful_trimming;
 
     }
 
@@ -325,6 +349,8 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
 
     } else {
 
+    unsuccessful_trimming:
+
       /* Tell the custom mutator that the trimming was unsuccessful */
       afl->stage_cur = mutator->afl_custom_post_trim(mutator->data, 0);
       if (unlikely(afl->stage_cur < 0)) {
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index 724da407..c53e0e06 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -177,6 +177,9 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) {
   afl->stage_cycles[STAGE_COLORIZATION] += afl->stage_cur;
   ck_free(backup);
 
+  ck_free(rng);
+  rng = NULL;
+
   while (ranges) {
 
     rng = ranges;
@@ -186,9 +189,6 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) {
 
   }
 
-  ck_free(rng);
-  rng = NULL;
-
   // save the input with the high entropy
 
   if (needs_write) {
@@ -277,9 +277,9 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
   u8 * o_buf_8 = &orig_buf[idx];
 
   u32 its_len = len - idx;
-  *status = 0;
+  // *status = 0;
 
-  if (SHAPE_BYTES(h->shape) == 8) {
+  if (SHAPE_BYTES(h->shape) >= 8) {
 
     if (its_len >= 8 && *buf_64 == pattern && *o_buf_64 == o_pattern) {
 
@@ -290,7 +290,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
     }
 
     // reverse encoding
-    if (do_reverse) {
+    if (do_reverse && *status != 1) {
 
       if (unlikely(cmp_extend_encoding(afl, h, SWAP64(pattern), SWAP64(repl),
                                        SWAP64(o_pattern), idx, orig_buf, buf,
@@ -304,7 +304,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
 
   }
 
-  if (SHAPE_BYTES(h->shape) == 4 || *status == 2) {
+  if (SHAPE_BYTES(h->shape) >= 4 && *status != 1) {
 
     if (its_len >= 4 && *buf_32 == (u32)pattern &&
         *o_buf_32 == (u32)o_pattern) {
@@ -316,7 +316,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
     }
 
     // reverse encoding
-    if (do_reverse) {
+    if (do_reverse && *status != 1) {
 
       if (unlikely(cmp_extend_encoding(afl, h, SWAP32(pattern), SWAP32(repl),
                                        SWAP32(o_pattern), idx, orig_buf, buf,
@@ -330,7 +330,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
 
   }
 
-  if (SHAPE_BYTES(h->shape) == 2 || *status == 2) {
+  if (SHAPE_BYTES(h->shape) >= 2 && *status != 1) {
 
     if (its_len >= 2 && *buf_16 == (u16)pattern &&
         *o_buf_16 == (u16)o_pattern) {
@@ -342,7 +342,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
     }
 
     // reverse encoding
-    if (do_reverse) {
+    if (do_reverse && *status != 1) {
 
       if (unlikely(cmp_extend_encoding(afl, h, SWAP16(pattern), SWAP16(repl),
                                        SWAP16(o_pattern), idx, orig_buf, buf,
@@ -356,7 +356,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
 
   }
 
-  if (SHAPE_BYTES(h->shape) == 1 || *status == 2) {
+  if (SHAPE_BYTES(h->shape) >= 1 && *status != 1) {
 
     if (its_len >= 1 && *buf_8 == (u8)pattern && *o_buf_8 == (u8)o_pattern) {
 
@@ -482,6 +482,7 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
 
     for (idx = 0; idx < len && fails < 8; ++idx) {
 
+      status = 0;
       if (unlikely(cmp_extend_encoding(afl, h, o->v0, o->v1, orig_o->v0, idx,
                                        orig_buf, buf, len, 1, &status))) {
 
@@ -499,6 +500,7 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
 
       }
 
+      status = 0;
       if (unlikely(cmp_extend_encoding(afl, h, o->v1, o->v0, orig_o->v1, idx,
                                        orig_buf, buf, len, 1, &status))) {
 
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 2a1664e2..6e3be72b 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -612,6 +612,8 @@ void sync_fuzzers(afl_state_t *afl) {
 
   }
 
+  if (afl->foreign_sync_cnt) read_foreign_testcases(afl, 0);
+
 }
 
 /* Trim all new test cases to save cycles when doing deterministic checks. The
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index fc93011b..2546a57a 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -39,7 +39,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
   u8                     fn[PATH_MAX];
   s32                    fd;
   FILE *                 f;
-  uint32_t               t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
+  u32                    t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
 
   snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
 
@@ -67,89 +67,101 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
 
   }
 
+  if ((unlikely(!afl->last_avg_exec_update ||
+                cur_time - afl->last_avg_exec_update >= 60000))) {
+
+    afl->last_avg_execs_saved =
+        (float)(1000 * (afl->fsrv.total_execs - afl->last_avg_execs)) /
+        (float)(cur_time - afl->last_avg_exec_update);
+    afl->last_avg_execs = afl->fsrv.total_execs;
+    afl->last_avg_exec_update = cur_time;
+
+  }
+
 #ifndef __HAIKU__
   if (getrusage(RUSAGE_CHILDREN, &rus)) { rus.ru_maxrss = 0; }
 #endif
 
-  fprintf(
-      f,
-      "start_time        : %llu\n"
-      "last_update       : %llu\n"
-      "run_time          : %llu\n"
-      "fuzzer_pid        : %u\n"
-      "cycles_done       : %llu\n"
-      "cycles_wo_finds   : %llu\n"
-      "execs_done        : %llu\n"
-      "execs_per_sec     : %0.02f\n"
-      //          "real_execs_per_sec: %0.02f\n"  // damn the name is too long
-      "paths_total       : %u\n"
-      "paths_favored     : %u\n"
-      "paths_found       : %u\n"
-      "paths_imported    : %u\n"
-      "max_depth         : %u\n"
-      "cur_path          : %u\n"        /* Must match find_start_position() */
-      "pending_favs      : %u\n"
-      "pending_total     : %u\n"
-      "variable_paths    : %u\n"
-      "stability         : %0.02f%%\n"
-      "bitmap_cvg        : %0.02f%%\n"
-      "unique_crashes    : %llu\n"
-      "unique_hangs      : %llu\n"
-      "last_path         : %llu\n"
-      "last_crash        : %llu\n"
-      "last_hang         : %llu\n"
-      "execs_since_crash : %llu\n"
-      "exec_timeout      : %u\n"
-      "slowest_exec_ms   : %u\n"
-      "peak_rss_mb       : %lu\n"
-      "cpu_affinity      : %d\n"
-      "edges_found       : %u\n"
-      "var_byte_count    : %u\n"
-      "afl_banner        : %s\n"
-      "afl_version       : " VERSION
-      "\n"
-      "target_mode       : %s%s%s%s%s%s%s%s%s\n"
-      "command_line      : %s\n",
-      afl->start_time / 1000, cur_time / 1000,
-      (cur_time - afl->start_time) / 1000, (u32)getpid(),
-      afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds,
-      afl->fsrv.total_execs,
-      afl->fsrv.total_execs /
-          ((double)(get_cur_time() - afl->start_time) / 1000),
-      afl->queued_paths, afl->queued_favored, afl->queued_discovered,
-      afl->queued_imported, afl->max_depth, afl->current_entry,
-      afl->pending_favored, afl->pending_not_fuzzed, afl->queued_variable,
-      stability, bitmap_cvg, afl->unique_crashes, afl->unique_hangs,
-      afl->last_path_time / 1000, afl->last_crash_time / 1000,
-      afl->last_hang_time / 1000, afl->fsrv.total_execs - afl->last_crash_execs,
-      afl->fsrv.exec_tmout, afl->slowest_exec_ms,
+  fprintf(f,
+          "start_time        : %llu\n"
+          "last_update       : %llu\n"
+          "run_time          : %llu\n"
+          "fuzzer_pid        : %u\n"
+          "cycles_done       : %llu\n"
+          "cycles_wo_finds   : %llu\n"
+          "execs_done        : %llu\n"
+          "execs_per_sec     : %0.02f\n"
+          "execs_ps_last_min : %0.02f\n"
+          "paths_total       : %u\n"
+          "paths_favored     : %u\n"
+          "paths_found       : %u\n"
+          "paths_imported    : %u\n"
+          "max_depth         : %u\n"
+          "cur_path          : %u\n"    /* Must match find_start_position() */
+          "pending_favs      : %u\n"
+          "pending_total     : %u\n"
+          "variable_paths    : %u\n"
+          "stability         : %0.02f%%\n"
+          "bitmap_cvg        : %0.02f%%\n"
+          "unique_crashes    : %llu\n"
+          "unique_hangs      : %llu\n"
+          "last_path         : %llu\n"
+          "last_crash        : %llu\n"
+          "last_hang         : %llu\n"
+          "execs_since_crash : %llu\n"
+          "exec_timeout      : %u\n"
+          "slowest_exec_ms   : %u\n"
+          "peak_rss_mb       : %lu\n"
+          "cpu_affinity      : %d\n"
+          "edges_found       : %u\n"
+          "var_byte_count    : %u\n"
+          "afl_banner        : %s\n"
+          "afl_version       : " VERSION
+          "\n"
+          "target_mode       : %s%s%s%s%s%s%s%s%s\n"
+          "command_line      : %s\n",
+          afl->start_time / 1000, cur_time / 1000,
+          (cur_time - afl->start_time) / 1000, (u32)getpid(),
+          afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds,
+          afl->fsrv.total_execs,
+          afl->fsrv.total_execs /
+              ((double)(get_cur_time() - afl->start_time) / 1000),
+          afl->last_avg_execs_saved, afl->queued_paths, afl->queued_favored,
+          afl->queued_discovered, afl->queued_imported, afl->max_depth,
+          afl->current_entry, afl->pending_favored, afl->pending_not_fuzzed,
+          afl->queued_variable, stability, bitmap_cvg, afl->unique_crashes,
+          afl->unique_hangs, afl->last_path_time / 1000,
+          afl->last_crash_time / 1000, afl->last_hang_time / 1000,
+          afl->fsrv.total_execs - afl->last_crash_execs, afl->fsrv.exec_tmout,
+          afl->slowest_exec_ms,
 #ifndef __HAIKU__
   #ifdef __APPLE__
-      (unsigned long int)(rus.ru_maxrss >> 20),
+          (unsigned long int)(rus.ru_maxrss >> 20),
   #else
-      (unsigned long int)(rus.ru_maxrss >> 10),
+          (unsigned long int)(rus.ru_maxrss >> 10),
   #endif
 #else
-      -1UL,
+          -1UL,
 #endif
 #ifdef HAVE_AFFINITY
-      afl->cpu_aff,
+          afl->cpu_aff,
 #else
-      -1,
+          -1,
 #endif
-      t_bytes, afl->var_byte_count, afl->use_banner,
-      afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "",
-      afl->non_instrumented_mode ? " non_instrumented " : "",
-      afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "",
-      afl->persistent_mode ? "persistent " : "",
-      afl->shmem_testcase_mode ? "shmem_testcase " : "",
-      afl->deferred_mode ? "deferred " : "",
-      (afl->unicorn_mode || afl->fsrv.qemu_mode || afl->non_instrumented_mode ||
-       afl->no_forkserver || afl->crash_mode || afl->persistent_mode ||
-       afl->deferred_mode)
-          ? ""
-          : "default",
-      afl->orig_cmdline);
+          t_bytes, afl->var_byte_count, afl->use_banner,
+          afl->unicorn_mode ? "unicorn" : "",
+          afl->fsrv.qemu_mode ? "qemu " : "",
+          afl->non_instrumented_mode ? " non_instrumented " : "",
+          afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "",
+          afl->persistent_mode ? "persistent " : "",
+          afl->shmem_testcase_mode ? "shmem_testcase " : "",
+          afl->deferred_mode ? "deferred " : "",
+          (afl->unicorn_mode || afl->fsrv.qemu_mode ||
+           afl->non_instrumented_mode || afl->no_forkserver ||
+           afl->crash_mode || afl->persistent_mode || afl->deferred_mode)
+              ? ""
+              : "default",
+          afl->orig_cmdline);
   /* ignore errors */
 
   if (afl->debug) {
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index e4e2669c..39e4f32d 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -42,19 +42,21 @@ static void at_exit() {
 
   int   i;
   char *list[4] = {SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, CMPLOG_SHM_ENV_VAR, NULL};
-  char *ptr = getenv("__AFL_TARGET_PID1");
+  char *ptr;
 
+  ptr = getenv(CPU_AFFINITY_ENV_VAR);
+  if (ptr && *ptr) unlink(ptr);
+
+  ptr = getenv("__AFL_TARGET_PID1");
   if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL);
 
   ptr = getenv("__AFL_TARGET_PID2");
-
   if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL);
 
   i = 0;
   while (list[i] != NULL) {
 
     ptr = getenv(list[i]);
-
     if (ptr && *ptr) {
 
 #ifdef USEMMAP
@@ -129,10 +131,13 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) {
       "executions.\n\n"
 
       "Other stuff:\n"
-      "  -T text       - text banner to show on the screen\n"
       "  -M/-S id      - distributed mode (see docs/parallel_fuzzing.md)\n"
       "                  use -D to force -S secondary to perform deterministic "
       "fuzzing\n"
+      "  -F path       - sync to a foreign fuzzer queue directory (requires "
+      "-M, can\n"
+      "                  be specified up to %u times)\n"
+      "  -T text       - text banner to show on the screen\n"
       "  -I command    - execute this command/script when a new crash is "
       "found\n"
       //"  -B bitmap.txt - mutate a specific test case, use the out/fuzz_bitmap
@@ -140,7 +145,7 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) {
       "  -C            - crash exploration mode (the peruvian rabbit thing)\n"
       "  -e ext        - file extension for the fuzz test input file (if "
       "needed)\n\n",
-      argv0, EXEC_TIMEOUT, MEM_LIMIT);
+      argv0, EXEC_TIMEOUT, MEM_LIMIT, FOREIGN_SYNCS_MAX);
 
   if (more_help > 1) {
 
@@ -264,6 +269,8 @@ int main(int argc, char **argv_orig, char **envp) {
   gettimeofday(&tv, &tz);
   rand_set_seed(afl, tv.tv_sec ^ tv.tv_usec ^ getpid());
 
+  afl->shmem_testcase_mode = 1;  // we always try to perform shmem fuzzing
+
   while ((opt = getopt(argc, argv,
                        "+c:i:I:o:f:m:t:T:dDnCB:S:M:x:QNUWe:p:s:V:E:L:hRP:")) >
          0) {
@@ -399,6 +406,19 @@ int main(int argc, char **argv_orig, char **envp) {
         afl->use_splicing = 1;
         break;
 
+      case 'F':                                         /* foreign sync dir */
+
+        if (!afl->is_main_node)
+          FATAL(
+              "Option -F can only be specified after the -M option for the "
+              "main fuzzer of a fuzzing campaign");
+        if (afl->foreign_sync_cnt >= FOREIGN_SYNCS_MAX)
+          FATAL("Maximum %u entried of -F option can be specified",
+                FOREIGN_SYNCS_MAX);
+        afl->foreign_syncs[afl->foreign_sync_cnt].dir = optarg;
+        afl->foreign_sync_cnt++;
+        break;
+
       case 'f':                                              /* target file */
 
         if (afl->fsrv.out_file) { FATAL("Multiple -f options not supported"); }
@@ -561,7 +581,6 @@ int main(int argc, char **argv_orig, char **envp) {
 
         if (afl->fsrv.qemu_mode) { FATAL("Multiple -Q options not supported"); }
         afl->fsrv.qemu_mode = 1;
-        afl->shmem_testcase_mode = 1;
 
         if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_QEMU; }
 
@@ -578,7 +597,6 @@ int main(int argc, char **argv_orig, char **envp) {
 
         if (afl->unicorn_mode) { FATAL("Multiple -U options not supported"); }
         afl->unicorn_mode = 1;
-        afl->shmem_testcase_mode = 1;
 
         if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_UNICORN; }
 
@@ -589,7 +607,6 @@ int main(int argc, char **argv_orig, char **envp) {
         if (afl->use_wine) { FATAL("Multiple -W options not supported"); }
         afl->fsrv.qemu_mode = 1;
         afl->use_wine = 1;
-        afl->shmem_testcase_mode = 1;
 
         if (!mem_limit_given) { afl->fsrv.mem_limit = 0; }
 
@@ -1011,17 +1028,19 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  check_crash_handling();
+  check_cpu_governor(afl);
+
   get_core_count(afl);
 
+  atexit(at_exit);
+
+  setup_dirs_fds(afl);
+
   #ifdef HAVE_AFFINITY
   bind_to_free_cpu(afl);
   #endif                                                   /* HAVE_AFFINITY */
 
-  check_crash_handling();
-  check_cpu_governor(afl);
-
-  atexit(at_exit);
-
   afl->fsrv.trace_bits =
       afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode);
 
@@ -1038,20 +1057,26 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
-  setup_dirs_fds(afl);
-
   if (afl->is_secondary_node && check_main_node_exists(afl) == 0) {
 
     WARNF("no -M main node found. You need to run one main instance!");
-    sleep(5);
+    sleep(3);
 
   }
 
+  #ifdef RAND_TEST_VALUES
+  u32 counter;
+  for (counter = 0; counter < 100000; counter++)
+    printf("DEBUG: rand %06d is %u\n", counter, rand_below(afl, 65536));
+  #endif
+
   setup_custom_mutators(afl);
 
   setup_cmdline_file(afl, argv + optind);
 
   read_testcases(afl);
+  // read_foreign_testcases(afl, 1); for the moment dont do this
+
   load_auto(afl);
 
   pivot_inputs(afl);
@@ -1209,6 +1234,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  (void)nice(-20);
   // real start time, we reset, so this works correctly with -V
   afl->start_time = get_cur_time();
 
diff --git a/src/afl-gcc.c b/src/afl-gcc.c
index b8ff7e77..22e6be8e 100644
--- a/src/afl-gcc.c
+++ b/src/afl-gcc.c
@@ -132,6 +132,9 @@ static void edit_params(u32 argc, char **argv) {
 
     name = argv[0];
 
+    /* This should never happen but fixes a scan-build warning */
+    if (!name) { FATAL("Empty argv set"); }
+
   } else {
 
     ++name;
@@ -465,7 +468,7 @@ int main(int argc, char **argv) {
     u32 map_size = atoi(ptr);
     if (map_size != MAP_SIZE) {
 
-      FATAL("AFL_MAP_SIZE is not supported by afl-gcc");
+      WARNF("AFL_MAP_SIZE is not supported by afl-gcc");
 
     }
 
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index 883398ff..71e975a1 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -456,15 +456,38 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
   setenv("ASAN_OPTIONS",
          "abort_on_error=1:"
          "detect_leaks=0:"
+         "allocator_may_return_null=1:"
          "symbolize=0:"
-         "allocator_may_return_null=1",
+         "handle_segv=0:"
+         "handle_sigbus=0:"
+         "handle_abort=0:"
+         "handle_sigfpe=0:"
+         "handle_sigill=0",
+         0);
+
+  setenv("UBSAN_OPTIONS",
+         "halt_on_error=1:"
+         "abort_on_error=1:"
+         "malloc_context_size=0:"
+         "allocator_may_return_null=1:"
+         "symbolize=0:"
+         "handle_segv=0:"
+         "handle_sigbus=0:"
+         "handle_abort=0:"
+         "handle_sigfpe=0:"
+         "handle_sigill=0",
          0);
 
   setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
-                         "symbolize=0:"
                          "abort_on_error=1:"
+                         "msan_track_origins=0"
                          "allocator_may_return_null=1:"
-                         "msan_track_origins=0", 0);
+                         "symbolize=0:"
+                         "handle_segv=0:"
+                         "handle_sigbus=0:"
+                         "handle_abort=0:"
+                         "handle_sigfpe=0:"
+                         "handle_sigill=0", 0);
 
   if (get_afl_env("AFL_PRELOAD")) {
 
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index 2db1eae7..68fcdd14 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -701,15 +701,38 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
   setenv("ASAN_OPTIONS",
          "abort_on_error=1:"
          "detect_leaks=0:"
+         "allocator_may_return_null=1:"
          "symbolize=0:"
-         "allocator_may_return_null=1",
+         "handle_segv=0:"
+         "handle_sigbus=0:"
+         "handle_abort=0:"
+         "handle_sigfpe=0:"
+         "handle_sigill=0",
+         0);
+
+  setenv("UBSAN_OPTIONS",
+         "halt_on_error=1:"
+         "abort_on_error=1:"
+         "malloc_context_size=0:"
+         "allocator_may_return_null=1:"
+         "symbolize=0:"
+         "handle_segv=0:"
+         "handle_sigbus=0:"
+         "handle_abort=0:"
+         "handle_sigfpe=0:"
+         "handle_sigill=0",
          0);
 
   setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
-                         "symbolize=0:"
                          "abort_on_error=1:"
+                         "msan_track_origins=0"
                          "allocator_may_return_null=1:"
-                         "msan_track_origins=0", 0);
+                         "symbolize=0:"
+                         "handle_segv=0:"
+                         "handle_sigbus=0:"
+                         "handle_abort=0:"
+                         "handle_sigfpe=0:"
+                         "handle_sigill=0", 0);
 
   if (get_afl_env("AFL_PRELOAD")) {
 
diff --git a/test/test-floatingpoint.c b/test/test-floatingpoint.c
new file mode 100644
index 00000000..acecd55a
--- /dev/null
+++ b/test/test-floatingpoint.c
@@ -0,0 +1,26 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdint.h>
+
+__AFL_FUZZ_INIT();
+
+int main(void) {
+
+  ssize_t bytes_read;
+
+  __AFL_INIT();
+  float *magic = (float *)__AFL_FUZZ_TESTCASE_BUF;
+
+  while (__AFL_LOOP(INT_MAX)) {
+
+    if (__AFL_FUZZ_TESTCASE_LEN != sizeof(float)) return 1;
+    /* 15 + 1/2 + 1/8 + 1/32 + 1/128 */
+    if ((-*magic == 15.0 + 0.5 + 0.125 + 0.03125 + 0.0078125)) abort();
+
+  }
+
+  return 0;
+
+}
+
diff --git a/test/test-fp_cases.c b/test/test-fp_cases.c
new file mode 100644
index 00000000..b0f792bc
--- /dev/null
+++ b/test/test-fp_cases.c
@@ -0,0 +1,213 @@
+/* test cases for floating point comparison transformations
+ * compile with -DFLOAT_TYPE=float
+ *          or  -DFLOAT_TYPE=double
+ *          or  -DFLOAT_TYPE="long double"
+ */
+
+#include <assert.h>
+
+int main() {
+
+  volatile FLOAT_TYPE a, b;
+  /* different values */
+  a = -2.1;
+  b = -2;                             /* signs equal, exp equal, mantissa > */
+  assert((a < b));
+  assert((a <= b));
+  assert(!(a > b));
+  assert(!(a >= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  a = 1.8;
+  b = 2.1;                           /* signs equal, exp differ, mantissa > */
+  assert((a < b));
+  assert((a <= b));
+  assert(!(a > b));
+  assert(!(a >= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  a = 2;
+  b = 2.1;                            /* signs equal, exp equal, mantissa < */
+  assert((a < b));
+  assert((a <= b));
+  assert(!(a > b));
+  assert(!(a >= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  a = -2;
+  b = -1.8;                          /* signs equal, exp differ, mantissa < */
+  assert((a < b));
+  assert((a <= b));
+  assert(!(a > b));
+  assert(!(a >= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  a = -1;
+  b = 1;                         /* signs differ, exp equal, mantissa equal */
+  assert((a < b));
+  assert((a <= b));
+  assert(!(a > b));
+  assert(!(a >= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  a = -1;
+  b = 0;                        /* signs differ, exp differ, mantissa equal */
+  assert((a < b));
+  assert((a <= b));
+  assert(!(a > b));
+  assert(!(a >= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  a = -2;
+  b = 2.8;                           /* signs differ, exp equal, mantissa < */
+  assert((a < b));
+  assert((a <= b));
+  assert(!(a > b));
+  assert(!(a >= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  a = -2;
+  b = 1.8;                          /* signs differ, exp differ, mantissa < */
+  assert((a < b));
+  assert((a <= b));
+  assert(!(a > b));
+  assert(!(a >= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  a = -2;
+  b = -2.1;                           /* signs equal, exp equal, mantissa > */
+  assert((a > b));
+  assert((a >= b));
+  assert(!(a < b));
+  assert(!(a <= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  a = 2.1;
+  b = 1.8;                           /* signs equal, exp differ, mantissa > */
+  assert((a > b));
+  assert((a >= b));
+  assert(!(a < b));
+  assert(!(a <= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  a = 2.1;
+  b = 2;                              /* signs equal, exp equal, mantissa < */
+  assert((a > b));
+  assert((a >= b));
+  assert(!(a < b));
+  assert(!(a <= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  a = -1.8;
+  b = -2;                            /* signs equal, exp differ, mantissa < */
+  assert((a > b));
+  assert((a >= b));
+  assert(!(a < b));
+  assert(!(a <= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  a = 1;
+  b = -1;                        /* signs differ, exp equal, mantissa equal */
+  assert((a > b));
+  assert((a >= b));
+  assert(!(a < b));
+  assert(!(a <= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  a = 0;
+  b = -1;                       /* signs differ, exp differ, mantissa equal */
+  assert((a > b));
+  assert((a >= b));
+  assert(!(a < b));
+  assert(!(a <= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  a = 2.8;
+  b = -2;                            /* signs differ, exp equal, mantissa < */
+  assert((a > b));
+  assert((a >= b));
+  assert(!(a < b));
+  assert(!(a <= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  a = 1.8;
+  b = -2;                           /* signs differ, exp differ, mantissa < */
+  assert((a > b));
+  assert((a >= b));
+  assert(!(a < b));
+  assert(!(a <= b));
+  assert((a != b));
+  assert(!(a == b));
+
+  /* equal values */
+  a = 0;
+  b = 0;
+  assert(!(a < b));
+  assert((a <= b));
+  assert(!(a > b));
+  assert((a >= b));
+  assert(!(a != b));
+  assert((a == b));
+
+  a = -0;
+  b = 0;
+  assert(!(a < b));
+  assert((a <= b));
+  assert(!(a > b));
+  assert((a >= b));
+  assert(!(a != b));
+  assert((a == b));
+
+  a = 1;
+  b = 1;
+  assert(!(a < b));
+  assert((a <= b));
+  assert(!(a > b));
+  assert((a >= b));
+  assert(!(a != b));
+  assert((a == b));
+
+  a = 0.5;
+  b = 0.5;
+  assert(!(a < b));
+  assert((a <= b));
+  assert(!(a > b));
+  assert((a >= b));
+  assert(!(a != b));
+  assert((a == b));
+
+  a = -1;
+  b = -1;
+  assert(!(a < b));
+  assert((a <= b));
+  assert(!(a > b));
+  assert((a >= b));
+  assert(!(a != b));
+  assert((a == b));
+
+  a = -0.5;
+  b = -0.5;
+  assert(!(a < b));
+  assert((a <= b));
+  assert(!(a > b));
+  assert((a >= b));
+  assert(!(a != b));
+  assert((a == b));
+
+}
+
diff --git a/test/test.sh b/test/test.sh
index 90920215..76b089e7 100755
--- a/test/test.sh
+++ b/test/test.sh
@@ -372,8 +372,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
     $ECHO "$YELLOW[-] llvm_mode InsTrim not compiled, cannot test"
     INCOMPLETE=1
   }
-  AFL_LLVM_INSTRUMENT=AFL
-  AFL_DEBUG=1 AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast -o test-compcov.compcov test-compcov.c > test.out 2>&1
+  AFL_LLVM_INSTRUMENT=AFL AFL_DEBUG=1 AFL_LLVM_LAF_SPLIT_SWITCHES=1 AFL_LLVM_LAF_TRANSFORM_COMPARES=1 AFL_LLVM_LAF_SPLIT_COMPARES=1 ../afl-clang-fast -o test-compcov.compcov test-compcov.c > test.out 2>&1
   test -e test-compcov.compcov && test_compcov_binary_functionality ./test-compcov.compcov && {
     grep --binary-files=text -Eq " [ 123][0-9][0-9] location| [3-9][0-9] location" test.out && {
       $ECHO "$GREEN[+] llvm_mode laf-intel/compcov feature works correctly"
@@ -386,6 +385,25 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
     CODE=1
   }
   rm -f test-compcov.compcov test.out
+  AFL_LLVM_INSTRUMENT=AFL AFL_LLVM_LAF_ALL=1 ../afl-clang-fast -o test-floatingpoint test-floatingpoint.c > test.out 2>&1
+  test -e test-floatingpoint && {
+    mkdir -p in
+    echo ZZ > in/in
+    $ECHO "$GREY[*] running afl-fuzz with floating point splitting, this will take max. 30 seconds"
+    {
+      AFL_BENCH_UNTIL_CRASH=1 AFL_NO_UI=1 ../afl-fuzz -s 123 -V30 -m ${MEM_LIMIT} -i in -o out -- ./test-floatingpoint >>errors 2>&1
+    } >>errors 2>&1
+    test -n "$( ls out/crashes/id:* 2>/dev/null )" && {
+      $ECHO "$GREEN[+] llvm_mode laf-intel floatingpoint splitting feature works correctly"
+    } || {
+      $ECHO "$RED[!] llvm_mode laf-intel floatingpoint splitting feature failed"
+      CODE=1
+    }
+  } || {
+    $ECHO "$RED[!] llvm_mode laf-intel floatingpoint splitting feature compilation failed"
+    CODE=1
+  }
+  rm -f test-floatingpoint test.out in/in
   echo foobar.c > instrumentlist.txt
   AFL_DEBUG=1 AFL_LLVM_INSTRUMENT_FILE=instrumentlist.txt ../afl-clang-fast -o test-compcov test-compcov.c > test.out 2>&1
   test -e test-compcov && test_compcov_binary_functionality ./test-compcov && {