about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile9
-rw-r--r--README.md19
-rw-r--r--TODO.md9
-rw-r--r--docs/Changelog.md28
-rw-r--r--docs/README.MOpt.md3
-rw-r--r--docs/env_variables.md16
-rw-r--r--examples/argv_fuzzing/Makefile6
-rw-r--r--examples/socket_fuzzing/Makefile6
-rw-r--r--gcc_plugin/afl-gcc-fast.c14
-rw-r--r--gcc_plugin/afl-gcc-rt.o.c12
-rw-r--r--include/afl-fuzz.h95
-rw-r--r--include/alloc-inl.h6
-rw-r--r--include/android-ashmem.h4
-rw-r--r--include/cmplog.h5
-rw-r--r--include/common.h16
-rw-r--r--include/config.h15
-rw-r--r--include/debug.h5
-rw-r--r--include/forkserver.h48
-rw-r--r--include/list.h2
-rw-r--r--include/sharedmem.h5
-rw-r--r--include/types.h2
-rw-r--r--libtokencap/GNUmakefile63
-rw-r--r--llvm_mode/GNUmakefile76
-rw-r--r--llvm_mode/README.lto.md215
-rw-r--r--llvm_mode/afl-clang-fast.c145
-rw-r--r--llvm_mode/afl-ld.c839
-rw-r--r--llvm_mode/afl-llvm-lto-instrumentation.so.cc566
-rw-r--r--llvm_mode/afl-llvm-pass.so.cc68
-rw-r--r--llvm_mode/afl-llvm-rt-lto.o.c23
-rw-r--r--llvm_mode/afl-llvm-rt.o.c236
-rw-r--r--llvm_mode/compare-transform-pass.so.cc143
-rwxr-xr-xqbdi_mode/build.sh2
-rwxr-xr-xqemu_mode/build_qemu_support.sh2
-rw-r--r--qemu_mode/patches/afl-qemu-cpu-inl.h12
-rw-r--r--qemu_mode/patches/afl-qemu-cpu-translate-inl.h5
-rw-r--r--qemu_mode/patches/afl-qemu-tcg-runtime-inl.h27
-rw-r--r--qemu_mode/patches/tcg-runtime-head.diff3
-rw-r--r--qemu_mode/unsigaction/GNUmakefile34
-rw-r--r--src/afl-analyze.c100
-rw-r--r--src/afl-common.c160
-rw-r--r--src/afl-forkserver.c391
-rw-r--r--src/afl-fuzz-bitmap.c114
-rw-r--r--src/afl-fuzz-cmplog.c478
-rw-r--r--src/afl-fuzz-extras.c12
-rw-r--r--src/afl-fuzz-init.c52
-rw-r--r--src/afl-fuzz-mutators.c20
-rw-r--r--src/afl-fuzz-one.c83
-rw-r--r--src/afl-fuzz-python.c4
-rw-r--r--src/afl-fuzz-queue.c20
-rw-r--r--src/afl-fuzz-redqueen.c240
-rw-r--r--src/afl-fuzz-run.c230
-rw-r--r--src/afl-fuzz-state.c52
-rw-r--r--src/afl-fuzz-stats.c86
-rw-r--r--src/afl-fuzz.c235
-rw-r--r--src/afl-gcc.c19
-rw-r--r--src/afl-sharedmem.c17
-rw-r--r--src/afl-showmap.c287
-rw-r--r--src/afl-tmin.c351
-rw-r--r--src/third_party/libradamsa/libradamsa.c82
-rw-r--r--src/third_party/libradamsa/radamsa.h14
-rw-r--r--test/test-compcov.c21
-rw-r--r--test/test-custom-mutator.c19
-rw-r--r--test/test-unsigaction.c50
-rwxr-xr-xtest/test.sh27
-rw-r--r--test/unittests/unit_list.c2
-rw-r--r--test/unittests/unit_maybe_alloc.c4
-rw-r--r--test/unittests/unit_preallocable.c2
-rwxr-xr-x[-rw-r--r--]unicorn_mode/build_unicorn_support.sh10
68 files changed, 2813 insertions, 3153 deletions
diff --git a/GNUmakefile b/GNUmakefile
index ecc475b3..11dfa803 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -69,7 +69,7 @@ ifneq "$(shell uname -m)" "x86_64"
 endif
 
 CFLAGS     ?= -O3 -funroll-loops $(CFLAGS_OPT)
-override CFLAGS += -Wall -g -Wno-pointer-sign \
+override CFLAGS += -Wall -g -Wno-pointer-sign -Wmissing-declarations\
 			  -I include/ -Werror -DAFL_PATH=\"$(HELPER_PATH)\" \
 			  -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\"
 
@@ -145,6 +145,11 @@ else
 	PYFLAGS=
 endif
 
+ifdef NO_PYTHON
+	PYTHON_OK=0
+	PYFLAGS=
+endif
+
 ifdef STATIC
   $(info Compiling static version of binaries)
   # Disable python for static compilation to simplify things
@@ -199,6 +204,7 @@ performance-test:	source-only
 	@cd test ; ./test-performance.sh
 
 
+# hint: make targets are also listed in the top level README.md
 help:
 	@echo "HELP --- the following make targets exist:"
 	@echo "=========================================="
@@ -359,6 +365,7 @@ code-format:
 	./.custom-format.py -i gcc_plugin/*.cc
 	./.custom-format.py -i examples/*/*.c
 	./.custom-format.py -i examples/*/*.h
+	./.custom-format.py -i test/*.c
 	./.custom-format.py -i qemu_mode/patches/*.h
 	./.custom-format.py -i qemu_mode/libcompcov/*.c
 	./.custom-format.py -i qemu_mode/libcompcov/*.cc
diff --git a/README.md b/README.md
index 8f817841..1e9b61f1 100644
--- a/README.md
+++ b/README.md
@@ -4,9 +4,9 @@
 
   ![Travis State](https://api.travis-ci.com/AFLplusplus/AFLplusplus.svg?branch=master)
 
-  Release Version: [2.63c](https://github.com/AFLplusplus/AFLplusplus/releases)
+  Release Version: [2.64c](https://github.com/AFLplusplus/AFLplusplus/releases)
 
-  Github Version: 2.63d
+  Github Version: 2.64d
 
   includes all necessary/interesting changes from Google's afl 2.56b
 
@@ -21,7 +21,7 @@
     * 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 noteable enhancements: [https://twitter.com/Dor3s/status/1154737061787660288](https://twitter.com/Dor3s/status/1154737061787660288)
+  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
 
@@ -44,7 +44,7 @@
 
   * Custom mutator by a library (instead of Python) by kyakdan
 
-  * Unicron mode which allows fuzzing of binaries from completely different platforms (integration provided by domenukk)
+  * 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
 
@@ -124,9 +124,9 @@ However, we already work on so many things that we do not have the time for
 all the big ideas.
 
 This can be your way to support and contribute to AFL++ - extend it to
-something cool
+something cool.
 
-We have an idea list in [docs/ideas.md](docs/ideas.md)
+We have an idea list in [docs/ideas.md](docs/ideas.md).
 
 For everyone who wants to contribute (and send pull requests) please read
 [CONTRIBUTING.md](CONTRIBUTING.md) before your submit.
@@ -145,7 +145,7 @@ $ sudo make install
 Note that "make distrib" also builds llvm_mode, qemu_mode, unicorn_mode and
 more. If you just want plain afl then do "make all", however compiling and
 using at least llvm_mode is highly recommended for much better results -
-hence in this case 
+hence in this case
 
 ```shell
 $ make source-only
@@ -158,6 +158,7 @@ These build targets exist:
 * binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap, radamsa
 * source-only: everything for source code fuzzing: llvm_mode, libdislocator, libtokencap, radamsa
 * distrib: everything (for both binary-only and source code fuzzing)
+* man: creates simple man pages from the help option of the programs
 * install: installs everything you have compiled with the build options above
 * clean: cleans everything. for qemu_mode and unicorn_mode it means it deletes all downloads as well
 * code-format: format the code, do this before you commit and send a PR please!
@@ -177,6 +178,7 @@ These build options exist:
 * STATIC - compile AFL++ static
 * ASAN_BUILD - compiles with memory sanitizer for debug purposes
 * PROFILING - compile with profiling information (gprof)
+* NO_PYTHON - disable python support
 * AFL_NO_X86 - if compiling on non-intel/amd platforms
 * LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian)
 
@@ -184,7 +186,7 @@ e.g.: make ASAN_BUILD=1
 
 
 Note that afl++ is faster and better the newer the compilers used are.
-Hence gcc-9 and especially llvm-9 should be the compilers of choice.
+Hence at least gcc-9 and especially llvm-9 should be the compilers of choice.
 If your distribution does not have them, you can use the Dockerfile:
 
 ```shell
@@ -350,6 +352,7 @@ 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:
diff --git a/TODO.md b/TODO.md
index c807d740..d31178c8 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,17 +1,12 @@
 # TODO list for AFL++
 
-## Roadmap 2.63
+## Roadmap 2.65
 
- - complete custom_mutator API changes and documentation
+ - AFL_MAP_SIZE for afl-llvm-pass, qemu_mode and unicorn_mode
  - fix stability calculation bug
-
-## Roadmap 2.64
-
- - context sensitive branch coverage in llvm_mode
  - random crc32 HASH_CONST per run? because with 65536 paths we have collisions
  - namespace for targets? e.g. network
  - libradamsa as a custom module?
- - laf-intel build auto-dictionary?
 
 ## Further down the road
 
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 70753fcc..9d6b5f87 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -9,6 +9,30 @@ 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.64c (release):
+  - llvm_mode LTO mode:
+    - now requires llvm11 - but compiles all targets! :)
+    - autodictionary feature added, enable with `AFL_LLVM_LTO_AUTODICTIONARY`
+    - variable map size usage
+  - afl-fuzz:
+    - variable map size support added (only LTO mode can use this)
+    - snapshot feature usage now visible in UI
+    - Now setting `-L -1` will enable MOpt in parallel to normal mutation.
+      Additionally, this allows to run dictionaries, radamsa and cmplog.
+    - fix for cmplog/redqueen mode if stdin was used
+    - fix for writing a better plot_data file
+  - qemu_mode: fix for persistent mode (which would not terminate or get stuck)
+  - compare-transform/AFL_LLVM_LAF_TRANSFORM_COMPARES now transforms also
+    static global and local variable comparisons (cannot find all though)
+  - extended forkserver: map_size and more information is communicated to
+    afl-fuzz (and afl-fuzz acts accordingly)
+  - new environment variable: AFL_MAP_SIZE to specify the size of the shared map
+  - if AFL_CC/AFL_CXX is set but empty afl compilers did fail, fixed
+    (this bug is in vanilla afl too)
+  - added NO_PYTHON flag to disable python support when building afl-fuzz
+  - more refactoring
+
+
 ### Version ++2.63c (release):
 
   ! the repository was moved from vanhauser-thc to AFLplusplus. It is now
@@ -41,7 +65,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
       easier: DEFAULT, CFG (INSTRIM), LTO, CTX, NGRAM-x (x=2-16)
     - made USE_TRACE_PC compile obsolete
   - LTO collision free instrumented added in llvm_mode with afl-clang-lto -
-    note that this mode is amazing, but quite some targets won't compile
+    this mode is amazing but requires you to build llvm 11 yourself
   - Added llvm_mode NGRAM prev_loc coverage by Adrean Herrera
     (https://github.com/adrianherrera/afl-ngram-pass/), activate by setting
     AFL_LLVM_INSTRUMENT=NGRAM-<value> or AFL_LLVM_NGRAM_SIZE=<value>
@@ -294,7 +318,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
     you use the new -p option :-) - see docs/power_schedules.md
   - added afl-system-config script to set all system performance options for fuzzing
   - llvm_mode works with llvm 3.9 up to including 8 !
-  - qemu_mode got upgraded from 2.1 to 3.1 - incorporated from 
+  - qemu_mode got upgraded from 2.1 to 3.1 - incorporated from
     https://github.com/andreafioraldi/afl and with community patches added
 
 
diff --git a/docs/README.MOpt.md b/docs/README.MOpt.md
index 94e63959..3de6d670 100644
--- a/docs/README.MOpt.md
+++ b/docs/README.MOpt.md
@@ -36,6 +36,9 @@ enter the pacemaker fuzzing mode.
 Setting 0 will enter the pacemaker fuzzing mode at first, which is
 recommended in a short time-scale evaluation. 
 
+Setting -1 will enable both pacemaker mode and normal aflmutation fuzzing in
+parallel.
+
 Other important parameters can be found in afl-fuzz.c, for instance, 
 
 'swarm_num': the number of the PSO swarms used in the fuzzing process.
diff --git a/docs/env_variables.md b/docs/env_variables.md
index cd002145..21bf9fad 100644
--- a/docs/env_variables.md
+++ b/docs/env_variables.md
@@ -111,10 +111,15 @@ Then there are a few specific features that are only available in llvm_mode:
     instrumentation which is 100% collision free (collisions are a big issue
     in afl and afl-like instrumentations). This is performed by using
     afl-clang-lto/afl-clang-lto++ instead of afl-clang-fast, but is only
-    built if LLVM 9 or newer is used.
+    built if LLVM 11 or newer is used.
 
-    None of these options are necessary to be used and are rather for manual
-    use (which only ever the author of this LTO implementation will use ;-)
+   - 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.
+
+    None of the following options are necessary to be used and are rather for
+    manual use (which only ever the author of this LTO implementation will use).
     These are used if several seperated instrumentation are performed which
     are then later combined.
 
@@ -238,6 +243,11 @@ checks or alter some of the more exotic semantics of the tool:
     normally indicated by the cycle counter in the UI turning green. May be
     convenient for some types of automated jobs.
 
+  - AFL_MAP_SIZE sets the size of the shared map that afl-fuzz, afl-showmap,
+    afl-tmin and afl-analyze create to gather instrumentation data from
+    the target. This must be equal or larger than the size the target was
+    compiled with.
+
   - Setting AFL_NO_AFFINITY disables attempts to bind to a specific CPU core
     on Linux systems. This slows things down, but lets you run more instances
     of afl-fuzz than would be prudent (if you really want to).
diff --git a/examples/argv_fuzzing/Makefile b/examples/argv_fuzzing/Makefile
index 104d0f55..cd8ebdbb 100644
--- a/examples/argv_fuzzing/Makefile
+++ b/examples/argv_fuzzing/Makefile
@@ -31,8 +31,10 @@ LDFLAGS  += $(LDFLAGS_ADD)
 M32FLAG = -m32
 M64FLAG = -m64
 
-CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep gcc; echo $$?)
-CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep arm; echo $$?)
+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)
diff --git a/examples/socket_fuzzing/Makefile b/examples/socket_fuzzing/Makefile
index 2fdc58ee..03146001 100644
--- a/examples/socket_fuzzing/Makefile
+++ b/examples/socket_fuzzing/Makefile
@@ -29,8 +29,10 @@ LDFLAGS  += $(LDFLAGS_ADD)
 M32FLAG = -m32
 M64FLAG = -m64
 
-CC_IS_GCC=$(shell $(CC) --version 2>/dev/null | grep gcc; echo $$?)
-CC_IS_ARMCOMPILER=$(shell $(CC) -v 2>&1 >/dev/null | grep arm; echo $$?)
+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)
diff --git a/gcc_plugin/afl-gcc-fast.c b/gcc_plugin/afl-gcc-fast.c
index fbda08b6..0e51ee62 100644
--- a/gcc_plugin/afl-gcc-fast.c
+++ b/gcc_plugin/afl-gcc-fast.c
@@ -121,12 +121,12 @@ static void edit_params(u32 argc, char **argv) {
   if (!strcmp(name, "afl-g++-fast")) {
 
     u8 *alt_cxx = getenv("AFL_CXX");
-    cc_params[0] = alt_cxx ? alt_cxx : (u8 *)AFL_GCC_CXX;
+    cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)AFL_GCC_CXX;
 
   } else {
 
     u8 *alt_cc = getenv("AFL_CC");
-    cc_params[0] = alt_cc ? alt_cc : (u8 *)AFL_GCC_CC;
+    cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)AFL_GCC_CC;
 
   }
 
@@ -364,6 +364,16 @@ int main(int argc, char **argv, char **envp) {
 
     be_quiet = 1;
 
+  u8 *ptr;
+  if (!be_quiet &&
+      ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE")))) {
+
+    u32 map_size = atoi(ptr);
+    if (map_size != MAP_SIZE)
+      FATAL("AFL_MAP_SIZE is not supported by afl-gcc-fast");
+
+  }
+
   check_environment_vars(envp);
 
   find_obj(argv[0]);
diff --git a/gcc_plugin/afl-gcc-rt.o.c b/gcc_plugin/afl-gcc-rt.o.c
index 30606150..0a2246e7 100644
--- a/gcc_plugin/afl-gcc-rt.o.c
+++ b/gcc_plugin/afl-gcc-rt.o.c
@@ -138,8 +138,9 @@ static void __afl_map_shm(void) {
 
 static void __afl_start_forkserver(void) {
 
-  static u8 tmp[4];
-  s32       child_pid;
+  u8  tmp[4] = {0, 0, 0, 0};
+  u32 map_size = MAP_SIZE;
+  s32 child_pid;
 
   u8 child_stopped = 0;
 
@@ -148,6 +149,13 @@ static void __afl_start_forkserver(void) {
   /* Phone home and tell the parent that we're OK. If parent isn't there,
      assume we're not running in forkserver mode and just execute program. */
 
+  if (MAP_SIZE <= 0x800000) {
+
+    map_size = (FS_OPT_ENABLED | FS_OPT_MAPSIZE | FS_OPT_SET_MAPSIZE(MAP_SIZE));
+    memcpy(tmp, &map_size, 4);
+
+  }
+
   if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
 
   while (1) {
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 56135d0e..87e6dcff 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -195,19 +195,6 @@ enum {
 
 };
 
-/* Execution status fault codes */
-
-enum {
-
-  /* 00 */ FAULT_NONE,
-  /* 01 */ FAULT_TMOUT,
-  /* 02 */ FAULT_CRASH,
-  /* 03 */ FAULT_ERROR,
-  /* 04 */ FAULT_NOINST,
-  /* 05 */ FAULT_NOBITS
-
-};
-
 #define operator_num 16
 #define swarm_num 5
 #define period_core 500000
@@ -331,7 +318,8 @@ typedef struct afl_env_vars {
   u8 afl_skip_cpufreq, afl_exit_when_done, afl_no_affinity, afl_skip_bin_check,
       afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui,
       afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one,
-      afl_bench_until_crash, afl_debug_child_output, afl_autoresume;
+      afl_bench_until_crash, afl_debug_child_output, afl_autoresume,
+      afl_cal_fast;
 
   u8 *afl_tmpdir, *afl_post_library, *afl_custom_mutator_library,
       *afl_python_module, *afl_path, *afl_hang_tmout, *afl_skip_crashes,
@@ -339,6 +327,13 @@ typedef struct afl_env_vars {
 
 } afl_env_vars_t;
 
+struct afl_pass_stat {
+
+  u8 total;
+  u8 faileds;
+
+};
+
 typedef struct afl_state {
 
   /* Position of this state in the global states list */
@@ -353,14 +348,14 @@ typedef struct afl_state {
   /* MOpt:
     Lots of globals, but mostly for the status UI and other things where it
     really makes no sense to haul them around as function parameters. */
-  u64 limit_time_puppet, orig_hit_cnt_puppet, last_limit_time_start,
-      tmp_pilot_time, total_pacemaker_time, total_puppet_find, temp_puppet_find,
-      most_time_key, most_time, most_execs_key, most_execs, old_hit_count,
-      force_ui_update;
+  u64 orig_hit_cnt_puppet, last_limit_time_start, tmp_pilot_time,
+      total_pacemaker_time, total_puppet_find, temp_puppet_find, most_time_key,
+      most_time, most_execs_key, most_execs, old_hit_count, force_ui_update;
 
   MOpt_globals_t mopt_globals_core, mopt_globals_pilot;
 
-  s32 SPLICE_CYCLES_puppet, limit_time_sig, key_puppet, key_module;
+  s32 limit_time_puppet, SPLICE_CYCLES_puppet, limit_time_sig, key_puppet,
+      key_module;
 
   double w_init, w_end, w_now;
 
@@ -425,7 +420,6 @@ typedef struct afl_state {
       use_splicing,                     /* Recombine input files?           */
       dumb_mode,                        /* Run in non-instrumented mode?    */
       score_changed,                    /* Scoring for favorites changed?   */
-      kill_signal,                      /* Signal that killed the child     */
       resuming_fuzz,                    /* Resuming an older fuzzing job?   */
       timeout_given,                    /* Specific timeout given?          */
       not_on_tty,                       /* stdout is not a tty              */
@@ -439,7 +433,6 @@ typedef struct afl_state {
       no_arith,                         /* Skip most arithmetic ops         */
       shuffle_queue,                    /* Shuffle input queue?             */
       bitmap_changed,                   /* Time to update bitmap?           */
-      qemu_mode,                        /* Running in QEMU mode?            */
       unicorn_mode,                     /* Running in Unicorn mode?         */
       use_wine,                         /* Use WINE with QEMU mode          */
       skip_requested,                   /* Skip request, via SIGUSR1        */
@@ -450,11 +443,11 @@ typedef struct afl_state {
       fast_cal,                         /* Try to calibrate faster?         */
       disable_trim;                     /* Never trim in fuzz_one           */
 
-  u8 virgin_bits[MAP_SIZE],             /* Regions yet untouched by fuzzing */
-      virgin_tmout[MAP_SIZE],           /* Bits we haven't seen in tmouts   */
-      virgin_crash[MAP_SIZE];           /* Bits we haven't seen in crashes  */
+  u8 *virgin_bits,                      /* Regions yet untouched by fuzzing */
+      *virgin_tmout,                    /* Bits we haven't seen in tmouts   */
+      *virgin_crash;                    /* Bits we haven't seen in crashes  */
 
-  u8 var_bytes[MAP_SIZE];               /* Bytes that appear to be variable */
+  u8 *var_bytes;                        /* Bytes that appear to be variable */
 
   volatile u8 stop_soon,                /* Ctrl-C pressed?                  */
       clear_screen;                     /* Window resized?                  */
@@ -481,7 +474,6 @@ typedef struct afl_state {
       total_tmouts,                     /* Total number of timeouts         */
       unique_tmouts,                    /* Timeouts with unique signatures  */
       unique_hangs,                     /* Hangs with unique signatures     */
-      total_execs,                      /* Total execve() calls             */
       last_crash_execs,                 /* Exec counter at last crash       */
       queue_cycle,                      /* Queue round counter              */
       cycles_wo_finds,                  /* Cycles without any new paths     */
@@ -543,7 +535,7 @@ typedef struct afl_state {
       *queue_top,                       /* Top of the list                  */
       *q_prev100;                       /* Previous 100 marker              */
 
-  struct queue_entry *top_rated[MAP_SIZE];  /* Top entries for bitmap bytes */
+  struct queue_entry **top_rated;           /* Top entries for bitmap bytes */
 
   struct extra_data *extras;            /* Extra tokens to fuzz with        */
   u32                extras_cnt;        /* Total number of tokens read      */
@@ -559,8 +551,8 @@ typedef struct afl_state {
 
   /* CmpLog */
 
-  char *cmplog_binary;
-  s32   cmplog_child_pid, cmplog_fsrv_pid;
+  char *           cmplog_binary;
+  afl_forkserver_t cmplog_fsrv;     /* cmplog has its own little forkserver */
 
   /* Custom mutators */
   struct custom_mutator *mutator;
@@ -569,6 +561,9 @@ typedef struct afl_state {
   s32 cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd;
   u32 cmplog_prev_timed_out;
 
+  struct afl_pass_stat *pass_stats;
+  struct cmp_map *      orig_cmp_map;
+
   u8 describe_op_buf_256[256]; /* describe_op will use this to return a string
                                   up to 256 */
 
@@ -577,7 +572,9 @@ typedef struct afl_state {
   u32 document_counter;
 #endif
 
-  /* statis file */
+  void *maybe_add_auto;
+
+  /* statistics file */
   double last_bitmap_cvg, last_stability, last_eps;
 
   /* plot file saves from last run */
@@ -587,9 +584,9 @@ typedef struct afl_state {
   u64 stats_last_stats_ms, stats_last_plot_ms, stats_last_ms, stats_last_execs;
   double stats_avg_exec;
 
-  u8 clean_trace[MAP_SIZE];
-  u8 clean_trace_custom[MAP_SIZE];
-  u8 first_trace[MAP_SIZE];
+  u8 *clean_trace;
+  u8 *clean_trace_custom;
+  u8 *first_trace;
 
   /*needed for afl_fuzz_one */
   // TODO: see which we can reuse
@@ -611,6 +608,9 @@ typedef struct afl_state {
   u8 *   ex_buf;
   size_t ex_size;
 
+  /* this is a fixed buffer of size map_size that can be used by any function if they do not call another function */
+  u8 *   map_tmp_buf;
+
 } afl_state_t;
 
 /* A global pointer to all instances is needed (for now) for signals to arrive
@@ -797,7 +797,7 @@ struct custom_mutator {
 
 };
 
-void afl_state_init(afl_state_t *);
+void afl_state_init(afl_state_t *, uint32_t map_size);
 void afl_state_deinit(afl_state_t *);
 void read_afl_environment(afl_state_t *, char **);
 
@@ -811,6 +811,7 @@ u8   trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf);
 /* Python */
 #ifdef USE_PYTHON
 
+void load_custom_mutator_py(afl_state_t *, char *);
 void finalize_py_module(void *);
 
 size_t pre_save_py(void *, u8 *, size_t, u8 **);
@@ -838,20 +839,19 @@ u32  calculate_score(afl_state_t *, struct queue_entry *);
 
 /* Bitmap */
 
-void read_bitmap(afl_state_t *, u8 *);
 void write_bitmap(afl_state_t *);
-u32  count_bits(u8 *);
-u32  count_bytes(u8 *);
-u32  count_non_255_bytes(u8 *);
+u32  count_bits(afl_state_t *, u8 *);
+u32  count_bytes(afl_state_t *, u8 *);
+u32  count_non_255_bytes(afl_state_t *, u8 *);
 #ifdef WORD_SIZE_64
-void simplify_trace(u64 *);
-void classify_counts(u64 *);
+void simplify_trace(afl_state_t *, u64 *);
+void classify_counts(afl_forkserver_t *);
 #else
-void simplify_trace(u32 *);
-void classify_counts(u32 *);
+void simplify_trace(afl_state_t *, u32 *);
+void classify_counts(afl_forkserver_t *);
 #endif
 void init_count_class16(void);
-void minimize_bits(u8 *, u8 *);
+void minimize_bits(afl_state_t *, u8 *, u8 *);
 #ifndef SIMPLE_FILES
 u8 *describe_op(afl_state_t *, u8);
 #endif
@@ -862,7 +862,7 @@ u8 has_new_bits(afl_state_t *, u8 *);
 
 void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32);
 void load_extras(afl_state_t *, u8 *);
-void maybe_add_auto(afl_state_t *, u8 *, u32);
+void maybe_add_auto(void *, u8 *, u32);
 void save_auto(afl_state_t *);
 void load_auto(afl_state_t *);
 void destroy_extras(afl_state_t *);
@@ -876,8 +876,8 @@ void show_init_stats(afl_state_t *);
 
 /* Run */
 
-u8   run_target(afl_state_t *, u32);
-void write_to_testcase(afl_state_t *, void *, u32);
+fsrv_run_result_t fuzz_run_target(afl_state_t *, afl_forkserver_t *fsrv, u32);
+void              write_to_testcase(afl_state_t *, void *, u32);
 u8   calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8);
 void sync_fuzzers(afl_state_t *);
 u8   trim_case(afl_state_t *, struct queue_entry *, u8 *);
@@ -920,8 +920,7 @@ void   save_cmdline(afl_state_t *, u32, char **);
 
 /* CmpLog */
 
-void init_cmplog_forkserver(afl_state_t *afl);
-u8   common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len);
+u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len);
 
 /* RedQueen */
 u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len,
diff --git a/include/alloc-inl.h b/include/alloc-inl.h
index 89889cc5..d16e84bb 100644
--- a/include/alloc-inl.h
+++ b/include/alloc-inl.h
@@ -85,7 +85,7 @@
 
 static inline void *DFL_ck_alloc_nozero(u32 size) {
 
-  u8 *ret;
+  void *ret;
 
   if (!size) return NULL;
 
@@ -127,7 +127,7 @@ static inline void DFL_ck_free(void *mem) {
 
 static inline void *DFL_ck_realloc(void *orig, u32 size) {
 
-  u8 *ret;
+  void *ret;
 
   if (!size) {
 
@@ -182,7 +182,7 @@ static inline u8 *DFL_ck_strdup(u8 *str) {
 
 static inline void *DFL_ck_memdup(void *mem, u32 size) {
 
-  u8 *ret;
+  void *ret;
 
   if (!mem || !size) return NULL;
 
diff --git a/include/android-ashmem.h b/include/android-ashmem.h
index 3a0b9969..6fdcb1ba 100644
--- a/include/android-ashmem.h
+++ b/include/android-ashmem.h
@@ -26,6 +26,8 @@
 #ifndef _ANDROID_ASHMEM_H
 #define _ANDROID_ASHMEM_H
 
+#ifdef __ANDROID__
+
 #include <fcntl.h>
 #include <linux/shm.h>
 #include <linux/ashmem.h>
@@ -103,5 +105,7 @@ static inline void *shmat(int __shmid, const void *__shmaddr, int __shmflg) {
 
 }
 
+#endif /* __ANDROID__ */
+
 #endif
 
diff --git a/include/cmplog.h b/include/cmplog.h
index 36f8f2c5..74e6a3bb 100644
--- a/include/cmplog.h
+++ b/include/cmplog.h
@@ -29,6 +29,7 @@
 #define _AFL_CMPLOG_H
 
 #include "config.h"
+#include "forkserver.h"
 
 #define CMP_MAP_W 65536
 #define CMP_MAP_H 256
@@ -74,5 +75,9 @@ struct cmp_map {
 
 };
 
+/* Execs the child */
+
+void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv);
+
 #endif
 
diff --git a/include/common.h b/include/common.h
index c9436e81..70ff0744 100644
--- a/include/common.h
+++ b/include/common.h
@@ -51,6 +51,16 @@ char * get_afl_env(char *env);
 extern u8  be_quiet;
 extern u8 *doc_path;                    /* path to documentation dir        */
 
+/* Find binary, used by analyze, showmap, tmin
+   @returns the path, allocating the string */
+
+u8 *find_binary(u8 *fname);
+
+/* Read a bitmap from file fname to memory
+   This is for the -B option again. */
+
+void read_bitmap(u8 *fname, u8 *map, size_t len);
+
 /* Get unix time in milliseconds */
 
 u64 get_cur_time(void);
@@ -99,9 +109,13 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms);
 
 /* Wrapper for select() and read(), reading exactly len bytes.
   Returns the time passed to read.
+  stop_soon should point to a variable indicating ctrl+c was pressed.
   If the wait times out, returns timeout_ms + 1;
   Returns 0 if an error occurred (fd closed, signal, ...); */
-u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms);
+u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms,
+               volatile u8 *stop_soon_p);
+
+u32 get_map_size();
 
 #endif
 
diff --git a/include/config.h b/include/config.h
index 6b50be60..1de9973b 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.63c"
+#define VERSION "++2.64c"
 
 /******************************************************
  *                                                    *
@@ -201,8 +201,8 @@
    (first value), and to keep in memory as candidates. The latter should be much
    higher than the former. */
 
-#define USE_AUTO_EXTRAS 50
-#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 10)
+#define USE_AUTO_EXTRAS 128
+#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 64)
 
 /* Scaling factor for the effector map used to skip some of the more
    expensive deterministic steps. The actual divisor is set to
@@ -400,5 +400,14 @@
 #endif
 #endif                           /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */
 
+/* Extended forkserver option values */
+
+#define FS_OPT_ENABLED 0x8f000001
+#define FS_OPT_MAPSIZE 0x40000000
+#define FS_OPT_SNAPSHOT 0x20000000
+#define FS_OPT_AUTODICT 0x10000000
+#define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1)
+#define FS_OPT_SET_MAPSIZE(x) (x <= 1 || x > 0x1000000 ? 0 : ((x - 1) << 1))
+
 #endif                                                  /* ! _HAVE_CONFIG_H */
 
diff --git a/include/debug.h b/include/debug.h
index ff2845f9..4cce56b5 100644
--- a/include/debug.h
+++ b/include/debug.h
@@ -28,6 +28,11 @@
 #include "types.h"
 #include "config.h"
 
+/* __FUNCTION__ is non-iso */
+#ifdef __func__
+#define __FUNCTION__ __func__
+#endif
+
 /*******************
  * Terminal colors *
  *******************/
diff --git a/include/forkserver.h b/include/forkserver.h
index 5d1bd2cf..18a287ad 100644
--- a/include/forkserver.h
+++ b/include/forkserver.h
@@ -29,7 +29,9 @@
 #define __AFL_FORKSERVER_H
 
 #include <stdio.h>
+#include <stdbool.h>
 
+#include "types.h"
 typedef struct afl_forkserver {
 
   /* a program that includes afl-forkserver needs to define these */
@@ -50,26 +52,60 @@ typedef struct afl_forkserver {
       fsrv_ctl_fd,                      /* Fork server control pipe (write) */
       fsrv_st_fd;                       /* Fork server status pipe (read)   */
 
+  u8 no_unlink;                         /* do not unlink cur_input          */
+
   u32 exec_tmout;                       /* Configurable exec timeout (ms)   */
+  u32 map_size;                         /* map size used by the target      */
+  u32 snapshot;                         /* is snapshot feature used         */
   u64 mem_limit;                        /* Memory cap for child (MB)        */
 
+  u64 total_execs;                      /* How often run_target was called  */
+
   u8 *out_file,                         /* File to fuzz, if any             */
-      *target_path;                                   /* Path of the target */
+      *target_path;                     /* Path of the target               */
 
   FILE *plot_file;                      /* Gnuplot output file              */
 
-  u8 child_timed_out;                   /* Traced process timed out?        */
+  /* Note: lat_run_timed_out is u32 to send it to the child as 4 byte array */
+  u32 last_run_timed_out;               /* Traced process timed out?        */
+
+  u8 last_kill_signal;                  /* Signal that killed the child     */
 
   u8 use_fauxsrv;                       /* Fauxsrv for non-forking targets? */
 
-  u32 prev_timed_out;                   /* if prev forkserver run timed out */
+  u8 qemu_mode;                         /* if running in qemu mode or not   */
+
+  char *cmplog_binary;                  /* the name of the cmplog binary    */
+
+  /* Function to kick off the forkserver child */
+  void (*init_child_func)(struct afl_forkserver *fsrv, char **argv);
+
+  u8 *function_opt;                     /* for autodictionary: afl ptr      */
+
+  void (*function_ptr)(void *afl_tmp, u8 *mem, u32 len);
 
 } afl_forkserver_t;
 
+typedef enum fsrv_run_result {
+
+  /* 00 */ FSRV_RUN_OK = 0,
+  /* 01 */ FSRV_RUN_TMOUT,
+  /* 02 */ FSRV_RUN_CRASH,
+  /* 03 */ FSRV_RUN_ERROR,
+  /* 04 */ FSRV_RUN_NOINST,
+  /* 05 */ FSRV_RUN_NOBITS,
+
+} fsrv_run_result_t;
+
 void afl_fsrv_init(afl_forkserver_t *fsrv);
-void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv);
-void afl_fsrv_deinit(afl_forkserver_t *fsrv);
-void afl_fsrv_killall();
+void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from);
+void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
+                    volatile u8 *stop_soon_p, u8 debug_child_output);
+void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len);
+fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
+                                      volatile u8 *stop_soon_p);
+void              afl_fsrv_killall(void);
+void              afl_fsrv_deinit(afl_forkserver_t *fsrv);
 
 #ifdef __APPLE__
 #define MSG_FORK_ON_APPLE                                                    \
diff --git a/include/list.h b/include/list.h
index e93b4e8f..bb985c4f 100644
--- a/include/list.h
+++ b/include/list.h
@@ -50,7 +50,7 @@ typedef struct list_element {
 typedef struct list {
 
   element_t element_prealloc_buf[LIST_PREALLOC_SIZE];
-  u32       element_prealloc_count;
+  s32       element_prealloc_count;
 
 } list_t;
 
diff --git a/include/sharedmem.h b/include/sharedmem.h
index 57ab6cf0..066a9904 100644
--- a/include/sharedmem.h
+++ b/include/sharedmem.h
@@ -28,6 +28,8 @@
 #ifndef __AFL_SHAREDMEM_H
 #define __AFL_SHAREDMEM_H
 
+#include "types.h"
+
 typedef struct sharedmem {
 
   // extern unsigned char *trace_bits;
@@ -44,8 +46,7 @@ typedef struct sharedmem {
 
   u8 *map;                                          /* shared memory region */
 
-  size_t size_alloc;                               /* actual allocated size */
-  size_t size_used;                                  /* in use by shmem app */
+  size_t map_size;                                 /* actual allocated size */
 
   int             cmplog_mode;
   struct cmp_map *cmp_map;
diff --git a/include/types.h b/include/types.h
index da95cb39..f2a12953 100644
--- a/include/types.h
+++ b/include/types.h
@@ -46,7 +46,7 @@ typedef uint32_t u32;
 
  */
 
-#ifdef __x86_64__
+#if defined(__x86_64__) || defined(__aarch64__)
 typedef unsigned long long u64;
 #else
 typedef uint64_t u64;
diff --git a/libtokencap/GNUmakefile b/libtokencap/GNUmakefile
deleted file mode 100644
index 5fcd7731..00000000
--- a/libtokencap/GNUmakefile
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# american fuzzy lop++ - libtokencap
-# --------------------------------
-#
-# Originally written by Michal Zalewski
-#
-# Copyright 2016 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
-#
-
-PREFIX      ?= /usr/local
-HELPER_PATH  = $(PREFIX)/lib/afl
-DOC_PATH    ?= $(PREFIX)/share/doc/afl
-MAN_PATH    ?= $(PREFIX)/man/man8
-
-VERSION     = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2)
-
-CFLAGS      ?= -O3 -funroll-loops
-override CFLAGS += -I ../include/ -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign
-
-ifeq "$(shell uname)" "Linux"
-  TARGETS = libtokencap.so
-  LDFLAGS     += -ldl
-endif
-ifeq "$(shell uname)" "Darwin"
-  TARGETS = libtokencap.so
-  LDFLAGS     += -ldl
-endif
-ifeq "$(shell uname)" "FreeBSD"
-  TARGETS = libtokencap.so
-endif
-ifeq "$(shell uname)" "OpenBSD"
-  TARGETS = libtokencap.so
-endif
-ifeq "$(shell uname)" "NetBSD"
-  TARGETS = libtokencap.so
-endif
-ifeq "$(shell uname)" "DragonFly"
-  TARGETS = libtokencap.so
-  LDFLAGS     += -ldl
-endif
-all: $(TARGETS)
-
-VPATH = ..
-libtokencap.so: libtokencap.so.c ../config.h
-	$(CC) $(CFLAGS) -shared -fPIC $< -o ../$@ $(LDFLAGS)
-
-.NOTPARALLEL: clean
-
-clean:
-	rm -f *.o *.so *~ a.out core core.[1-9][0-9]*
-	rm -f ../libtokencap.so
-
-install: all
-	install -m 755 -d $${DESTDIR}$(HELPER_PATH)
-	install -m 755 ../libtokencap.so $${DESTDIR}$(HELPER_PATH)
-	install -m 644 -T README.md $${DESTDIR}$(DOC_PATH)/README.tokencap.md
-
diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile
index e3708efa..67c31f14 100644
--- a/llvm_mode/GNUmakefile
+++ b/llvm_mode/GNUmakefile
@@ -58,19 +58,20 @@ endif
 
 ifeq "$(LLVM_MAJOR)" "9"
   $(info [+] llvm_mode detected llvm 9, enabling neverZero implementation)
-  $(info [+] llvm_mode detected llvm 9, enabling afl-clang-lto LTO implementation)
-  LLVM_LTO = 1
 endif
 
 ifeq "$(LLVM_NEW_API)" "1"
   $(info [+] llvm_mode detected llvm 10+, enabling neverZero implementation and c++14)
-  $(info [+] llvm_mode detected llvm 9, enabling afl-clang-lto LTO implementation)
   LLVM_STDCXX = c++14
+endif
+
+ifeq "$(LLVM_MAJOR)" "11"
+  $(info [+] llvm_mode detected llvm 11, enabling afl-clang-lto LTO implementation)
   LLVM_LTO = 1
 endif
 
 ifeq "$(LLVM_LTO)" "0"
-  $(info [+] llvm_mode detected llvm < 9, afl-clang-lto LTO will not be build.)
+  $(info [+] llvm_mode detected llvm < 11, afl-clang-lto LTO will not be build.)
 endif
 
 ifeq "$(LLVM_APPLE)" "1"
@@ -81,8 +82,8 @@ endif
 # this seems to be busted on some distros, so using the one in $PATH is
 # probably better.
 
-CC         = $(LLVM_BINDIR)/clang
-CXX        = $(LLVM_BINDIR)/clang++
+CC         ?= $(LLVM_BINDIR)/clang
+CXX        ?= $(LLVM_BINDIR)/clang++
 
 ifeq "$(shell test -e $(CC) || echo 1 )" "1"
   # llvm-config --bindir may not providing a valid path, so ...
@@ -125,14 +126,18 @@ else
  endif
 endif
 
-ifneq "$(AFL_CLANG_FLTO)" ""
-ifeq "$(AFL_REAL_LD)" ""
-  AFL_REAL_LD = $(shell readlink /bin/ld 2>/dev/null)
-  ifeq "$(AFL_REAL_LD)" ""
-    AFL_REAL_LD = $(shell readlink /usr/bin/ld 2>/dev/null)
+ifeq "$(LLVM_LTO)" "1"
+  ifneq "$(AFL_CLANG_FLTO)" ""
+    ifeq "$(AFL_REAL_LD)" ""
+      ifneq "$(shell readlink $(LLVM_BINDIR)/ld.lld 2>&1)" ""
+        AFL_REAL_LD = $(LLVM_BINDIR)/ld.lld
+      else
+        $(warn ld.lld not found, can not enable LTO mode)
+        LLVM_LTO = 0
+      endif
+    endif
   endif
 endif
-endif
 
 AFL_CLANG_FUSELD=
 ifneq "$(AFL_CLANG_FLTO)" ""
@@ -141,13 +146,27 @@ ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -fuse-ld=`command -v
 endif
 endif
 
+CLANG_BIN = $(basename $(CC))
+CLANGPP_BIN = $(basename $(CXX))
+ifeq "$(shell test -e $(CLANG_BIN) || echo 1 )" "1"
+  CLANG_BIN = $(CC)
+  CLANGPP_BIN = $(CXX)
+endif
+
+ifeq "$(CC)" "$(LLVM_BINDIR)/clang"
+  USE_BINDIR = 1
+else
+  USE_BINDIR = 0
+endif
+
 CFLAGS          ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2
-override CFLAGS = -Wall \
+override CFLAGS += -Wall \
                -g -Wno-pointer-sign -I ../include/ \
                -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
                -DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \
                -DLLVM_VERSION=\"$(LLVMVER)\"  -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \
-               -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" -Wno-unused-function
+               -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \
+               -DCLANG_BIN=\"$(CC)\" -DCLANGPP_BIN=\"$(CXX)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function
 ifdef AFL_TRACE_PC
   $(info Compile option AFL_TRACE_PC is deprecated, just set AFL_LLVM_INSTRUMENT=PCGUARD to activate when compiling targets )
 endif
@@ -183,7 +202,7 @@ ifeq "$(TEST_MMAP)" "1"
         LDFLAGS += -lrt
 endif
 
-  PROGS      = ../afl-clang-fast ../afl-ld ../afl-llvm-pass.so ../afl-llvm-lto-whitelist.so ../afl-llvm-lto-instrumentation.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so
+  PROGS      = ../afl-clang-fast ../afl-llvm-pass.so ../afl-llvm-lto-whitelist.so ../afl-llvm-lto-instrumentation.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so
 
 # If prerequisites are not given, warn, do not build anything, and exit with code 0
 ifeq "$(LLVMVER)" ""
@@ -251,16 +270,6 @@ ifeq "$(LLVM_LTO)" "1"
 endif
 endif
 
-../afl-ld: afl-ld.c
-ifneq "$(AFL_CLANG_FLTO)" ""
-ifeq "$(LLVM_LTO)" "1"
-	$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
-	ln -sf afl-ld ../ld
-	@rm -f .test-instr
-	@-export AFL_QUIET=1 AFL_PATH=.. PATH="..:$(PATH)" ; ../afl-clang-lto -Wl,--afl -o .test-instr ../test-instr.c && echo "[+] afl-clang-lto and afl-ld seem to work fine :)" || echo "[!] WARNING: clang seems to have a hardcoded "'/bin/ld'" - check README.lto"
-	@rm -f .test-instr
-endif
-endif
 ../libLLVMInsTrim.so: LLVMInsTrim.so.cc MarkNodes.cc | test_deps
 	-$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL)
 
@@ -275,9 +284,12 @@ ifeq "$(LLVM_LTO)" "1"
 	$(CXX) $(CLANG_CFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL)
 endif
 
-../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc MarkNodes.cc
+../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc
 ifeq "$(LLVM_LTO)" "1"
-	$(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL)
+	$(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL)
+	$(CC) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o
+	@$(CC) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
+	@$(CC) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi
 endif
 
 # laf
@@ -296,15 +308,15 @@ endif
 	$(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL)
 
 ../afl-llvm-rt.o: afl-llvm-rt.o.c | test_deps
-	$(CC) $(CFLAGS) -fPIC -c $< -o $@
+	$(CC) $(CFLAGS) -Wno-unused-result -fPIC -c $< -o $@
 
 ../afl-llvm-rt-32.o: afl-llvm-rt.o.c | test_deps
 	@printf "[*] Building 32-bit variant of the runtime (-m32)... "
-	@$(CC) $(CFLAGS) -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
+	@$(CC) $(CFLAGS) -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
 
 ../afl-llvm-rt-64.o: afl-llvm-rt.o.c | test_deps
 	@printf "[*] Building 64-bit variant of the runtime (-m64)... "
-	@$(CC) $(CFLAGS) -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
+	@$(CC) $(CFLAGS) -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi
 
 test_build: $(PROGS)
 	@echo "[*] Testing the CC wrapper and instrumentation output..."
@@ -323,7 +335,7 @@ all_done: test_build
 install: all
 	install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH)
 	if [ -f ../afl-clang-fast -a -f ../libLLVMInsTrim.so -a -f ../afl-llvm-rt.o ]; then set -e; install -m 755 ../afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 ../libLLVMInsTrim.so ../afl-llvm-pass.so ../afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi
-	if [ -f ../afl-clang-lto -a -f ../afl-ld ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-ld $${DESTDIR}$(HELPER_PATH); ln -sf afl-ld $${DESTDIR}$(HELPER_PATH)/ld; install -m 755 ../afl-llvm-lto-instrumentation.so $${DESTDIR}$(HELPER_PATH); install -m 755 ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_PATH); fi
+	if [ -f ../afl-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so ../afl-llvm-rt-lto*.o ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_PATH); fi
 	if [ -f ../afl-llvm-rt-32.o ]; then set -e; install -m 755 ../afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
 	if [ -f ../afl-llvm-rt-64.o ]; then set -e; install -m 755 ../afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi
 	if [ -f ../compare-transform-pass.so ]; then set -e; install -m 755 ../compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi
@@ -363,4 +375,4 @@ endif
 
 clean:
 	rm -f *.o *.so *~ a.out core core.[1-9][0-9]* .test2 test-instr .test-instr0 .test-instr1 *.dwo
-	rm -f $(PROGS) afl-common.o ../afl-clang-fast++ ../afl-clang-lto ../afl-clang-lto++ ../afl-clang*.8 ../ld
+	rm -f $(PROGS) afl-common.o ../afl-clang-fast++ ../afl-clang-lto ../afl-clang-lto++ ../afl-clang*.8 ../ld ../afl-ld ../afl-llvm-rt*.o
diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md
index 28b3b045..9af9ffff 100644
--- a/llvm_mode/README.lto.md
+++ b/llvm_mode/README.lto.md
@@ -2,31 +2,32 @@
 
 ## TLDR;
 
-1. This compile mode is very frickle if it works it is amazing, if it fails
-   - well use afl-clang-fast
+This version requires a current llvm 11 compiled from the github master.
 
-2. Use afl-clang-lto/afl-clang-lto++ because it is faster and gives better
+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
 
-3. You can use it together with llvm_mode: laf-intel and whitelisting
+2. You can use it together with llvm_mode: laf-intel and whitelisting
    features and can be combined with cmplog/Redqueen
 
-4. It only works with llvm 9 (and likely 10+ but is not tested there yet)
+3. It only works with llvm 11 (current github master state)
+
+4. AUTODICTIONARY feature! see below
 
 ## Introduction and problem description
 
 A big issue with how afl/afl++ works is that the basic block IDs that are
-set during compilation are random - and hence natually the larger the number
-of instrumented locations, the higher the number of edge collisions in the
+set during compilation are random - and hence naturally the larger the number
+of instrumented locations, the higher the number of edge collisions are in the
 map. This can result in not discovering new paths and therefore degrade the
-efficiency of the fuzzing.
+efficiency of the fuzzing process.
 
-*This issue is understimated in the fuzzing community!*
+*This issue is underestimated in the fuzzing community!*
 With a 2^16 = 64kb standard map at already 256 instrumented blocks there is
 on average one collision. On average a target has 10.000 to 50.000
 instrumented blocks hence the real collisions are between 750-18.000!
 
-To get to a solution that prevents any collision took several approaches
+To reach a solution that prevents any collisions took several approaches
 and many dead ends until we got to this:
 
  * We instrument at link time when we have all files pre-compiled
@@ -34,38 +35,48 @@ and many dead ends until we got to this:
  * Our compiler (afl-clang-lto/afl-clang-lto++) takes care of setting the
    correct LTO options and runs our own afl-ld linker instead of the system
    linker
- * Our linker collects all LTO files to link and instruments them so that
+ * The LLVM linker collects all LTO files to link and instruments them so that
    we have non-colliding edge overage
  * We use a new (for afl) edge coverage - which is the same as in llvm
    -fsanitize=coverage edge coverage mode :)
- * after inserting our instrumentation in all interesting edges we link
-   all parts of the program together to our executable
 
 The result:
- * 10-15% speed gain compared to llvm_mode
+ * 10-20% speed gain compared to llvm_mode
  * guaranteed non-colliding edge coverage :-)
  * The compile time especially for libraries can be longer
 
 Example build output from a libtiff build:
 ```
-/bin/bash ../libtool  --tag=CC   --mode=link afl-clang-lto  -g -O2 -Wall -W   -o thumbnail thumbnail.o ../libtiff/libtiff.la ../port/libport.la -llzma -ljbig -ljpeg -lz -lm 
 libtool: link: afl-clang-lto -g -O2 -Wall -W -o thumbnail thumbnail.o  ../libtiff/.libs/libtiff.a ../port/.libs/libport.a -llzma -ljbig -ljpeg -lz -lm
-afl-clang-lto++2.62d by Marc "vanHauser" Heuse <mh@mh-sec.de>
-afl-ld++2.62d by Marc "vanHauser" Heuse <mh@mh-sec.de> (level 0)
-[+] Running ar unpacker on /prg/tests/lto/tiff-4.0.4/tools/../libtiff/.libs/libtiff.a into /tmp/.afl-3914343-1583339800.dir
-[+] Running ar unpacker on /prg/tests/lto/tiff-4.0.4/tools/../port/.libs/libport.a into /tmp/.afl-3914343-1583339800.dir
-[+] Running bitcode linker, creating /tmp/.afl-3914343-1583339800-1.ll
-[+] Performing optimization via opt, creating /tmp/.afl-3914343-1583339800-2.bc
-[+] Performing instrumentation via opt, creating /tmp/.afl-3914343-1583339800-3.bc
-afl-llvm-lto++2.62d by Marc "vanHauser" Heuse <mh@mh-sec.de>
-[+] Instrumented 15833 locations with no collisions (on average 1767 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode).
-[+] Running real linker /bin/x86_64-linux-gnu-ld
-[+] Linker was successful
+afl-clang-lto++2.63d by Marc "vanHauser" Heuse <mh@mh-sec.de> in mode LTO
+afl-llvm-lto++2.63d by Marc "vanHauser" Heuse <mh@mh-sec.de>
+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).
+```
+
+## Building llvm 11
+
+```
+$ sudo apt install binutils-dev  # this is *essential*!
+$ git clone https://github.com/llvm/llvm-project
+$ cd llvm-project
+$ mkdir build
+$ cd build
+$ cmake -DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra;compiler-rt;libclc;libcxx;libcxxabi;libunwind;lld' -DCMAKE_BUILD_TYPE=Release -DLLVM_BINUTILS_INCDIR=/usr/include/ ../llvm/
+$ make -j $(nproc)
+$ export PATH=`pwd`/bin:$PATH
+$ export LLVM_CONFIG=`pwd`/bin/llcm-config
+$ cd /path/to/AFLplusplus/
+$ make
+$ cd llvm_mode
+$ make
+$ cd ..
+$ make install
 ```
 
 ## How to use afl-clang-lto
 
-Just use afl-clang-lto like you did afl-clang-fast or afl-gcc.
+Just use afl-clang-lto like you did with afl-clang-fast or afl-gcc.
 
 Also whitelisting (AFL_LLVM_WHITELIST -> [README.whitelist.md](README.whitelist.md)) and
 laf-intel/compcov (AFL_LLVM_LAF_* -> [README.laf-intel.md](README.laf-intel.md)) work.
@@ -77,6 +88,13 @@ CC=afl-clang-lto CXX=afl-clang-lto++ ./configure
 make
 ```
 
+## 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.
+
 ## Potential issues
 
 ### compiling libraries fails
@@ -94,145 +112,16 @@ AR=llvm-ar RANLIB=llvm-ranlib CC=afl-clang-lto CXX=afl-clang-lto++ ./configure -
 ```
 and on some target you have to to AR=/RANLIB= even for make as the configure script does not save it ...
 
-### "linking globals named '...': symbol multiply defined" error
-
-The target program is using multiple global variables or functions with the
-same name. This is a common error when compiling a project with LTO, and
-the fix is `-Wl,--allow-multiple-definition` - however llvm-link which we
-need to link all llvm IR LTO files does not support this - yet (hopefully).
-Hence if you see this error either you have to remove the duplicate global
-variable (think `#ifdef` ...) or you are out of luck. :-(
-
-### "expected top-level entity" + binary ouput error
-
-This happens if multiple .a archives are to be linked and they contain the
-same object filenames, the first in LTO form, the other in ELF form.
-This can not be fixed programmatically, but can be fixed by hand.
-You can try to delete the file from either archive
-(`llvm-ar d <archive>.a <file>.o`) or performing the llvm-linking, optimizing
-and instrumentation by hand (see below).
-
-### "undefined reference to ..."
-
-This *can* be the opposite situation of the "expected top-level entity" error -
-the library with the ELF file is before the LTO library.
-However it can also be a bug in the program - try to compile it normally. If 
-fails then it is a bug in the program.
-Solutions: You can try to delete the file from either archive, e.g.
-(`llvm-ar d <archive>.a <file>.o`) or performing the llvm-linking, optimizing
-and instrumentation by hand (see below).
-
-### "File format not recognized"
-
-This happens if the build system has fixed LDFLAGS, CPPFLAGS, CXXFLAGS and/or
-CFLAGS. Ensure that they all contain the `-flto` flag that afl-clang-lto was
-compiled with (you can see that by typing `afl-clang-lto -h` and inspecting
-the last line of the help output) and add them otherwise
-
-### clang is hardcoded to /bin/ld
-
-Some clang packages have 'ld' hardcoded to /bin/ld. This is an issue as this
-prevents "our" afl-ld being called.
-
--fuse-ld=/path/to/afl-ld should be set through makefile magic in llvm_mode - 
-if it is supported - however if this fails you can try:
-```
-LDFLAGS=-fuse-ld=</path/to/afl-ld
-```
-
-As workaround attempt #2 you will have to switch /bin/ld:
-```
-  mv /bin/ld /bin/ld.orig
-  cp afl-ld /bin/ld
-```
-This can result in two problems though:
-
- !1!
-  When compiling afl-ld, the build process looks at where the /bin/ld link
-  is going to. So when the workaround was applied and a recompiling afl-ld
-  is performed then the link is gone and the new afl-ld clueless where
-  the real ld is.
-  In this case set AFL_REAL_LD=/bin/ld.orig
-
- !2! 
- When you install an updated gcc/clang/... package, your OS might restore
- the ld link.
-
-### Performing the steps by hand
-
-It is possible to perform all the steps afl-ld by hand to workaround issues
-in the target.
-
-1. Recompile with AFL_DEBUG=1 and collect the afl-clang-lto command that fails
-   e.g.: `AFL_DEBUG=1 make 2>&1 | grep afl-clang-lto | tail -n 1`
-
-2. run this command prepended with AFL_DEBUG=1 and collect the afl-ld command
-   parameters, e.g. `AFL_DEBUG=1 afl-clang-lto[++] .... | grep /afl/ld`
-
-3. for every .a archive you want to instrument unpack it into a seperate
-   directory, e.g.
-   `mkdir archive1.dir ; cd archive1.dir ; llvm-link x ../<archive>.a`
-
-4. run `file archive*.dir/*.o` and make two lists, one containing all ELF files
-   and one containing all LLVM IR bitcode files.
-   You do the same for all .o files of the ../afl/ld command options
-
-5. Create a single bitcode file by using llvm-link, e.g.
-   `llvm-link -o all-bitcode.bc <list of all LLVM IR .o files>`
-   If this fails it is game over - or you modify the source code
-
-6. Run the optimizer on the new bitcode file:
-   `opt -O3 --polly -o all-optimized.bc all-bitcode.bc`
-
-7. Instrument the optimized bitcode file:
-   `opt --load=$AFL_PATH/afl-llvm-lto-instrumentation.so --disable-opt --afl-lto all-optimized.bc -o all-instrumented.bc
-
-8. If the parameter `--allow-multiple-definition` is not in the list, add it
-   as first command line option.
-
-9. Link everything together.
-   a) You use the afl-ld command and instead of e.g. `/usr/local/lib/afl/ld`
-      you replace that with `ld`, the real linker.
-   b) Every .a archive you instrumented files from you remove the <archive>.a
-      or -l<archive> from the command
-   c) If you have entries in your ELF files list (see step 4), you put them to
-      the command line - but them in the same order!
-   d) put the all-instrumented.bc before the first library or .o file
-   e) run the command and hope it compiles, if it doesn't you have to analyze
-      what the issue is and fix that in the approriate step above.
-
-Yes this is long and complicated. That is why there is afl-ld doing this and
-that why this can easily fail and not all different ways how it *can* fail can
-be implemented ...
-
 ### compiling programs still fail
 
 afl-clang-lto is still work in progress.
-Complex targets are still likely not to compile and this needs to be fixed.
 Please report issues at:
 [https://github.com/AFLplusplus/AFLplusplus/issues/226](https://github.com/AFLplusplus/AFLplusplus/issues/226)
 
-Known issues:
-* ffmpeg
-* bogofilter
-* libjpeg-turbo-1.3.1
-
 ## Upcoming Work
 
-1. Currently the LTO whitelist feature does not allow to not instrument main, start and init functions
-2. Modify the forkserver + afl-fuzz so that only the necessary map size is
-   loaded and used - and communicated to afl-fuzz too.
-   Result: faster fork in the target and faster map analysis in afl-fuzz
-   => more speed :-)
-
-## Tested and working targets
-
-* libpng-1.2.53
-* libxml2-2.9.2
-* tiff-4.0.4
-* unrar-nonfree-5.6.6
-* exiv 0.27
-* jpeg-6b
+1. Currently the LTO whitelist feature does not allow to instrument main,
+   start and init functions
 
 ## History
 
@@ -249,14 +138,20 @@ This was first implemented in January and work ... kinda.
 The LTO time instrumentation worked, however the "how" the basic blocks were
 instrumented was a problem, as reducing duplicates turned out to be very,
 very difficult with a program that has so many paths and therefore so many
-dependencies. At lot of stratgies were implemented - and failed.
+dependencies. At lot of strategies were implemented - and failed.
 And then sat solvers were tried, but with over 10.000 variables that turned
 out to be a dead-end too.
+
 The final idea to solve this came from domenukk who proposed to insert a block
 into an edge and then just use incremental counters ... and this worked!
 After some trials and errors to implement this vanhauser-thc found out that
 there is actually an llvm function for this: SplitEdge() :-)
+
 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.
-As long as there are no larger changes in llvm this all should work well now ...
+
+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/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c
index e2b44def..3de5fd7d 100644
--- a/llvm_mode/afl-clang-fast.c
+++ b/llvm_mode/afl-clang-fast.c
@@ -159,7 +159,6 @@ static void find_obj(u8 *argv0) {
 static void edit_params(u32 argc, char **argv, char **envp) {
 
   u8  fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0;
-  u8  has_llvm_config = 0;
   u8 *name;
 
   cc_params = ck_alloc((argc + 128) * sizeof(u8 *));
@@ -170,8 +169,6 @@ static void edit_params(u32 argc, char **argv, char **envp) {
   else
     ++name;
 
-  has_llvm_config = (strlen(LLVM_BINDIR) > 0);
-
   if (instrument_mode == INSTRUMENT_LTO)
     if (lto_flag[0] != '-')
       FATAL(
@@ -181,20 +178,29 @@ static void edit_params(u32 argc, char **argv, char **envp) {
   if (!strcmp(name, "afl-clang-fast++") || !strcmp(name, "afl-clang-lto++")) {
 
     u8 *alt_cxx = getenv("AFL_CXX");
-    if (has_llvm_config)
+    if (USE_BINDIR)
       snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang++", LLVM_BINDIR);
     else
-      sprintf(llvm_fullpath, "clang++");
-    cc_params[0] = alt_cxx ? alt_cxx : (u8 *)llvm_fullpath;
+      sprintf(llvm_fullpath, CLANGPP_BIN);
+    cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)llvm_fullpath;
 
-  } else {
+  } else if (!strcmp(name, "afl-clang-fast") ||
+
+             !strcmp(name, "afl-clang-lto")) {
 
     u8 *alt_cc = getenv("AFL_CC");
-    if (has_llvm_config)
+    if (USE_BINDIR)
       snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang", LLVM_BINDIR);
     else
-      sprintf(llvm_fullpath, "clang");
-    cc_params[0] = alt_cc ? alt_cc : (u8 *)llvm_fullpath;
+      sprintf(llvm_fullpath, CLANG_BIN);
+    cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)llvm_fullpath;
+
+  } else {
+
+    fprintf(stderr, "Name of the binary: %s\n", argv[0]);
+    FATAL(
+        "Name of the binary is not a known name, expected afl-clang-fast(++) "
+        "or afl-clang-lto(++)");
 
   }
 
@@ -220,6 +226,13 @@ static void edit_params(u32 argc, char **argv, char **envp) {
   if (getenv("LAF_TRANSFORM_COMPARES") ||
       getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) {
 
+    if (!be_quiet && getenv("AFL_LLVM_LTO_AUTODICTIONARY") &&
+        instrument_mode != INSTRUMENT_LTO)
+      WARNF(
+          "using AFL_LLVM_LAF_TRANSFORM_COMPARES together with "
+          "AFL_LLVM_LTO_AUTODICTIONARY makes no sense. Use only "
+          "AFL_LLVM_LTO_AUTODICTIONARY.");
+
     cc_params[cc_par_cnt++] = "-Xclang";
     cc_params[cc_par_cnt++] = "-load";
     cc_params[cc_par_cnt++] = "-Xclang";
@@ -269,12 +282,6 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
   if (instrument_mode == INSTRUMENT_LTO) {
 
-    char *old_path = getenv("PATH");
-    char *new_path = alloc_printf("%s:%s", AFL_PATH, old_path);
-
-    setenv("PATH", new_path, 1);
-    setenv("AFL_LD", "1", 1);
-
     if (getenv("AFL_LLVM_WHITELIST") != NULL) {
 
       cc_params[cc_par_cnt++] = "-Xclang";
@@ -285,13 +292,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
     }
 
-#ifdef AFL_CLANG_FUSELD
-    cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s/afl-ld", AFL_PATH);
-#endif
-
-    cc_params[cc_par_cnt++] = "-B";
-    cc_params[cc_par_cnt++] = AFL_PATH;
-
+    cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", AFL_REAL_LD);
+    cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
+    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 {
@@ -410,7 +414,11 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
   }
 
-  if (getenv("AFL_NO_BUILTIN")) {
+  if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
+      getenv("LAF_TRANSFORM_COMPARES") ||
+      (instrument_mode == INSTRUMENT_LTO &&
+       (getenv("AFL_LLVM_LTO_AUTODICTIONARY") ||
+        getenv("AFL_LLVM_AUTODICTIONARY")))) {
 
     cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
     cc_params[cc_par_cnt++] = "-fno-builtin-strncmp";
@@ -491,21 +499,38 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
     case 0:
       cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt.o", obj_path);
+      if (instrument_mode == INSTRUMENT_LTO)
+        cc_params[cc_par_cnt++] =
+            alloc_printf("%s/afl-llvm-rt-lto.o", obj_path);
       break;
 
     case 32:
       cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-32.o", obj_path);
-
       if (access(cc_params[cc_par_cnt - 1], R_OK))
         FATAL("-m32 is not supported by your compiler");
+      if (instrument_mode == INSTRUMENT_LTO) {
+
+        cc_params[cc_par_cnt++] =
+            alloc_printf("%s/afl-llvm-rt-lto-32.o", obj_path);
+        if (access(cc_params[cc_par_cnt - 1], R_OK))
+          FATAL("-m32 is not supported by your compiler");
+
+      }
 
       break;
 
     case 64:
       cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-64.o", obj_path);
-
       if (access(cc_params[cc_par_cnt - 1], R_OK))
         FATAL("-m64 is not supported by your compiler");
+      if (instrument_mode == INSTRUMENT_LTO) {
+
+        cc_params[cc_par_cnt++] =
+            alloc_printf("%s/afl-llvm-rt-lto-64.o", obj_path);
+        if (access(cc_params[cc_par_cnt - 1], R_OK))
+          FATAL("-m64 is not supported by your compiler");
+
+      }
 
       break;
 
@@ -539,6 +564,10 @@ int main(int argc, char **argv, char **envp) {
 
   if ((ptr = getenv("AFL_LLVM_INSTRUMENT")) != NULL) {
 
+    if (strncasecmp(ptr, "default", strlen("default")) == 0 ||
+        strncasecmp(ptr, "afl", strlen("afl")) == 0 ||
+        strncasecmp(ptr, "classic", strlen("classic")) == 0)
+      instrument_mode = INSTRUMENT_DEFAULT;
     if (strncasecmp(ptr, "cfg", strlen("cfg")) == 0 ||
         strncasecmp(ptr, "instrim", strlen("instrim")) == 0)
       instrument_mode = INSTRUMENT_CFG;
@@ -692,30 +721,30 @@ int main(int argc, char **argv, char **envp) {
         "Environment variables used:\n"
         "AFL_CC: path to the C compiler to use\n"
         "AFL_CXX: path to the C++ compiler to use\n"
-        "AFL_PATH: path to instrumenting pass and runtime "
-        "(afl-llvm-rt.*o)\n"
-        "AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n"
-        "AFL_NO_BUILTIN: compile for use with libtokencap.so\n"
-        "AFL_INST_RATIO: percentage of branches to instrument\n"
-        "AFL_QUIET: suppress verbose output\n"
         "AFL_DEBUG: enable developer debugging output\n"
+        "AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n"
         "AFL_HARDEN: adds code hardening to catch memory bugs\n"
-        "AFL_USE_ASAN: activate address sanitizer\n"
-        "AFL_USE_MSAN: activate memory sanitizer\n"
-        "AFL_USE_UBSAN: activate undefined behaviour sanitizer\n"
-        "AFL_USE_CFISAN: activate control flow sanitizer\n"
-        "AFL_LLVM_WHITELIST: enable whitelisting (selective "
-        "instrumentation)\n"
+        "AFL_INST_RATIO: percentage of branches to instrument\n"
         "AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n"
         "AFL_LLVM_LAF_SPLIT_COMPARES: enable cascaded comparisons\n"
-        "AFL_LLVM_LAF_SPLIT_SWITCHES: casc. comp. in 'switch'\n"
-        "AFL_LLVM_LAF_TRANSFORM_COMPARES: transform library comparison "
-        "function calls\n"
-        " to cascaded comparisons\n"
         "AFL_LLVM_LAF_SPLIT_FLOATS: transform floating point comp. to "
         "cascaded "
         "comp.\n"
-        "AFL_LLVM_LAF_SPLIT_COMPARES_BITW: size limit (default 8)\n",
+        "AFL_LLVM_LAF_SPLIT_SWITCHES: casc. comp. in 'switch'\n"
+        " to cascaded comparisons\n"
+        "AFL_LLVM_LAF_TRANSFORM_COMPARES: transform library comparison "
+        "function calls\n"
+        "AFL_LLVM_LAF_SPLIT_COMPARES_BITW: size limit (default 8)\n"
+        "AFL_LLVM_WHITELIST: enable whitelisting (selective "
+        "instrumentation)\n"
+        "AFL_NO_BUILTIN: compile for use with libtokencap.so\n"
+        "AFL_PATH: path to instrumenting pass and runtime "
+        "(afl-llvm-rt.*o)\n"
+        "AFL_QUIET: suppress verbose output\n"
+        "AFL_USE_ASAN: activate address sanitizer\n"
+        "AFL_USE_CFISAN: activate control flow sanitizer\n"
+        "AFL_USE_MSAN: activate memory sanitizer\n"
+        "AFL_USE_UBSAN: activate undefined behaviour sanitizer\n",
         callname, BIN_PATH, BIN_PATH);
 
     SAYF(
@@ -723,24 +752,22 @@ int main(int argc, char **argv, char **envp) {
         "AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen mutator)\n"
         "AFL_LLVM_INSTRUMENT: set instrumentation mode: DEFAULT, CFG "
         "(INSTRIM), LTO, CTX, NGRAM-2 ... NGRAM-16\n"
-        "You can also use the old environment variables:"
-        "AFL_LLVM_CTX: use context sensitive coverage\n"
-        "AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n"
-        "AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage\n"
-        "AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n"
-        "AFL_LLVM_INSTRIM_LOOPHEAD: optimize loop tracing for speed (sub "
+        " You can also use the old environment variables instead:"
+        "  AFL_LLVM_CTX: use context sensitive coverage\n"
+        "  AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n"
+        "  AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage\n"
+        "  AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n"
+        "  AFL_LLVM_INSTRIM_LOOPHEAD: optimize loop tracing for speed (sub "
         "option to INSTRIM)\n");
 
 #ifdef AFL_CLANG_FLTO
     SAYF(
         "\nafl-clang-lto specific environment variables:\n"
-        "AFL_LLVM_LTO_STARTID: from which ID to start counting from for a "
-        "bb\n"
         "AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a "
         "global var\n"
-        "AFL_REAL_LD: use this linker instead of the compiled in path\n"
-        "AFL_LD_PASSTHROUGH: do not perform instrumentation (for configure "
-        "scripts)\n"
+        "AFL_LLVM_LTO_STARTID: from which ID to start counting from for a "
+        "bb\n"
+        "AFL_REAL_LD: use this lld linker instead of the compiled in path\n"
         "\nafl-clang-lto was built with linker target \"%s\" and LTO flags "
         "\"%s\"\n"
         "If anything fails - be sure to read README.lto.md!\n",
@@ -774,6 +801,16 @@ int main(int argc, char **argv, char **envp) {
 
   }
 
+  u8 *ptr2;
+  if (!be_quiet && instrument_mode != INSTRUMENT_LTO &&
+      ((ptr2 = getenv("AFL_MAP_SIZE")) || (ptr2 = getenv("AFL_MAPSIZE")))) {
+
+    u32 map_size = atoi(ptr2);
+    if (map_size != MAP_SIZE)
+      FATAL("AFL_MAP_SIZE is not supported by afl-clang-fast");
+
+  }
+
   if (debug) {
 
     SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
diff --git a/llvm_mode/afl-ld.c b/llvm_mode/afl-ld.c
deleted file mode 100644
index eb46c85c..00000000
--- a/llvm_mode/afl-ld.c
+++ /dev/null
@@ -1,839 +0,0 @@
-/*
-  american fuzzy lop++ - wrapper for GNU ld
-  -----------------------------------------
-
-  Written by Marc Heuse <mh@mh-sec.de> for afl++
-
-  Maintained by Marc Heuse <mh@mh-sec.de>,
-                Heiko Eißfeldt <heiko.eissfeldt@hexco.de>
-                Andrea Fioraldi <andreafioraldi@gmail.com>
-                Dominik Maier <domenukk@gmail.com>
-
-  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
-
-  The sole purpose of this wrapper is to preprocess clang LTO files before
-  linking by ld and perform the instrumentation on the whole program.
-
-*/
-
-#define AFL_MAIN
-
-#include "config.h"
-#include "types.h"
-#include "debug.h"
-#include "alloc-inl.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <ctype.h>
-#include <fcntl.h>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/time.h>
-
-#include <dirent.h>
-
-#define MAX_PARAM_COUNT 4096
-
-static u8 **ld_params,              /* Parameters passed to the real 'ld'   */
-    **link_params,                  /* Parameters passed to 'llvm-link'     */
-    **opt_params,                   /* Parameters passed to 'opt' opt       */
-    **inst_params;                  /* Parameters passed to 'opt' inst      */
-
-static u8 *input_file;              /* Originally specified input file      */
-static u8 *final_file,              /* Instrumented file for the real 'ld'  */
-    *linked_file,                   /* file where we link all files         */
-    *modified_file;                 /* file that was optimized before instr */
-static u8 *afl_path = AFL_PATH;
-static u8 *real_ld = AFL_REAL_LD;
-static u8  cwd[4096];
-static u8 *tmp_dir;
-static u8 *ar_dir;
-static u8  ar_dir_cnt;
-static u8 *libdirs[254];
-static u8  libdir_cnt;
-
-static u8 be_quiet,                 /* Quiet mode (no stderr output)        */
-    debug,                          /* AFL_DEBUG                            */
-    passthrough,                    /* AFL_LD_PASSTHROUGH - no link+optimize*/
-    we_link,                        /* we have bc/ll -> link + optimize     */
-    just_version;                   /* Just show version?                   */
-
-static u32 ld_param_cnt = 1,        /* Number of params to 'ld'             */
-    link_param_cnt = 1,             /* Number of params to 'llvm-link'      */
-    opt_param_cnt = 1,              /* Number of params to 'opt' opt        */
-    inst_param_cnt = 1;             /* Number of params to 'opt' instr      */
-
-/* This function wipes a directory - our AR unpack directory in this case */
-static u8 wipe_directory(u8 *path) {
-
-  DIR *          d;
-  struct dirent *d_ent;
-
-  d = opendir(path);
-
-  if (!d) return 0;
-
-  while ((d_ent = readdir(d))) {
-
-    if (strcmp(d_ent->d_name, ".") != 0 && strcmp(d_ent->d_name, "..") != 0) {
-
-      u8 *fname = alloc_printf("%s/%s", path, d_ent->d_name);
-      if (unlink(fname)) PFATAL("Unable to delete '%s'", fname);
-      ck_free(fname);
-
-    }
-
-  }
-
-  closedir(d);
-
-  return !!rmdir(path);
-
-}
-
-/* remove temporary files on fatal errors */
-static void at_exit_handler(void) {
-
-  if (!getenv("AFL_KEEP_ASSEMBLY")) {
-
-    if (linked_file) {
-
-      unlink(linked_file);
-      linked_file = NULL;
-
-    }
-
-    if (modified_file) {
-
-      unlink(modified_file);
-      modified_file = NULL;
-
-    }
-
-    if (final_file) {
-
-      unlink(final_file);
-      final_file = NULL;
-
-    }
-
-    if (ar_dir != NULL) {
-
-      wipe_directory(ar_dir);
-      ar_dir = NULL;
-
-    }
-
-  }
-
-}
-
-/* This function checks if the parameter is a) an existing file and b)
-   if it is a BC or LL file, if both are true it returns 1 and 0 otherwise */
-int is_llvm_file(const char *file) {
-
-  int fd;
-  u8  buf[5];
-
-  if ((fd = open(file, O_RDONLY)) < 0) {
-
-    if (debug) SAYF(cMGN "[D] " cRST "File %s not found", file);
-    return 0;
-
-  }
-
-  if (read(fd, buf, 4) != 4) return 0;
-  buf[sizeof(buf) - 1] = 0;
-
-  close(fd);
-
-  if (strncmp(buf, "; Mo", 4) == 0) return 1;
-
-  if (buf[0] == 'B' && buf[1] == 'C' && buf[2] == 0xc0 && buf[3] == 0xde)
-    return 1;
-
-  return 0;
-
-}
-
-/* Return the current working directory, not thread safe ;-) */
-u8 *getthecwd() {
-
-  static u8 fail[] = "";
-  if (getcwd(cwd, sizeof(cwd)) == NULL) return fail;
-  return cwd;
-
-}
-
-/* Check if an ar extracted file is already in the parameter list */
-int is_duplicate(u8 **params, u32 ld_param_cnt, u8 *ar_file) {
-
-  for (uint32_t i = 0; i < ld_param_cnt; i++)
-    if (params[i] != NULL)
-      if (strcmp(params[i], ar_file) == 0) return 1;
-
-  return 0;
-
-}
-
-/* Examine and modify parameters to pass to 'ld', 'llvm-link' and 'llmv-ar'.
-   Note that the file name is always the last parameter passed by GCC,
-   so we exploit this property to keep the code "simple". */
-static void edit_params(int argc, char **argv) {
-
-  u32 i, have_lto = 0, libdir_index;
-  u8  libdir_file[4096];
-
-  if (tmp_dir == NULL) {
-
-    tmp_dir = getenv("TMPDIR");
-    if (!tmp_dir) tmp_dir = getenv("TEMP");
-    if (!tmp_dir) tmp_dir = getenv("TMP");
-    if (!tmp_dir) tmp_dir = "/tmp";
-
-  }
-
-  linked_file =
-      alloc_printf("%s/.afl-%u-%u-1.ll", tmp_dir, getpid(), (u32)time(NULL));
-  modified_file =
-      alloc_printf("%s/.afl-%u-%u-2.bc", tmp_dir, getpid(), (u32)time(NULL));
-  final_file =
-      alloc_printf("%s/.afl-%u-%u-3.bc", tmp_dir, getpid(), (u32)time(NULL));
-
-  ld_params = ck_alloc(4096 * sizeof(u8 *));
-  link_params = ck_alloc(4096 * sizeof(u8 *));
-  inst_params = ck_alloc(12 * sizeof(u8 *));
-  opt_params = ck_alloc(12 * sizeof(u8 *));
-
-  ld_params[0] = (u8 *)real_ld;
-  ld_params[ld_param_cnt++] = "--allow-multiple-definition";
-
-  link_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "llvm-link");
-  link_params[link_param_cnt++] = "-S";  // we create the linked file as .ll
-  link_params[link_param_cnt++] = "-o";
-  link_params[link_param_cnt++] = linked_file;
-
-  opt_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "opt");
-  if (getenv("AFL_DONT_OPTIMIZE") == NULL)
-    opt_params[opt_param_cnt++] = "-O3";
-  else
-    opt_params[opt_param_cnt++] = "-O0";
-
-  // opt_params[opt_param_cnt++] = "-S"; // only when debugging
-  opt_params[opt_param_cnt++] = linked_file;  // input: .ll file
-  opt_params[opt_param_cnt++] = "-o";
-  opt_params[opt_param_cnt++] = modified_file;  // output: .bc file
-
-  inst_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "opt");
-  inst_params[inst_param_cnt++] =
-      alloc_printf("--load=%s/afl-llvm-lto-instrumentation.so", afl_path);
-  // inst_params[inst_param_cnt++] = "-S"; // only when debugging
-  inst_params[inst_param_cnt++] = "--disable-opt";
-  inst_params[inst_param_cnt++] = "--afl-lto";
-  inst_params[inst_param_cnt++] = modified_file;  // input: .bc file
-  inst_params[inst_param_cnt++] = "-o";
-  inst_params[inst_param_cnt++] = final_file;  // output: .bc file
-
-  // first we must collect all library search paths
-  for (i = 1; i < argc; i++)
-    if (strlen(argv[i]) > 2 && argv[i][0] == '-' && argv[i][1] == 'L')
-      libdirs[libdir_cnt++] = argv[i] + 2;
-
-  // then we inspect all options to the target linker
-  for (i = 1; i < argc; i++) {
-
-    if (ld_param_cnt >= MAX_PARAM_COUNT || link_param_cnt >= MAX_PARAM_COUNT)
-      FATAL(
-          "Too many command line parameters because of unpacking .a archives, "
-          "this would need to be done by hand ... sorry! :-(");
-
-    if (strncmp(argv[i], "-flto", 5) == 0) have_lto = 1;
-
-    if (!strcmp(argv[i], "-version")) {
-
-      just_version = 1;
-      ld_params[1] = argv[i];
-      ld_params[2] = NULL;
-      final_file = input_file;
-      return;
-
-    }
-
-    if (strcmp(argv[i], "--afl") == 0) {
-
-      if (!be_quiet) OKF("afl++ test command line flag detected, exiting.");
-      exit(0);
-
-    }
-
-    // if a -l library is linked and no .so is found but an .a archive is there
-    // then the archive will be used. So we have to emulate this and check
-    // if an archive will be used and if yes we will instrument it too
-    libdir_file[0] = 0;
-    libdir_index = libdir_cnt;
-    if (strncmp(argv[i], "-l", 2) == 0 && libdir_cnt > 0 &&
-        strncmp(argv[i], "-lgcc", 5) != 0) {
-
-      u8 found = 0;
-
-      for (uint32_t j = 0; j < libdir_cnt && !found; j++) {
-
-        snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j],
-                 argv[i] + 2, ".so");
-        if (access(libdir_file, R_OK) != 0) {  // no .so found?
-
-          snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j],
-                   argv[i] + 2, ".a");
-          if (access(libdir_file, R_OK) == 0) {  // but .a found?
-
-            libdir_index = j;
-            found = 1;
-            if (debug) SAYF(cMGN "[D] " cRST "Found %s\n", libdir_file);
-
-          }
-
-        } else {
-
-          found = 1;
-          if (debug) SAYF(cMGN "[D] " cRST "Found %s\n", libdir_file);
-
-        }
-
-      }
-
-    }
-
-    // is the parameter an .a AR archive? If so, unpack and check its files
-    if (libdir_index < libdir_cnt ||
-        (argv[i][0] != '-' && strlen(argv[i]) > 2 &&
-         argv[i][strlen(argv[i]) - 1] == 'a' &&
-         argv[i][strlen(argv[i]) - 2] == '.')) {
-
-      // This gets a bit odd. I encountered several .a files being linked and
-      // where the same "foo.o" was in both .a archives. llvm-link does not
-      // like this so we have to work around that ...
-
-      u8             this_wd[4096], *this_ar;
-      u8             ar_params_cnt = 4;
-      u8 *           ar_params[ar_params_cnt];
-      u8 *           file = argv[i];
-      s32            pid, status;
-      DIR *          arx;
-      struct dirent *dir_ent;
-
-      if (libdir_index < libdir_cnt) file = libdir_file;
-
-      if (ar_dir_cnt == 0) {  // first archive, we setup up the basics
-
-        ar_dir = alloc_printf("%s/.afl-%u-%u.dir", tmp_dir, getpid(),
-                              (u32)time(NULL));
-        if (mkdir(ar_dir, 0700) != 0)
-          FATAL("can not create temporary directory %s", ar_dir);
-
-      }
-
-      if (getcwd(this_wd, sizeof(this_wd)) == NULL)
-        FATAL("can not get the current working directory");
-      if (chdir(ar_dir) != 0)
-        FATAL("can not chdir to temporary directory %s", ar_dir);
-      if (file[0] == '/')
-        this_ar = file;
-      else
-        this_ar = alloc_printf("%s/%s", this_wd, file);
-      ar_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "llvm-ar");
-      ar_params[1] = "x";
-      ar_params[2] = this_ar;
-      ar_params[3] = NULL;
-
-      if (!be_quiet) OKF("Running ar unpacker on %s into %s", this_ar, ar_dir);
-
-      if (debug) {
-
-        SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
-        for (uint32_t j = 0; j < ar_params_cnt; j++)
-          SAYF(" \"%s\"", ar_params[j]);
-        SAYF("\n");
-
-      }
-
-      if (!(pid = fork())) {
-
-        execvp(ar_params[0], (char **)ar_params);
-        FATAL("Oops, failed to execute '%s'", ar_params[0]);
-
-      }
-
-      if (pid < 0) FATAL("fork() failed");
-      if (waitpid(pid, &status, 0) <= 0) FATAL("waitpid() failed");
-      if (WEXITSTATUS(status) != 0) exit(WEXITSTATUS(status));
-
-      if (chdir(this_wd) != 0)
-        FATAL("can not chdir back to our working directory %s", this_wd);
-
-      if (!(arx = opendir(ar_dir))) FATAL("can not open directory %s", ar_dir);
-
-      while ((dir_ent = readdir(arx)) != NULL) {
-
-        u8 *ar_file = alloc_printf("%s/%s", ar_dir, dir_ent->d_name);
-
-        if (dir_ent->d_name[strlen(dir_ent->d_name) - 1] == 'o' &&
-            dir_ent->d_name[strlen(dir_ent->d_name) - 2] == '.') {
-
-          if (passthrough || is_llvm_file(ar_file) == 0) {
-
-            if (is_duplicate(ld_params, ld_param_cnt, ar_file) == 0) {
-
-              ld_params[ld_param_cnt++] = ar_file;
-              if (debug)
-                SAYF(cMGN "[D] " cRST "not a LTO link file: %s\n", ar_file);
-
-            }
-
-          } else {
-
-            if (is_duplicate(link_params, link_param_cnt, ar_file) == 0) {
-
-              if (we_link == 0) {  // we have to honor order ...
-
-                ld_params[ld_param_cnt++] = final_file;
-                we_link = 1;
-
-              }
-
-              link_params[link_param_cnt++] = ar_file;
-              if (debug) SAYF(cMGN "[D] " cRST "is a link file: %s\n", ar_file);
-
-            }
-
-          }
-
-        } else
-
-            if (dir_ent->d_name[0] != '.' && !be_quiet)
-          WARNF("Unusual file found in ar archive %s: %s", argv[i], ar_file);
-
-      }
-
-      closedir(arx);
-      ar_dir_cnt++;
-
-      continue;
-
-    }
-
-    if (passthrough || argv[i][0] == '-' || is_llvm_file(argv[i]) == 0) {
-
-      // -O3 fucks up the CFG and instrumentation, so we downgrade to O2
-      // which is as we want things. Lets hope this is not too different
-      // in the various llvm versions!
-      if (strncmp(argv[i], "-plugin-opt=O", 13) == 0 &&
-          !getenv("AFL_DONT_OPTIMIZE"))
-        ld_params[ld_param_cnt++] = "-plugin-opt=O2";
-      else
-        ld_params[ld_param_cnt++] = argv[i];
-
-    } else {
-
-      if (we_link == 0) {  // we have to honor order ...
-        ld_params[ld_param_cnt++] = final_file;
-        we_link = 1;
-
-      }
-
-      link_params[link_param_cnt++] = argv[i];
-
-    }
-
-  }
-
-  // if (have_lto == 0) ld_params[ld_param_cnt++] = AFL_CLANG_FLTO; // maybe we
-  // should not ...
-  ld_params[ld_param_cnt] = NULL;
-  link_params[link_param_cnt] = NULL;
-  opt_params[opt_param_cnt] = NULL;
-  inst_params[inst_param_cnt] = NULL;
-
-}
-
-/* clean AFL_PATH from PATH */
-
-void clean_path() {
-
-  char *tmp, *newpath = NULL, *path = getenv("PATH");
-  u8    done = 0;
-
-  if (debug)
-    SAYF(cMGN "[D]" cRST " old PATH=%s, AFL_PATH=%s\n", path, AFL_PATH);
-
-  // wipe AFL paths from PATH that we set
-  // we added two paths so we remove the two paths
-  while (!done) {
-
-    if (*path == 0)
-      done = 1;
-    else if (*path++ == ':')
-      done = 1;
-
-  }
-
-  while (*path == ':')
-    path++;
-
-  // AFL_PATH could be additionally in PATH so check and remove to not call our
-  // 'ld'
-  const size_t pathlen = strlen(path);
-  const size_t afl_pathlen = strlen(AFL_PATH);
-  newpath = malloc(pathlen + 1);
-  if (strcmp(AFL_PATH, "/bin") != 0 && strcmp(AFL_PATH, "/usr/bin") != 0 &&
-      afl_pathlen > 1 && (tmp = strstr(path, AFL_PATH)) != NULL &&  // it exists
-      (tmp == path ||
-       (tmp > path &&
-        tmp[-1] == ':')) &&  // either starts with it or has a colon before
-      (tmp + afl_pathlen == path + pathlen ||
-       (tmp + afl_pathlen <
-        path + (pathlen && tmp[afl_pathlen] ==
-                               ':'))  // end with it or has a colon at the end
-       )) {
-
-    int one_colon = 1;
-
-    if (tmp > path) {
-
-      memcpy(newpath, path, tmp - path);
-      newpath[tmp - path - 1] = 0;  // remove ':'
-      one_colon = 0;
-
-    }
-
-    if (tmp + afl_pathlen < path + pathlen) tmp += afl_pathlen + one_colon;
-
-    setenv("PATH", newpath, 1);
-
-  } else
-
-    setenv("PATH", path, 1);
-
-  if (debug) SAYF(cMGN "[D]" cRST " new PATH=%s\n", getenv("PATH"));
-  free(newpath);
-
-}
-
-/* Main entry point */
-
-int main(int argc, char **argv) {
-
-  s32 pid, i;
-  int status;
-  u8 *ptr, exe[4096], exe2[4096], proc[32], val[2] = " ";
-  int have_afl_ld_caller = 0;
-
-  if (isatty(2) && !getenv("AFL_QUIET") && !getenv("AFL_DEBUG")) {
-
-    if (getenv("AFL_LD") != NULL)
-      SAYF(cCYA "afl-ld" VERSION cRST
-                " by Marc \"vanHauser\" Heuse <mh@mh-sec.de> (level %d)\n",
-           have_afl_ld_caller);
-
-  } else
-
-    be_quiet = 1;
-
-  if (getenv("AFL_DEBUG") != NULL) debug = 1;
-  if (getenv("AFL_PATH") != NULL) afl_path = getenv("AFL_PATH");
-  if (getenv("AFL_LD_PASSTHROUGH") != NULL) passthrough = 1;
-  if (getenv("AFL_REAL_LD") != NULL) real_ld = getenv("AFL_REAL_LD");
-  if (real_ld == NULL || strlen(real_ld) < 2) real_ld = "/bin/ld";
-  if (real_ld != NULL && real_ld[0] != '/')
-    real_ld = alloc_printf("/bin/%s", real_ld);
-
-  if ((ptr = getenv("AFL_LD_CALLER")) != NULL) have_afl_ld_caller = atoi(ptr);
-  val[0] = 0x31 + have_afl_ld_caller;
-  setenv("AFL_LD_CALLER", val, 1);
-
-  if (debug) {
-
-    SAYF(cMGN "[D] " cRST
-              "AFL_LD=%s, set AFL_LD_CALLER=%s, have_afl_ld_caller=%d, "
-              "real_ld=%s\n",
-         getenv("AFL_LD"), val, have_afl_ld_caller, real_ld);
-    SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
-    for (i = 0; i < argc; i++)
-      SAYF(" \"%s\"", argv[i]);
-    SAYF("\n");
-
-  }
-
-  sprintf(proc, "/proc/%d/exe", getpid());
-  if (readlink(proc, exe, sizeof(exe) - 1) > 0) {
-
-    if (readlink(real_ld, exe2, sizeof(exe2) - 1) < 1) exe2[0] = 0;
-    exe[sizeof(exe) - 1] = 0;
-    exe[sizeof(exe2) - 1] = 0;
-    if (strcmp(exe, real_ld) == 0 || strcmp(exe, exe2) == 0)
-      PFATAL(cLRD "[!] " cRST
-                  "Error: real 'ld' path points to afl-ld, set AFL_REAL_LD to "
-                  "the real 'ld' program!");
-
-  }
-
-  if (have_afl_ld_caller > 1)
-    PFATAL(cLRD "[!] " cRST
-                "Error: afl-ld calls itself in a loop, set AFL_REAL_LD to the "
-                "real 'ld' program!");
-
-  if (argc < 2) {
-
-    SAYF(
-        "\n"
-        "This is a helper application for afl-fuzz. It is a wrapper around GNU "
-        "'ld',\n"
-        "executed by the toolchain whenever using "
-        "afl-clang-lto/afl-clang-lto++.\n"
-        "You probably don't want to run this program directly.\n\n"
-
-        "Environment variables:\n"
-        "  AFL_LD_PASSTHROUGH   do not link+optimize == no instrumentation\n"
-        "  AFL_REAL_LD          point to the real ld if necessary\n"
-
-        "\nafl-ld was compiled with the fixed real 'ld' path of %s and the "
-        "clang "
-        "bin path of %s\n\n",
-        real_ld, LLVM_BINDIR);
-
-    exit(1);
-
-  }
-
-  if (getenv("AFL_LD") == NULL) {
-
-    /* if someone install clang/ld into the same directory as afl++ then
-       they are out of luck ... */
-
-    if (have_afl_ld_caller == 1) { clean_path(); }
-
-    if (real_ld != NULL && strlen(real_ld) > 1) execvp(real_ld, argv);
-    execvp("ld", argv);  // fallback
-    PFATAL("Oops, failed to execute 'ld' - check your PATH");
-
-  }
-
-  atexit(at_exit_handler);  // ensure to wipe temp files if things fail
-
-  edit_params(argc, argv);  // here most of the magic happens :-)
-
-  if (debug)
-    SAYF(cMGN "[D] " cRST
-              "param counts: ar:%u lib:%u ld:%u link:%u opt:%u instr:%u\n",
-         ar_dir_cnt, libdir_cnt, ld_param_cnt, link_param_cnt, opt_param_cnt,
-         inst_param_cnt);
-
-  if (!just_version) {
-
-    if (we_link == 0) {
-
-      if (!getenv("AFL_QUIET"))
-        WARNF("No LTO input file found, cannot instrument!");
-
-    } else {
-
-      /* first we link all files */
-      if (!be_quiet) OKF("Running bitcode linker, creating %s", linked_file);
-
-      if (debug) {
-
-        SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
-        for (i = 0; i < link_param_cnt; i++)
-          SAYF(" \"%s\"", link_params[i]);
-        SAYF("\n");
-
-      }
-
-      if (!(pid = fork())) {
-
-        execvp(link_params[0], (char **)link_params);
-        FATAL("Oops, failed to execute '%s'", link_params[0]);
-
-      }
-
-      if (pid < 0) PFATAL("fork() failed");
-      if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
-      if (WEXITSTATUS(status) != 0) {
-
-        SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD
-             "\n[-] PROGRAM ABORT : " cRST);
-        SAYF(
-            "llvm-link failed! Probable causes:\n\n"
-            " #1  If the error is \"linking globals named '...': symbol "
-            "multiply defined\"\n"
-            "     then there is nothing we can do - llvm-link is missing an "
-            "important feature\n\n"
-            " #2  If the error is \"expected top-level entity\" and then "
-            "binary output, this\n"
-            "     is because the same file is present in different .a archives "
-            "in different\n"
-            "     formats. This can be fixed by manual doing the steps afl-ld "
-            "is doing but\n"
-            "     programmatically - sorry!\n\n");
-        exit(WEXITSTATUS(status));
-
-      }
-
-      /* then we perform an optimization on the collected objects files */
-      if (!be_quiet)
-        OKF("Performing optimization via opt, creating %s", modified_file);
-      if (debug) {
-
-        SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
-        for (i = 0; i < opt_param_cnt; i++)
-          SAYF(" \"%s\"", opt_params[i]);
-        SAYF("\n");
-
-      }
-
-      if (!(pid = fork())) {
-
-        execvp(opt_params[0], (char **)opt_params);
-        FATAL("Oops, failed to execute '%s'", opt_params[0]);
-
-      }
-
-      if (pid < 0) PFATAL("fork() failed");
-      if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
-      if (WEXITSTATUS(status) != 0) exit(WEXITSTATUS(status));
-
-      /* then we run the instrumentation through the optimizer */
-      if (!be_quiet)
-        OKF("Performing instrumentation via opt, creating %s", final_file);
-      if (debug) {
-
-        SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
-        for (i = 0; i < inst_param_cnt; i++)
-          SAYF(" \"%s\"", inst_params[i]);
-        SAYF("\n");
-
-      }
-
-      if (!(pid = fork())) {
-
-        execvp(inst_params[0], (char **)inst_params);
-        FATAL("Oops, failed to execute '%s'", inst_params[0]);
-
-      }
-
-      if (pid < 0) PFATAL("fork() failed");
-      if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
-      if (WEXITSTATUS(status) != 0) exit(WEXITSTATUS(status));
-
-    }
-
-    /* next step - run the linker! :-) */
-
-  }
-
-  if (!be_quiet) OKF("Running real linker %s", real_ld);
-  if (debug) {
-
-    SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd());
-    for (i = 0; i < ld_param_cnt; i++)
-      SAYF(" \"%s\"", ld_params[i]);
-    SAYF("\n");
-
-  }
-
-  if (!(pid = fork())) {
-
-    clean_path();
-
-    unsetenv("AFL_LD");
-
-    if (strlen(real_ld) > 1) execvp(real_ld, (char **)ld_params);
-    execvp("ld", (char **)ld_params);  // fallback
-    FATAL("Oops, failed to execute 'ld' - check your PATH");
-
-  }
-
-  if (pid < 0) PFATAL("fork() failed");
-
-  if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
-  if (debug) SAYF(cMGN "[D] " cRST "linker result: %d\n", status);
-
-  if (!just_version) {
-
-    if (!getenv("AFL_KEEP_ASSEMBLY")) {
-
-      if (linked_file) {
-
-        unlink(linked_file);
-        linked_file = NULL;
-
-      }
-
-      if (modified_file) {
-
-        unlink(modified_file);
-        modified_file = NULL;
-
-      }
-
-      if (final_file) {
-
-        unlink(final_file);
-        final_file = NULL;
-
-      }
-
-      if (ar_dir != NULL) {
-
-        wipe_directory(ar_dir);
-        ar_dir = NULL;
-
-      }
-
-    } else {
-
-      if (!be_quiet) {
-
-        SAYF(
-            "[!] afl-ld: keeping link file %s, optimized bitcode %s and "
-            "instrumented bitcode %s",
-            linked_file, modified_file, final_file);
-        if (ar_dir_cnt > 0 && ar_dir)
-          SAYF(" and ar archive unpack directory %s", ar_dir);
-        SAYF("\n");
-
-      }
-
-    }
-
-    if (status == 0) {
-
-      if (!be_quiet) OKF("Linker was successful");
-
-    } else {
-
-      SAYF(cLRD "[-] " cRST
-                "Linker failed, please investigate and send a bug report. Most "
-                "likely an 'ld' option is incompatible with %s. Try "
-                "AFL_KEEP_ASSEMBLY=1 and AFL_DEBUG=1 for replaying.\n",
-           AFL_CLANG_FLTO);
-
-    }
-
-  }
-
-  exit(WEXITSTATUS(status));
-
-}
-
diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc
index 4bc16f17..ece3201f 100644
--- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc
+++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc
@@ -23,12 +23,6 @@
 
  */
 
-// CONFIG OPTION:
-// If #define USE_SPLIT is used, then the llvm::SplitEdge function is used
-// instead of our own implementation. Ours looks better and will
-// compile everywhere. But it is not working for complex code. yet. damn.
-#define USE_SPLIT
-
 #define AFL_LLVM_PASS
 
 #include "config.h"
@@ -44,31 +38,24 @@
 #include <sys/time.h>
 
 #include "llvm/Config/llvm-config.h"
-#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
-typedef long double max_align_t;
-#endif
-
+#include "llvm/ADT/Statistic.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/LegacyPassManager.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/Module.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/Verifier.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
-
-#ifdef USE_SPLIT
 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/Analysis/MemorySSAUpdater.h"
-#endif
+#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/Pass.h"
 
-#if LLVM_VERSION_MAJOR > 3 || \
-    (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
-#include "llvm/IR/DebugInfo.h"
-#include "llvm/IR/CFG.h"
-#else
-#include "llvm/DebugInfo.h"
-#include "llvm/Support/CFG.h"
-#endif
+#include <set>
 
 using namespace llvm;
 
@@ -91,7 +78,6 @@ class AFLLTOPass : public ModulePass {
 
   }
 
-#ifdef USE_SPLIT
   void getAnalysisUsage(AnalysisUsage &AU) const override {
 
     ModulePass::getAnalysisUsage(AU);
@@ -100,8 +86,6 @@ class AFLLTOPass : public ModulePass {
 
   }
 
-#endif
-
   // Calculate the number of average collisions that would occur if all
   // location IDs would be assigned randomly (like normal afl/afl++).
   // This uses the "balls in bins" algorithm.
@@ -168,7 +152,7 @@ class AFLLTOPass : public ModulePass {
   bool runOnModule(Module &M) override;
 
  protected:
-  int      afl_global_id = 1, debug = 0;
+  int      afl_global_id = 1, debug = 0, autodictionary = 0;
   uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0, total_instr = 0;
 
 };
@@ -177,22 +161,19 @@ class AFLLTOPass : public ModulePass {
 
 bool AFLLTOPass::runOnModule(Module &M) {
 
-  LLVMContext &C = M.getContext();
+  LLVMContext &                    C = M.getContext();
+  std::vector<std::string>         dictionary;
+  std::vector<CallInst *>          calls;
+  DenseMap<Value *, std::string *> valueMap;
 
-  IntegerType *   Int8Ty = IntegerType::getInt8Ty(C);
-  IntegerType *   Int32Ty = IntegerType::getInt32Ty(C);
-  struct timeval  tv;
-  struct timezone tz;
-  u32             rand_seed;
+  IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
+  IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
 
-  /* Setup random() so we get Actually Random(TM) outputs from AFL_R() */
-  gettimeofday(&tv, &tz);
-  rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
-  AFL_SR(rand_seed);
+  if (getenv("AFL_DEBUG")) debug = 1;
 
   /* Show a banner */
 
-  if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
+  if ((isatty(2) && !getenv("AFL_QUIET")) || debug) {
 
     SAYF(cCYA "afl-llvm-lto" VERSION cRST
               " by Marc \"vanHauser\" Heuse <mh@mh-sec.de>\n");
@@ -201,9 +182,9 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
     be_quiet = 1;
 
-#if LLVM_VERSION_MAJOR < 9
-  char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO");
-#endif
+  if (getenv("AFL_LLVM_AUTODICTIONARY") ||
+      getenv("AFL_LLVM_LTO_AUTODICTIONARY"))
+    autodictionary = 1;
 
   /* Get globals for the SHM region and the previous location. Note that
      __afl_prev_loc is thread-local. */
@@ -224,14 +205,320 @@ bool AFLLTOPass::runOnModule(Module &M) {
     if (F.size() < 2) continue;
     if (isBlacklisted(&F)) continue;
 
-#ifdef USE_SPLIT
-      // DominatorTree &DT =
-      // getAnalysis<DominatorTreeWrapperPass>(F).getDomTree(); LoopInfo & LI =
-      // getAnalysis<LoopInfoWrapperPass>(F).getLoopInfo();
-#endif
-
     std::vector<BasicBlock *> InsBlocks;
 
+    if (autodictionary) {
+
+      /*  Some implementation notes.
+       *
+       *  We try to handle 3 cases:
+       *  - memcmp("foo", arg, 3) <- literal string
+       *  - static char globalvar[] = "foo";
+       *    memcmp(globalvar, arg, 3) <- global variable
+       *  - char localvar[] = "foo";
+       *    memcmp(locallvar, arg, 3) <- local variable
+       *
+       *  The local variable case is the hardest. We can only detect that
+       *  case if there is no reassignment or change in the variable.
+       *  And it might not work across llvm version.
+       *  What we do is hooking the initializer function for local variables
+       *  (llvm.memcpy.p0i8.p0i8.i64) and note the string and the assigned
+       *  variable. And if that variable is then used in a compare function
+       *  we use that noted string.
+       *  This seems not to work for tokens that have a size <= 4 :-(
+       *
+       *  - if the compared length is smaller than the string length we
+       *    save the full string. This is likely better for fuzzing but
+       *    might be wrong in a few cases depending on optimizers
+       *
+       *  - not using StringRef because there is a bug in the llvm 11
+       *    checkout I am using which sometimes points to wrong strings
+       *
+       *  Over and out. Took me a full day. damn. mh/vh
+       */
+
+      for (auto &BB : F) {
+
+        for (auto &IN : BB) {
+
+          CallInst *callInst = nullptr;
+
+          if ((callInst = dyn_cast<CallInst>(&IN))) {
+
+            bool    isStrcmp = true;
+            bool    isMemcmp = true;
+            bool    isStrncmp = true;
+            bool    isStrcasecmp = true;
+            bool    isStrncasecmp = true;
+            bool    isIntMemcpy = true;
+            bool    addedNull = false;
+            uint8_t optLen = 0;
+
+            Function *Callee = callInst->getCalledFunction();
+            if (!Callee) continue;
+            if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
+            std::string FuncName = Callee->getName().str();
+            isStrcmp &= !FuncName.compare("strcmp");
+            isMemcmp &= !FuncName.compare("memcmp");
+            isStrncmp &= !FuncName.compare("strncmp");
+            isStrcasecmp &= !FuncName.compare("strcasecmp");
+            isStrncasecmp &= !FuncName.compare("strncasecmp");
+            isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64");
+
+            if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
+                !isStrncasecmp && !isIntMemcpy)
+              continue;
+
+            /* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function
+             * prototype */
+            FunctionType *FT = Callee->getFunctionType();
+
+            isStrcmp &= FT->getNumParams() == 2 &&
+                        FT->getReturnType()->isIntegerTy(32) &&
+                        FT->getParamType(0) == FT->getParamType(1) &&
+                        FT->getParamType(0) ==
+                            IntegerType::getInt8PtrTy(M.getContext());
+            isStrcasecmp &= FT->getNumParams() == 2 &&
+                            FT->getReturnType()->isIntegerTy(32) &&
+                            FT->getParamType(0) == FT->getParamType(1) &&
+                            FT->getParamType(0) ==
+                                IntegerType::getInt8PtrTy(M.getContext());
+            isMemcmp &= FT->getNumParams() == 3 &&
+                        FT->getReturnType()->isIntegerTy(32) &&
+                        FT->getParamType(0)->isPointerTy() &&
+                        FT->getParamType(1)->isPointerTy() &&
+                        FT->getParamType(2)->isIntegerTy();
+            isStrncmp &= FT->getNumParams() == 3 &&
+                         FT->getReturnType()->isIntegerTy(32) &&
+                         FT->getParamType(0) == FT->getParamType(1) &&
+                         FT->getParamType(0) ==
+                             IntegerType::getInt8PtrTy(M.getContext()) &&
+                         FT->getParamType(2)->isIntegerTy();
+            isStrncasecmp &= FT->getNumParams() == 3 &&
+                             FT->getReturnType()->isIntegerTy(32) &&
+                             FT->getParamType(0) == FT->getParamType(1) &&
+                             FT->getParamType(0) ==
+                                 IntegerType::getInt8PtrTy(M.getContext()) &&
+                             FT->getParamType(2)->isIntegerTy();
+
+            if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
+                !isStrncasecmp && !isIntMemcpy)
+              continue;
+
+            /* is a str{n,}{case,}cmp/memcmp, check if we have
+             * str{case,}cmp(x, "const") or str{case,}cmp("const", x)
+             * strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x, ..)
+             * memcmp(x, "const", ..) or memcmp("const", x, ..) */
+            Value *Str1P = callInst->getArgOperand(0),
+                  *Str2P = callInst->getArgOperand(1);
+            std::string Str1, Str2;
+            StringRef   TmpStr;
+            bool        HasStr1 = getConstantStringInfo(Str1P, TmpStr);
+            if (TmpStr.empty())
+              HasStr1 = false;
+            else
+              Str1 = TmpStr.str();
+            bool HasStr2 = getConstantStringInfo(Str2P, TmpStr);
+            if (TmpStr.empty())
+              HasStr2 = false;
+            else
+              Str2 = TmpStr.str();
+
+            if (debug)
+              fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n",
+                      FuncName.c_str(), Str1P, Str1P->getName().str().c_str(),
+                      Str1.c_str(), HasStr1 == true ? "true" : "false", Str2P,
+                      Str2P->getName().str().c_str(), Str2.c_str(),
+                      HasStr2 == true ? "true" : "false");
+
+            // we handle the 2nd parameter first because of llvm memcpy
+            if (!HasStr2) {
+
+              auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
+              if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
+
+                if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
+
+                  if (auto *Array =
+                          dyn_cast<ConstantDataArray>(Var->getInitializer())) {
+
+                    HasStr2 = true;
+                    Str2 = Array->getAsString().str();
+
+                  }
+
+                }
+
+              }
+
+            }
+
+            // for the internal memcpy routine we only care for the second
+            // parameter and are not reporting anything.
+            if (isIntMemcpy == true) {
+
+              if (HasStr2 == true) {
+
+                Value *      op2 = callInst->getArgOperand(2);
+                ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
+                if (ilen) {
+
+                  uint64_t literalLength = Str2.size();
+                  uint64_t optLength = ilen->getZExtValue();
+                  if (literalLength + 1 == optLength) {
+
+                    Str2.append("\0", 1);  // add null byte
+                    addedNull = true;
+
+                  }
+
+                }
+
+                valueMap[Str1P] = new std::string(Str2);
+
+                if (debug)
+                  fprintf(stderr, "Saved: %s for %p\n", Str2.c_str(), Str1P);
+                continue;
+
+              }
+
+              continue;
+
+            }
+
+            // Neither a literal nor a global variable?
+            // maybe it is a local variable that we saved
+            if (!HasStr2) {
+
+              std::string *strng = valueMap[Str2P];
+              if (strng && !strng->empty()) {
+
+                Str2 = *strng;
+                HasStr2 = true;
+                if (debug)
+                  fprintf(stderr, "Filled2: %s for %p\n", strng->c_str(),
+                          Str2P);
+
+              }
+
+            }
+
+            if (!HasStr1) {
+
+              auto Ptr = dyn_cast<ConstantExpr>(Str1P);
+
+              if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
+
+                if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
+
+                  if (auto *Array =
+                          dyn_cast<ConstantDataArray>(Var->getInitializer())) {
+
+                    HasStr1 = true;
+                    Str1 = Array->getAsString().str();
+
+                  }
+
+                }
+
+              }
+
+            }
+
+            // Neither a literal nor a global variable?
+            // maybe it is a local variable that we saved
+            if (!HasStr1) {
+
+              std::string *strng = valueMap[Str1P];
+              if (strng && !strng->empty()) {
+
+                Str1 = *strng;
+                HasStr1 = true;
+                if (debug)
+                  fprintf(stderr, "Filled1: %s for %p\n", strng->c_str(),
+                          Str1P);
+
+              }
+
+            }
+
+            /* handle cases of one string is const, one string is variable */
+            if (!(HasStr1 ^ HasStr2)) continue;
+
+            std::string thestring;
+
+            if (HasStr1)
+              thestring = Str1;
+            else
+              thestring = Str2;
+
+            optLen = thestring.length();
+
+            if (isMemcmp || isStrncmp || isStrncasecmp) {
+
+              Value *      op2 = callInst->getArgOperand(2);
+              ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
+              if (ilen) {
+
+                uint64_t literalLength = optLen;
+                optLen = ilen->getZExtValue();
+                if (literalLength + 1 == optLen) {  // add null byte
+                  thestring.append("\0", 1);
+                  addedNull = true;
+
+                }
+
+              }
+
+            }
+
+            // add null byte if this is a string compare function and a null
+            // was not already added
+            if (addedNull == false && !isMemcmp) {
+
+              thestring.append("\0", 1);  // add null byte
+              optLen++;
+
+            }
+
+            if (!be_quiet) {
+
+              std::string outstring;
+              fprintf(stderr, "%s: length %u/%u \"", FuncName.c_str(), optLen,
+                      (unsigned int)thestring.length());
+              for (uint8_t i = 0; i < thestring.length(); i++) {
+
+                uint8_t c = thestring[i];
+                if (c <= 32 || c >= 127)
+                  fprintf(stderr, "\\x%02x", c);
+                else
+                  fprintf(stderr, "%c", c);
+
+              }
+
+              fprintf(stderr, "\"\n");
+
+            }
+
+            // we take the longer string, even if the compare was to a
+            // shorter part. Note that depending on the optimizer of the
+            // compiler this can be wrong, but it is more likely that this
+            // is helping the fuzzer
+            if (optLen != thestring.length()) optLen = thestring.length();
+            if (optLen > MAX_AUTO_EXTRA) optLen = MAX_AUTO_EXTRA;
+            if (optLen < MIN_AUTO_EXTRA)  // too short? skip
+              continue;
+
+            dictionary.push_back(thestring.substr(0, optLen));
+
+          }
+
+        }
+
+      }
+
+    }
+
     for (auto &BB : F) {
 
       uint32_t succ = 0;
@@ -274,11 +561,7 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
         for (uint32_t j = 0; j < Successors.size(); j++) {
 
-#ifdef USE_SPLIT
           BasicBlock *newBB = llvm::SplitEdge(origBB, Successors[j]);
-#else
-          BasicBlock *newBB = BasicBlock::Create(C, "", &F, nullptr);
-#endif
 
           if (!newBB) {
 
@@ -287,12 +570,8 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
           }
 
-#ifdef USE_SPLIT
           BasicBlock::iterator IP = newBB->getFirstInsertionPt();
           IRBuilder<>          IRB(&(*IP));
-#else
-          IRBuilder<> IRB(&(*newBB));
-#endif
 
           /* Set the ID of the inserted basic block */
 
@@ -313,38 +592,12 @@ bool AFLLTOPass::runOnModule(Module &M) {
 
           Value *Incr = IRB.CreateAdd(Counter, One);
 
-#if LLVM_VERSION_MAJOR < 9
-          if (neverZero_counters_str !=
-              NULL) {  // with llvm 9 we make this the default as the bug in
-                       // llvm is then fixed
-#endif
-            auto cf = IRB.CreateICmpEQ(Incr, Zero);
-            auto carry = IRB.CreateZExt(cf, Int8Ty);
-            Incr = IRB.CreateAdd(Incr, carry);
-#if LLVM_VERSION_MAJOR < 9
-
-          }
-
-#endif
+          auto cf = IRB.CreateICmpEQ(Incr, Zero);
+          auto carry = IRB.CreateZExt(cf, Int8Ty);
+          Incr = IRB.CreateAdd(Incr, carry);
           IRB.CreateStore(Incr, MapPtrIdx)
               ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
 
-#ifdef USE_SPLIT
-          // nothing
-#else
-
-          // Unconditional jump to the destination BB
-
-          IRB.CreateBr(Successors[j]);
-
-          // Replace the original destination to this newly inserted BB
-
-          origBB->replacePhiUsesWith(Successors[j], newBB);
-          BasicBlock *S = Successors[j];
-          S->replacePhiUsesWith(origBB, newBB);
-          TI->setSuccessor(j, newBB);
-
-#endif
           // done :)
 
           inst_blocks++;
@@ -358,28 +611,147 @@ bool AFLLTOPass::runOnModule(Module &M) {
   }
 
   // save highest location ID to global variable
-
-  if (afl_global_id > MAP_SIZE) {
+  // do this after each function to fail faster
+  if (!be_quiet && afl_global_id > MAP_SIZE) {
 
     uint32_t pow2map = 1, map = afl_global_id;
     while ((map = map >> 1))
       pow2map++;
-    FATAL(
-        "We have %u blocks to instrument but the map size is only %u! Edit "
-        "config.h and set MAP_SIZE_POW2 from %u to %u, then recompile "
-        "afl-fuzz and llvm_mode.",
-        afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map);
+    WARNF(
+        "We have %u blocks to instrument but the map size is only %u. Either "
+        "edit config.h and set MAP_SIZE_POW2 from %u to %u, then recompile "
+        "afl-fuzz and llvm_mode and then make this target - or set "
+        "AFL_MAP_SIZE with at least size %u when running afl-fuzz with this "
+        "target.",
+        afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map, afl_global_id);
 
   }
 
-  if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
+  if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL || dictionary.size()) {
+
+    // yes we could create our own function, insert it into ctors ...
+    // but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o
+
+    Function *f = M.getFunction("__afl_auto_init_globals");
+
+    if (!f) {
+
+      fprintf(stderr,
+              "Error: init function could not be found (this should not "
+              "happen)\n");
+      exit(-1);
+
+    }
+
+    BasicBlock *bb = &f->getEntryBlock();
+    if (!bb) {
+
+      fprintf(stderr,
+              "Error: init function does not have an EntryBlock (this should "
+              "not happen)\n");
+      exit(-1);
+
+    }
+
+    BasicBlock::iterator IP = bb->getFirstInsertionPt();
+    IRBuilder<>          IRB(&(*IP));
+
+    if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
 
-    GlobalVariable *AFLFinalLoc = new GlobalVariable(
-        M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc", 0,
-        GlobalVariable::GeneralDynamicTLSModel, 0, false);
-    ConstantInt *const_loc = ConstantInt::get(Int32Ty, afl_global_id);
-    AFLFinalLoc->setAlignment(4);
-    AFLFinalLoc->setInitializer(const_loc);
+      uint32_t write_loc = afl_global_id;
+
+      if (afl_global_id % 8) write_loc = (((afl_global_id + 8) >> 3) << 3);
+
+      if (write_loc <= MAP_SIZE && write_loc <= 0x800000) {
+
+        GlobalVariable *AFLFinalLoc = new GlobalVariable(
+            M, Int32Ty, true, GlobalValue::ExternalLinkage, 0,
+            "__afl_final_loc", 0, GlobalVariable::GeneralDynamicTLSModel, 0,
+            false);
+        ConstantInt *const_loc = ConstantInt::get(Int32Ty, write_loc);
+        StoreInst *  StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
+        StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"),
+                                   MDNode::get(C, None));
+
+      }
+
+    }
+
+    if (dictionary.size()) {
+
+      size_t memlen = 0, count = 0, offset = 0;
+      char * ptr;
+
+      for (auto token : dictionary) {
+
+        memlen += token.length();
+        count++;
+
+      }
+
+      if (!be_quiet)
+        printf("AUTODICTIONARY: %lu string%s found\n", count,
+               count == 1 ? "" : "s");
+
+      if (count) {
+
+        if ((ptr = (char *)malloc(memlen + count)) == NULL) {
+
+          fprintf(stderr, "Error: malloc for %lu bytes failed!\n",
+                  memlen + count);
+          exit(-1);
+
+        }
+
+        count = 0;
+
+        for (auto token : dictionary) {
+
+          if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) {
+
+            ptr[offset++] = (uint8_t)token.length();
+            memcpy(ptr + offset, token.c_str(), token.length());
+            offset += token.length();
+            count++;
+
+          }
+
+        }
+
+        GlobalVariable *AFLDictionaryLen = new GlobalVariable(
+            M, Int32Ty, false, GlobalValue::ExternalLinkage, 0,
+            "__afl_dictionary_len", 0, GlobalVariable::GeneralDynamicTLSModel,
+            0, false);
+        ConstantInt *const_len = ConstantInt::get(Int32Ty, offset);
+        StoreInst *StoreDictLen = IRB.CreateStore(const_len, AFLDictionaryLen);
+        StoreDictLen->setMetadata(M.getMDKindID("nosanitize"),
+                                  MDNode::get(C, None));
+
+        ArrayType *ArrayTy = ArrayType::get(IntegerType::get(C, 8), offset);
+        GlobalVariable *AFLInternalDictionary = new GlobalVariable(
+            M, ArrayTy, true, GlobalValue::ExternalLinkage,
+            ConstantDataArray::get(C,
+                                   *(new ArrayRef<char>((char *)ptr, offset))),
+            "__afl_internal_dictionary", 0,
+            GlobalVariable::GeneralDynamicTLSModel, 0, false);
+        AFLInternalDictionary->setInitializer(ConstantDataArray::get(
+            C, *(new ArrayRef<char>((char *)ptr, offset))));
+        AFLInternalDictionary->setConstant(true);
+
+        GlobalVariable *AFLDictionary = new GlobalVariable(
+            M, PointerType::get(Int8Ty, 0), false, GlobalValue::ExternalLinkage,
+            0, "__afl_dictionary");
+
+        Value *AFLDictOff = IRB.CreateGEP(AFLInternalDictionary, Zero);
+        Value *AFLDictPtr =
+            IRB.CreatePointerCast(AFLDictOff, PointerType::get(Int8Ty, 0));
+        StoreInst *StoreDict = IRB.CreateStore(AFLDictPtr, AFLDictionary);
+        StoreDict->setMetadata(M.getMDKindID("nosanitize"),
+                               MDNode::get(C, None));
+
+      }
+
+    }
 
   }
 
@@ -423,5 +795,5 @@ static RegisterPass<AFLLTOPass> X("afl-lto", "afl++ LTO instrumentation pass",
                                   false, false);
 
 static RegisterStandardPasses RegisterAFLLTOPass(
-    PassManagerBuilder::EP_OptimizerLast, registerAFLLTOPass);
+    PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerAFLLTOPass);
 
diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc
index b4249802..71abcd05 100644
--- a/llvm_mode/afl-llvm-pass.so.cc
+++ b/llvm_mode/afl-llvm-pass.so.cc
@@ -125,6 +125,7 @@ class AFLCoverage : public ModulePass {
   std::list<std::string> myWhitelist;
   uint32_t               ngram_size = 0;
   uint32_t               debug = 0;
+  uint32_t               map_size = MAP_SIZE;
   char *                 ctx_str = NULL;
 
 };
@@ -192,6 +193,19 @@ bool AFLCoverage::runOnModule(Module &M) {
 
     be_quiet = 1;
 
+  /*
+    char *ptr;
+    if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) {
+
+      map_size = atoi(ptr);
+      if (map_size < 8 || map_size > (1 << 29))
+        FATAL("illegal AFL_MAP_SIZE %u, must be between 2^3 and 2^30",
+    map_size); if (map_size % 8) map_size = (((map_size >> 3) + 1) << 3);
+
+    }
+
+  */
+
   /* Decide instrumentation ratio */
 
   char *       inst_ratio_str = getenv("AFL_INST_RATIO");
@@ -365,7 +379,7 @@ bool AFLCoverage::runOnModule(Module &M) {
       // if yes we store a context ID for this function in the global var
       if (has_calls) {
 
-        ConstantInt *NewCtx = ConstantInt::get(Int32Ty, AFL_R(MAP_SIZE));
+        ConstantInt *NewCtx = ConstantInt::get(Int32Ty, AFL_R(map_size));
         StoreInst *  StoreCtx = IRB.CreateStore(NewCtx, AFLContext);
         StoreCtx->setMetadata(M.getMDKindID("nosanitize"),
                               MDNode::get(C, None));
@@ -509,7 +523,7 @@ bool AFLCoverage::runOnModule(Module &M) {
       /* Make up cur_loc */
 
       // cur_loc++;
-      cur_loc = AFL_R(MAP_SIZE);
+      cur_loc = AFL_R(map_size);
 
 /* There is a problem with Ubuntu 18.04 and llvm 6.0 (see issue #63).
    The inline function successors() is not inlined and also not found at runtime
@@ -705,6 +719,56 @@ bool AFLCoverage::runOnModule(Module &M) {
 
   }
 
+  /*
+    // This is currently disabled because we not only need to create/insert a
+    // function (easy), but also add it as a constructor with an ID < 5
+
+    if (getenv("AFL_LLVM_DONTWRITEID") == NULL) {
+
+      // yes we could create our own function, insert it into ctors ...
+      // but this would be a pain in the butt ... so we use afl-llvm-rt.o
+
+      Function *f = ...
+
+      if (!f) {
+
+        fprintf(stderr,
+                "Error: init function could not be created (this should not
+    happen)\n"); exit(-1);
+
+      }
+
+      ... constructor for f = 4
+
+      BasicBlock *bb = &f->getEntryBlock();
+      if (!bb) {
+
+        fprintf(stderr,
+                "Error: init function does not have an EntryBlock (this should
+    not happen)\n"); exit(-1);
+
+      }
+
+      BasicBlock::iterator IP = bb->getFirstInsertionPt();
+      IRBuilder<>          IRB(&(*IP));
+
+      if (map_size <= 0x800000) {
+
+        GlobalVariable *AFLFinalLoc = new GlobalVariable(
+            M, Int32Ty, true, GlobalValue::ExternalLinkage, 0,
+            "__afl_final_loc", 0, GlobalVariable::GeneralDynamicTLSModel, 0,
+            false);
+        ConstantInt *const_loc = ConstantInt::get(Int32Ty, map_size);
+        StoreInst *  StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
+        StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"),
+                                     MDNode::get(C, None));
+
+      }
+
+    }
+
+  */
+
   /* Say something nice. */
 
   if (!be_quiet) {
diff --git a/llvm_mode/afl-llvm-rt-lto.o.c b/llvm_mode/afl-llvm-rt-lto.o.c
new file mode 100644
index 00000000..5921f968
--- /dev/null
+++ b/llvm_mode/afl-llvm-rt-lto.o.c
@@ -0,0 +1,23 @@
+/*
+   american fuzzy lop++ - LLVM instrumentation bootstrap
+   -----------------------------------------------------
+
+   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
+
+*/
+
+// to prevent the function from being removed
+unsigned char __afl_lto_mode = 0;
+
+/* Proper initialization routine. */
+
+__attribute__((constructor(0))) void __afl_auto_init_globals(void) {
+
+  __afl_lto_mode = 1;
+
+}
+
diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c
index 3651fd97..f286e66a 100644
--- a/llvm_mode/afl-llvm-rt.o.c
+++ b/llvm_mode/afl-llvm-rt.o.c
@@ -50,11 +50,7 @@
    Basically, we need to make sure that the forkserver is initialized after
    the LLVM-generated runtime initialization pass, not before. */
 
-#ifdef USE_TRACE_PC
 #define CONST_PRIO 5
-#else
-#define CONST_PRIO 0
-#endif                                                     /* ^USE_TRACE_PC */
 
 #include <sys/mman.h>
 #include <fcntl.h>
@@ -65,17 +61,20 @@
 
 u8  __afl_area_initial[MAP_SIZE];
 u8 *__afl_area_ptr = __afl_area_initial;
+u8 *__afl_dictionary;
 
 #ifdef __ANDROID__
 PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
 u32        __afl_final_loc;
 u32        __afl_prev_ctx;
 u32        __afl_cmp_counter;
+u32        __afl_dictionary_len;
 #else
 __thread PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX];
 __thread u32        __afl_final_loc;
 __thread u32        __afl_prev_ctx;
 __thread u32        __afl_cmp_counter;
+__thread u32        __afl_dictionary_len;
 #endif
 
 struct cmp_map *__afl_cmp_map;
@@ -100,6 +99,10 @@ static void __afl_map_shm(void) {
     const char *   shm_file_path = id_str;
     int            shm_fd = -1;
     unsigned char *shm_base = NULL;
+    unsigned int   map_size = MAP_SIZE
+
+        if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE) map_size =
+            __afl_final_loc;
 
     /* create the shared memory segment as if it was a file */
     shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
@@ -111,7 +114,7 @@ static void __afl_map_shm(void) {
     }
 
     /* map the shared memory segment to the address space of the process */
-    shm_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+    shm_base = mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
     if (shm_base == MAP_FAILED) {
 
       close(shm_fd);
@@ -187,8 +190,15 @@ static void __afl_map_shm(void) {
 #ifdef __linux__
 static void __afl_start_snapshots(void) {
 
-  static u8 tmp[4];
+  static u8 tmp[4] = {0, 0, 0, 0};
   s32       child_pid;
+  u32       status = 0;
+  u32       map_size = MAP_SIZE;
+  u32       already_read_first = 0;
+  u32       was_killed;
+
+  if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE)
+    map_size = __afl_final_loc;
 
   u8 child_stopped = 0;
 
@@ -197,16 +207,74 @@ static void __afl_start_snapshots(void) {
   /* Phone home and tell the parent that we're OK. If parent isn't there,
      assume we're not running in forkserver mode and just execute program. */
 
+  status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT);
+  if (map_size <= 0x800000)
+    status |= (FS_OPT_SET_MAPSIZE(map_size) | FS_OPT_MAPSIZE);
+  if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT;
+  memcpy(tmp, &status, 4);
+
   if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
 
+  if (__afl_dictionary_len > 0 && __afl_dictionary) {
+
+    if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
+
+    if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) ==
+        (FS_OPT_ENABLED | FS_OPT_AUTODICT)) {
+
+      // great lets pass the dictionary through the forkserver FD
+      u32 len = __afl_dictionary_len, offset = 0;
+      s32 ret;
+
+      if (write(FORKSRV_FD + 1, &len, 4) != 4) {
+
+        write(2, "Error: could not send dictionary len\n",
+              strlen("Error: could not send dictionary len\n"));
+        _exit(1);
+
+      }
+
+      while (len != 0) {
+
+        ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
+
+        if (ret < 1) {
+
+          write(2, "Error: could not send dictionary\n",
+                strlen("Error: could not send dictionary\n"));
+          _exit(1);
+
+        }
+
+        len -= ret;
+        offset += ret;
+
+      }
+
+    } else {
+
+      // uh this forkserver master does not understand extended option passing
+      // or does not want the dictionary
+      already_read_first = 1;
+
+    }
+
+  }
+
   while (1) {
 
-    u32 was_killed;
     int status;
 
-    /* Wait for parent by reading from the pipe. Abort if read fails. */
+    if (already_read_first) {
 
-    if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
+      already_read_first = 0;
+
+    } else {
+
+      /* Wait for parent by reading from the pipe. Abort if read fails. */
+      if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
+
+    }
 
     /* If we stopped the child in persistent mode, but there was a race
        condition and afl-fuzz already issued SIGKILL, write off the old
@@ -291,26 +359,92 @@ static void __afl_start_forkserver(void) {
 
 #endif
 
-  static u8 tmp[4];
-  s32       child_pid;
+  u8  tmp[4] = {0, 0, 0, 0};
+  s32 child_pid;
+  u32 status = 0;
+  u32 map_size = MAP_SIZE;
+  u32 already_read_first = 0;
+  u32 was_killed;
+
+  if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE)
+    map_size = __afl_final_loc;
 
   u8 child_stopped = 0;
 
   void (*old_sigchld_handler)(int) = 0;  // = signal(SIGCHLD, SIG_DFL);
 
+  if (map_size <= 0x800000)
+    status |= (FS_OPT_SET_MAPSIZE(map_size) | FS_OPT_MAPSIZE);
+  if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT;
+  if (status) status |= (FS_OPT_ENABLED);
+  memcpy(tmp, &status, 4);
+
   /* Phone home and tell the parent that we're OK. If parent isn't there,
      assume we're not running in forkserver mode and just execute program. */
 
   if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
 
+  if (__afl_dictionary_len > 0 && __afl_dictionary) {
+
+    if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
+
+    if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) ==
+        (FS_OPT_ENABLED | FS_OPT_AUTODICT)) {
+
+      // great lets pass the dictionary through the forkserver FD
+      u32 len = __afl_dictionary_len, offset = 0;
+      s32 ret;
+
+      if (write(FORKSRV_FD + 1, &len, 4) != 4) {
+
+        write(2, "Error: could not send dictionary len\n",
+              strlen("Error: could not send dictionary len\n"));
+        _exit(1);
+
+      }
+
+      while (len != 0) {
+
+        ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
+
+        if (ret < 1) {
+
+          write(2, "Error: could not send dictionary\n",
+                strlen("Error: could not send dictionary\n"));
+          _exit(1);
+
+        }
+
+        len -= ret;
+        offset += ret;
+
+      }
+
+    } else {
+
+      // uh this forkserver master does not understand extended option passing
+      // or does not want the dictionary
+      already_read_first = 1;
+
+    }
+
+  }
+
   while (1) {
 
-    u32 was_killed;
     int status;
 
     /* Wait for parent by reading from the pipe. Abort if read fails. */
 
-    if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
+    if (already_read_first) {
+
+      already_read_first = 0;
+
+    } else {
+
+      if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
+
+    }
 
     /* If we stopped the child in persistent mode, but there was a race
        condition and afl-fuzz already issued SIGKILL, write off the old
@@ -378,8 +512,12 @@ static void __afl_start_forkserver(void) {
 
 int __afl_persistent_loop(unsigned int max_cnt) {
 
-  static u8  first_pass = 1;
-  static u32 cycle_cnt;
+  static u8    first_pass = 1;
+  static u32   cycle_cnt;
+  unsigned int map_size = MAP_SIZE;
+
+  if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE)
+    map_size = __afl_final_loc;
 
   if (first_pass) {
 
@@ -390,7 +528,7 @@ int __afl_persistent_loop(unsigned int max_cnt) {
 
     if (is_persistent) {
 
-      memset(__afl_area_ptr, 0, MAP_SIZE);
+      memset(__afl_area_ptr, 0, map_size);
       __afl_area_ptr[0] = 1;
       memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
 
@@ -513,13 +651,30 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
 
 ///// CmpLog instrumentation
 
-void __cmplog_ins_hook1(uint8_t Arg1, uint8_t Arg2) {
+void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2) {
+
+  if (!__afl_cmp_map) return;
 
-  return;
+  uintptr_t k = (uintptr_t)__builtin_return_address(0);
+  k = (k >> 4) ^ (k << 8);
+  k &= CMP_MAP_W - 1;
+
+  __afl_cmp_map->headers[k].type = CMP_TYPE_INS;
+
+  u32 hits = __afl_cmp_map->headers[k].hits;
+  __afl_cmp_map->headers[k].hits = hits + 1;
+  // if (!__afl_cmp_map->headers[k].cnt)
+  //  __afl_cmp_map->headers[k].cnt = __afl_cmp_counter++;
+
+  __afl_cmp_map->headers[k].shape = 0;
+
+  hits &= CMP_MAP_H - 1;
+  __afl_cmp_map->log[k][hits].v0 = arg1;
+  __afl_cmp_map->log[k][hits].v1 = arg2;
 
 }
 
-void __cmplog_ins_hook2(uint16_t Arg1, uint16_t Arg2) {
+void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2) {
 
   if (!__afl_cmp_map) return;
 
@@ -531,19 +686,16 @@ void __cmplog_ins_hook2(uint16_t Arg1, uint16_t Arg2) {
 
   u32 hits = __afl_cmp_map->headers[k].hits;
   __afl_cmp_map->headers[k].hits = hits + 1;
-  // if (!__afl_cmp_map->headers[k].cnt)
-  //  __afl_cmp_map->headers[k].cnt = __afl_cmp_counter++;
 
   __afl_cmp_map->headers[k].shape = 1;
-  //__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
 
   hits &= CMP_MAP_H - 1;
-  __afl_cmp_map->log[k][hits].v0 = Arg1;
-  __afl_cmp_map->log[k][hits].v1 = Arg2;
+  __afl_cmp_map->log[k][hits].v0 = arg1;
+  __afl_cmp_map->log[k][hits].v1 = arg2;
 
 }
 
-void __cmplog_ins_hook4(uint32_t Arg1, uint32_t Arg2) {
+void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2) {
 
   if (!__afl_cmp_map) return;
 
@@ -559,12 +711,12 @@ void __cmplog_ins_hook4(uint32_t Arg1, uint32_t Arg2) {
   __afl_cmp_map->headers[k].shape = 3;
 
   hits &= CMP_MAP_H - 1;
-  __afl_cmp_map->log[k][hits].v0 = Arg1;
-  __afl_cmp_map->log[k][hits].v1 = Arg2;
+  __afl_cmp_map->log[k][hits].v0 = arg1;
+  __afl_cmp_map->log[k][hits].v1 = arg2;
 
 }
 
-void __cmplog_ins_hook8(uint64_t Arg1, uint64_t Arg2) {
+void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2) {
 
   if (!__afl_cmp_map) return;
 
@@ -580,8 +732,8 @@ void __cmplog_ins_hook8(uint64_t Arg1, uint64_t Arg2) {
   __afl_cmp_map->headers[k].shape = 7;
 
   hits &= CMP_MAP_H - 1;
-  __afl_cmp_map->log[k][hits].v0 = Arg1;
-  __afl_cmp_map->log[k][hits].v1 = Arg2;
+  __afl_cmp_map->log[k][hits].v0 = arg1;
+  __afl_cmp_map->log[k][hits].v1 = arg2;
 
 }
 
@@ -596,28 +748,28 @@ void __cmplog_ins_hook8(uint64_t Arg1, uint64_t Arg2) {
 #pragma weak __sanitizer_cov_trace_cmp4 = __cmplog_ins_hook4
 #pragma weak __sanitizer_cov_trace_cmp8 = __cmplog_ins_hook8
 #else
-void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2)
+void __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2)
     __attribute__((alias("__cmplog_ins_hook1")));
-void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2)
+void __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2)
     __attribute__((alias("__cmplog_ins_hook2")));
-void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2)
+void __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2)
     __attribute__((alias("__cmplog_ins_hook4")));
-void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2)
+void __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2)
     __attribute__((alias("__cmplog_ins_hook8")));
 
-void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2)
+void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2)
     __attribute__((alias("__cmplog_ins_hook1")));
-void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2)
+void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2)
     __attribute__((alias("__cmplog_ins_hook2")));
-void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2)
+void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2)
     __attribute__((alias("__cmplog_ins_hook4")));
-void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2)
+void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2)
     __attribute__((alias("__cmplog_ins_hook8")));
 #endif                                                /* defined(__APPLE__) */
 
-void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
+void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
 
-  for (uint64_t i = 0; i < Cases[0]; i++) {
+  for (uint64_t i = 0; i < cases[0]; i++) {
 
     uintptr_t k = (uintptr_t)__builtin_return_address(0) + i;
     k = (k >> 4) ^ (k << 8);
@@ -631,8 +783,8 @@ void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
     __afl_cmp_map->headers[k].shape = 7;
 
     hits &= CMP_MAP_H - 1;
-    __afl_cmp_map->log[k][hits].v0 = Val;
-    __afl_cmp_map->log[k][hits].v1 = Cases[i + 2];
+    __afl_cmp_map->log[k][hits].v0 = val;
+    __afl_cmp_map->log[k][hits].v1 = cases[i + 2];
 
   }
 
diff --git a/llvm_mode/compare-transform-pass.so.cc b/llvm_mode/compare-transform-pass.so.cc
index 2ca70659..84a9b8d9 100644
--- a/llvm_mode/compare-transform-pass.so.cc
+++ b/llvm_mode/compare-transform-pass.so.cc
@@ -112,11 +112,12 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
                                      const bool processStrcasecmp,
                                      const bool processStrncasecmp) {
 
-  std::vector<CallInst *> calls;
-  LLVMContext &           C = M.getContext();
-  IntegerType *           Int8Ty = IntegerType::getInt8Ty(C);
-  IntegerType *           Int32Ty = IntegerType::getInt32Ty(C);
-  IntegerType *           Int64Ty = IntegerType::getInt64Ty(C);
+  DenseMap<Value *, std::string *> valueMap;
+  std::vector<CallInst *>          calls;
+  LLVMContext &                    C = M.getContext();
+  IntegerType *                    Int8Ty = IntegerType::getInt8Ty(C);
+  IntegerType *                    Int32Ty = IntegerType::getInt32Ty(C);
+  IntegerType *                    Int64Ty = IntegerType::getInt64Ty(C);
 
 #if LLVM_VERSION_MAJOR < 9
   Constant *
@@ -263,6 +264,8 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
           bool isStrncmp = processStrncmp;
           bool isStrcasecmp = processStrcasecmp;
           bool isStrncasecmp = processStrncasecmp;
+          bool isIntMemcpy = true;
+          bool indirect = false;
 
           Function *Callee = callInst->getCalledFunction();
           if (!Callee) continue;
@@ -273,9 +276,10 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
           isStrncmp &= !FuncName.compare(StringRef("strncmp"));
           isStrcasecmp &= !FuncName.compare(StringRef("strcasecmp"));
           isStrncasecmp &= !FuncName.compare(StringRef("strncasecmp"));
+          isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64");
 
           if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
-              !isStrncasecmp)
+              !isStrncasecmp && !isIntMemcpy)
             continue;
 
           /* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function
@@ -309,7 +313,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
                            FT->getParamType(2)->isIntegerTy();
 
           if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
-              !isStrncasecmp)
+              !isStrncasecmp && !isIntMemcpy)
             continue;
 
           /* is a str{n,}{case,}cmp/memcmp, check if we have
@@ -322,6 +326,97 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
           bool      HasStr1 = getConstantStringInfo(Str1P, Str1);
           bool      HasStr2 = getConstantStringInfo(Str2P, Str2);
 
+          if (isIntMemcpy && HasStr2) {
+
+            valueMap[Str1P] = new std::string(Str2.str());
+            // fprintf(stderr, "saved %s for %p\n", Str2.str().c_str(), Str1P);
+            continue;
+
+          }
+
+          // not literal? maybe global or local variable
+          if (!(HasStr1 ^ HasStr2)) {
+
+            auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
+            if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
+
+              if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
+
+                if (auto *Array =
+                        dyn_cast<ConstantDataArray>(Var->getInitializer())) {
+
+                  HasStr2 = true;
+                  Str2 = Array->getAsString();
+                  valueMap[Str2P] = new std::string(Str2.str());
+                  // fprintf(stderr, "glo2 %s\n", Str2.str().c_str());
+
+                }
+
+              }
+
+            }
+
+            if (!HasStr2) {
+
+              auto *Ptr = dyn_cast<ConstantExpr>(Str1P);
+              if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
+
+                if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
+
+                  if (auto *Array =
+                          dyn_cast<ConstantDataArray>(Var->getInitializer())) {
+
+                    HasStr1 = true;
+                    Str1 = Array->getAsString();
+                    valueMap[Str1P] = new std::string(Str1.str());
+                    // fprintf(stderr, "glo1 %s\n", Str1.str().c_str());
+
+                  }
+
+                }
+
+              }
+
+            } else if (isIntMemcpy) {
+
+              valueMap[Str1P] = new std::string(Str2.str());
+              // fprintf(stderr, "saved\n");
+
+            }
+
+            if ((HasStr1 ^ HasStr2)) indirect = true;
+
+          }
+
+          if (isIntMemcpy) continue;
+
+          if (!(HasStr1 ^ HasStr2)) {
+
+            // do we have a saved local variable initialization?
+            std::string *val = valueMap[Str1P];
+            if (val && !val->empty()) {
+
+              Str1 = StringRef(*val);
+              HasStr1 = true;
+              indirect = true;
+              // fprintf(stderr, "loaded1 %s\n", Str1.str().c_str());
+
+            } else {
+
+              val = valueMap[Str2P];
+              if (val && !val->empty()) {
+
+                Str2 = StringRef(*val);
+                HasStr2 = true;
+                indirect = true;
+                // fprintf(stderr, "loaded2 %s\n", Str2.str().c_str());
+
+              }
+
+            }
+
+          }
+
           /* handle cases of one string is const, one string is variable */
           if (!(HasStr1 ^ HasStr2)) continue;
 
@@ -334,9 +429,8 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
             if (!ilen) continue;
             /* final precaution: if size of compare is larger than constant
              * string skip it*/
-            uint64_t literalLength =
-                HasStr1 ? GetStringLength(Str1P) : GetStringLength(Str2P);
-            if (literalLength < ilen->getZExtValue()) continue;
+            uint64_t literalLength = HasStr1 ? Str1.size() : Str2.size();
+            if (literalLength + 1 < ilen->getZExtValue()) continue;
 
           }
 
@@ -363,9 +457,9 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
     std::string TmpConstStr;
     Value *     VarStr;
     bool        HasStr1 = getConstantStringInfo(Str1P, Str1);
-    getConstantStringInfo(Str2P, Str2);
-    uint64_t constLen, sizedLen;
-    bool     isMemcmp =
+    bool        HasStr2 = getConstantStringInfo(Str2P, Str2);
+    uint64_t    constLen, sizedLen;
+    bool        isMemcmp =
         !callInst->getCalledFunction()->getName().compare(StringRef("memcmp"));
     bool isSizedcmp = isMemcmp ||
                       !callInst->getCalledFunction()->getName().compare(
@@ -389,6 +483,29 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp,
 
     }
 
+    if (!(HasStr1 ^ HasStr2)) {
+
+      // do we have a saved local or global variable initialization?
+      std::string *val = valueMap[Str1P];
+      if (val && !val->empty()) {
+
+        Str1 = StringRef(*val);
+        HasStr1 = true;
+
+      } else {
+
+        val = valueMap[Str2P];
+        if (val && !val->empty()) {
+
+          Str2 = StringRef(*val);
+          HasStr2 = true;
+
+        }
+
+      }
+
+    }
+
     if (HasStr1) {
 
       TmpConstStr = Str1.str();
diff --git a/qbdi_mode/build.sh b/qbdi_mode/build.sh
index e3786f40..b10971d9 100755
--- a/qbdi_mode/build.sh
+++ b/qbdi_mode/build.sh
@@ -52,6 +52,6 @@ ${compiler_prefix}${CC} -shared -o libdemo.so demo-so.c -w -g
 echo "[+] Building afl-fuzz for Android"
 # build afl-fuzz
 cd ..
-${compiler_prefix}${CC} -DANDROID_DISABLE_FANCY=1 -O3 -funroll-loops -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign -I include/ -DAFL_PATH=\"/usr/local/lib/afl\" -DBIN_PATH=\"/usr/local/bin\" -DDOC_PATH=\"/usr/local/share/doc/afl\" -Wno-unused-function src/afl-fuzz-misc.c src/afl-fuzz-extras.c src/afl-fuzz-queue.c src/afl-fuzz-one.c src/afl-fuzz-python.c src/afl-fuzz-stats.c src/afl-fuzz-init.c src/afl-fuzz.c src/afl-fuzz-bitmap.c src/afl-fuzz-run.c src/afl-fuzz-state.c src/afl-common.c src/afl-sharedmem.c src/afl-forkserver.c -o qbdi_mode/afl-fuzz  -ldl -w
+${compiler_prefix}${CC} -DANDROID_DISABLE_FANCY=1 -O3 -funroll-loops -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign -I include/ -DAFL_PATH=\"/usr/local/lib/afl\" -DBIN_PATH=\"/usr/local/bin\" -DDOC_PATH=\"/usr/local/share/doc/afl\" -Wno-unused-function src/afl-fuzz-*.c src/afl-fuzz.c src/afl-common.c src/afl-sharedmem.c src/afl-forkserver.c -o qbdi_mode/afl-fuzz  -ldl -w
 
 echo "[+] All done. Enjoy!"
diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh
index 118f6ebd..b34a149b 100755
--- a/qemu_mode/build_qemu_support.sh
+++ b/qemu_mode/build_qemu_support.sh
@@ -233,7 +233,9 @@ if [ "$ORIG_CPU_TARGET" = "" ]; then
   gcc test-instr.c -o test-instr || exit 1
 
   unset AFL_INST_RATIO
+  export ASAN_OPTIONS=detect_leaks=0
 
+  echo "[*] Comparing two afl-showmap -Q outputs..."
   echo 0 | ./afl-showmap -m none -Q -q -o .test-instr0 ./test-instr || exit 1
   echo 1 | ./afl-showmap -m none -Q -q -o .test-instr1 ./test-instr || exit 1
 
diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h
index 3bd107d7..06243141 100644
--- a/qemu_mode/patches/afl-qemu-cpu-inl.h
+++ b/qemu_mode/patches/afl-qemu-cpu-inl.h
@@ -293,7 +293,8 @@ static void print_mappings(void) {
 
 void afl_forkserver(CPUState *cpu) {
 
-  static unsigned char tmp[4];
+  u32           map_size = 0;
+  unsigned char tmp[4] = {0};
 
   if (forkserver_installed == 1) return;
   forkserver_installed = 1;
@@ -306,6 +307,15 @@ void afl_forkserver(CPUState *cpu) {
   int   t_fd[2];
   u8    child_stopped = 0;
 
+  // if in the future qemu has non-collding coverage then switch MAP_SIZE
+  // with the max ID value
+  if (MAP_SIZE <= 0x800000) {
+
+    map_size = (FS_OPT_ENABLED | FS_OPT_MAPSIZE | FS_OPT_SET_MAPSIZE(MAP_SIZE));
+    memcpy(tmp, &map_size, 4);
+
+  }
+
   /* Tell the parent that we're alive. If the parent doesn't want
      to talk, assume that we're not running in forkserver mode. */
 
diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h
index 72353967..1abec477 100644
--- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h
+++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h
@@ -53,11 +53,12 @@ static void afl_gen_compcov(target_ulong cur_loc, TCGv arg1, TCGv arg2,
 
     TCGv cur_loc_v = tcg_const_tl(cur_loc);
 
-    switch (ot) {
+    switch (ot & MO_SIZE) {
 
       case MO_64: gen_helper_afl_cmplog_64(cur_loc_v, arg1, arg2); break;
       case MO_32: gen_helper_afl_cmplog_32(cur_loc_v, arg1, arg2); break;
       case MO_16: gen_helper_afl_cmplog_16(cur_loc_v, arg1, arg2); break;
+      case MO_8: gen_helper_afl_cmplog_8(cur_loc_v, arg1, arg2); break;
       default: break;
 
     }
@@ -75,7 +76,7 @@ static void afl_gen_compcov(target_ulong cur_loc, TCGv arg1, TCGv arg2,
 
     if (cur_loc >= afl_inst_rms) return;
 
-    switch (ot) {
+    switch (ot & MO_SIZE) {
 
       case MO_64: gen_helper_afl_compcov_64(cur_loc_v, arg1, arg2); break;
       case MO_32: gen_helper_afl_compcov_32(cur_loc_v, arg1, arg2); break;
diff --git a/qemu_mode/patches/afl-qemu-tcg-runtime-inl.h b/qemu_mode/patches/afl-qemu-tcg-runtime-inl.h
index 1526f09c..a0246198 100644
--- a/qemu_mode/patches/afl-qemu-tcg-runtime-inl.h
+++ b/qemu_mode/patches/afl-qemu-tcg-runtime-inl.h
@@ -107,18 +107,39 @@ void HELPER(afl_compcov_64)(target_ulong cur_loc, target_ulong arg1,
 
 }
 
+void HELPER(afl_cmplog_8)(target_ulong cur_loc, target_ulong arg1,
+                          target_ulong arg2) {
+
+  register uintptr_t k = (uintptr_t)cur_loc;
+
+  __afl_cmp_map->headers[k].type = CMP_TYPE_INS;
+
+  u32 hits = __afl_cmp_map->headers[k].hits;
+  __afl_cmp_map->headers[k].hits = hits + 1;
+  // if (!__afl_cmp_map->headers[k].cnt)
+  //  __afl_cmp_map->headers[k].cnt = __afl_cmp_counter++;
+
+  __afl_cmp_map->headers[k].shape = 0;
+
+  hits &= CMP_MAP_H - 1;
+  __afl_cmp_map->log[k][hits].v0 = arg1;
+  __afl_cmp_map->log[k][hits].v1 = arg2;
+
+}
+
 void HELPER(afl_cmplog_16)(target_ulong cur_loc, target_ulong arg1,
                            target_ulong arg2) {
 
   register uintptr_t k = (uintptr_t)cur_loc;
 
+  __afl_cmp_map->headers[k].type = CMP_TYPE_INS;
+
   u32 hits = __afl_cmp_map->headers[k].hits;
   __afl_cmp_map->headers[k].hits = hits + 1;
   // if (!__afl_cmp_map->headers[k].cnt)
   //  __afl_cmp_map->headers[k].cnt = __afl_cmp_counter++;
 
   __afl_cmp_map->headers[k].shape = 1;
-  //__afl_cmp_map->headers[k].type = CMP_TYPE_INS;
 
   hits &= CMP_MAP_H - 1;
   __afl_cmp_map->log[k][hits].v0 = arg1;
@@ -131,6 +152,8 @@ void HELPER(afl_cmplog_32)(target_ulong cur_loc, target_ulong arg1,
 
   register uintptr_t k = (uintptr_t)cur_loc;
 
+  __afl_cmp_map->headers[k].type = CMP_TYPE_INS;
+
   u32 hits = __afl_cmp_map->headers[k].hits;
   __afl_cmp_map->headers[k].hits = hits + 1;
 
@@ -147,6 +170,8 @@ void HELPER(afl_cmplog_64)(target_ulong cur_loc, target_ulong arg1,
 
   register uintptr_t k = (uintptr_t)cur_loc;
 
+  __afl_cmp_map->headers[k].type = CMP_TYPE_INS;
+
   u32 hits = __afl_cmp_map->headers[k].hits;
   __afl_cmp_map->headers[k].hits = hits + 1;
 
diff --git a/qemu_mode/patches/tcg-runtime-head.diff b/qemu_mode/patches/tcg-runtime-head.diff
index 626c67ef..f250686e 100644
--- a/qemu_mode/patches/tcg-runtime-head.diff
+++ b/qemu_mode/patches/tcg-runtime-head.diff
@@ -2,7 +2,7 @@ diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h
 index 1bd39d13..81ef3973 100644
 --- a/accel/tcg/tcg-runtime.h
 +++ b/accel/tcg/tcg-runtime.h
-@@ -260,3 +260,13 @@ DEF_HELPER_FLAGS_4(gvec_leu8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+@@ -260,3 +260,14 @@ DEF_HELPER_FLAGS_4(gvec_leu8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
  DEF_HELPER_FLAGS_4(gvec_leu16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
  DEF_HELPER_FLAGS_4(gvec_leu32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
  DEF_HELPER_FLAGS_4(gvec_leu64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
@@ -12,6 +12,7 @@ index 1bd39d13..81ef3973 100644
 +DEF_HELPER_FLAGS_3(afl_compcov_16, TCG_CALL_NO_RWG, void, tl, tl, tl)
 +DEF_HELPER_FLAGS_3(afl_compcov_32, TCG_CALL_NO_RWG, void, tl, tl, tl)
 +DEF_HELPER_FLAGS_3(afl_compcov_64, TCG_CALL_NO_RWG, void, tl, tl, tl)
++DEF_HELPER_FLAGS_3(afl_cmplog_8, TCG_CALL_NO_RWG, void, tl, tl, tl)
 +DEF_HELPER_FLAGS_3(afl_cmplog_16, TCG_CALL_NO_RWG, void, tl, tl, tl)
 +DEF_HELPER_FLAGS_3(afl_cmplog_32, TCG_CALL_NO_RWG, void, tl, tl, tl)
 +DEF_HELPER_FLAGS_3(afl_cmplog_64, TCG_CALL_NO_RWG, void, tl, tl, tl)
diff --git a/qemu_mode/unsigaction/GNUmakefile b/qemu_mode/unsigaction/GNUmakefile
deleted file mode 100644
index 31fa8c55..00000000
--- a/qemu_mode/unsigaction/GNUmakefile
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# american fuzzy lop++ - unsigaction
-# --------------------------------
-#
-# Written by Andrea Fioraldi <andreafioraldi@gmail.com>
-#
-# Copyright 2019-2020 Andrea Fioraldi. 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
-#
-
-ifndef AFL_NO_X86
-
-all: lib_i386 lib_amd64
-
-lib_i386:
-	@$(CC) -m32 -fPIC -shared unsigaction.c -o unsigaction32.so 2>/dev/null ; if [ "$$?" = "0" ]; then echo "unsigaction32 build success"; else echo "unsigaction32 build failure (that's fine)"; fi
-
-lib_amd64:
-	$(CC) -fPIC -shared unsigaction.c -o unsigaction64.so
-
-clean:
-	rm -f unsigaction32.so unsigaction64.so
-
-else
-
-all:
-	@echo "[!] Note: skipping compilation of unsigaction (AFL_NO_X86 set)."
-
-endif
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index 427fbe6d..b2c0f841 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -36,6 +36,7 @@
 #include "hash.h"
 #include "sharedmem.h"
 #include "common.h"
+#include "forkserver.h"
 
 #include <stdio.h>
 #include <unistd.h>
@@ -57,7 +58,7 @@
 
 static s32 child_pid;                  /* PID of the tested program         */
 
-u8 *trace_bits;                        /* SHM with instrumentation bitmap   */
+static u8 *trace_bits;                 /* SHM with instrumentation bitmap   */
 
 static u8 *in_file,                    /* Analyzer input test case          */
     *prog_in;                          /* Targeted program input file       */
@@ -74,16 +75,16 @@ static u64 mem_limit = MEM_LIMIT;      /* Memory limit (MB)                 */
 
 static s32 dev_null_fd = -1;           /* FD to /dev/null                   */
 
-u8 edges_only,                         /* Ignore hit counts?                */
+static u8 edges_only,                  /* Ignore hit counts?                */
     use_hex_offsets,                   /* Show hex offsets?                 */
     use_stdin = 1;                     /* Use stdin for program input?      */
 
 static volatile u8 stop_soon,          /* Ctrl-C pressed?                   */
     child_timed_out;                   /* Child timed out?                  */
 
-static u8 qemu_mode;
-
 static u8 *target_path;
+static u8  qemu_mode;
+static u32 map_size = MAP_SIZE;
 
 /* Constants used for describing byte behavior. */
 
@@ -115,7 +116,7 @@ static u8 count_class_lookup[256] = {
 
 static void classify_counts(u8 *mem) {
 
-  u32 i = MAP_SIZE;
+  u32 i = map_size;
 
   if (edges_only) {
 
@@ -144,7 +145,7 @@ static void classify_counts(u8 *mem) {
 static inline u8 anything_set(void) {
 
   u32 *ptr = (u32 *)trace_bits;
-  u32  i = (MAP_SIZE >> 2);
+  u32  i = (map_size >> 2);
 
   while (i--)
     if (*(ptr++)) return 1;
@@ -209,7 +210,7 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
 /* Execute target application. Returns exec checksum, or 0 if program
    times out. */
 
-static u32 run_target(char **argv, u8 *mem, u32 len, u8 first_run) {
+static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) {
 
   static struct itimerval it;
   int                     status = 0;
@@ -217,7 +218,7 @@ static u32 run_target(char **argv, u8 *mem, u32 len, u8 first_run) {
   s32 prog_in_fd;
   u32 cksum;
 
-  memset(trace_bits, 0, MAP_SIZE);
+  memset(trace_bits, 0, map_size);
   MEM_BARRIER();
 
   prog_in_fd = write_to_file(prog_in, mem, len);
@@ -311,7 +312,7 @@ static u32 run_target(char **argv, u8 *mem, u32 len, u8 first_run) {
 
   }
 
-  cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST);
+  cksum = hash32(trace_bits, map_size, HASH_CONST);
 
   /* We don't actually care if the target is crashing or not,
      except that when it does, the checksum should be different. */
@@ -560,16 +561,16 @@ static void analyze(char **argv) {
        code. */
 
     in_data[i] ^= 0xff;
-    xor_ff = run_target(argv, in_data, in_len, 0);
+    xor_ff = analyze_run_target(argv, in_data, in_len, 0);
 
     in_data[i] ^= 0xfe;
-    xor_01 = run_target(argv, in_data, in_len, 0);
+    xor_01 = analyze_run_target(argv, in_data, in_len, 0);
 
     in_data[i] = (in_data[i] ^ 0x01) - 0x10;
-    sub_10 = run_target(argv, in_data, in_len, 0);
+    sub_10 = analyze_run_target(argv, in_data, in_len, 0);
 
     in_data[i] += 0x20;
-    add_10 = run_target(argv, in_data, in_len, 0);
+    add_10 = analyze_run_target(argv, in_data, in_len, 0);
     in_data[i] -= 0x10;
 
     /* Classify current behavior. */
@@ -795,8 +796,10 @@ static void usage(u8 *argv0) {
       "              (must contain abort_on_error=1 and symbolize=0)\n"
       "MSAN_OPTIONS: custom settings for MSAN\n"
       "              (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
-      "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
       "AFL_ANALYZE_HEX: print file offsets in hexadecimal instead of decimal\n"
+      "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
+      "              the target was compiled for\n"
+      "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
       "AFL_SKIP_BIN_CHECK: skip checking the location of and the target\n"
 
       , argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
@@ -805,61 +808,6 @@ static void usage(u8 *argv0) {
 
 }
 
-/* Find binary. */
-
-static void find_binary(u8 *fname) {
-
-  u8 *        env_path = 0;
-  struct stat st;
-
-  if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
-
-    target_path = ck_strdup(fname);
-
-    if (stat(target_path, &st) || !S_ISREG(st.st_mode) ||
-        !(st.st_mode & 0111) || st.st_size < 4)
-      FATAL("Program '%s' not found or not executable", fname);
-
-  } else {
-
-    while (env_path) {
-
-      u8 *cur_elem, *delim = strchr(env_path, ':');
-
-      if (delim) {
-
-        cur_elem = ck_alloc(delim - env_path + 1);
-        memcpy(cur_elem, env_path, delim - env_path);
-        delim++;
-
-      } else
-
-        cur_elem = ck_strdup(env_path);
-
-      env_path = delim;
-
-      if (cur_elem[0])
-        target_path = alloc_printf("%s/%s", cur_elem, fname);
-      else
-        target_path = ck_strdup(fname);
-
-      ck_free(cur_elem);
-
-      if (!stat(target_path, &st) && S_ISREG(st.st_mode) &&
-          (st.st_mode & 0111) && st.st_size >= 4)
-        break;
-
-      ck_free(target_path);
-      target_path = 0;
-
-    }
-
-    if (!target_path) FATAL("Program '%s' not found or not executable", fname);
-
-  }
-
-}
-
 /* Main entry point */
 
 int main(int argc, char **argv, char **envp) {
@@ -902,6 +850,8 @@ int main(int argc, char **argv, char **envp) {
         if (mem_limit_given) FATAL("Multiple -m options not supported");
         mem_limit_given = 1;
 
+        if (!optarg) { FATAL("Wrong usage of -m"); }
+
         if (!strcmp(optarg, "none")) {
 
           mem_limit = 0;
@@ -938,6 +888,8 @@ int main(int argc, char **argv, char **envp) {
         if (timeout_given) FATAL("Multiple -t options not supported");
         timeout_given = 1;
 
+        if (!optarg) FATAL("Wrong usage of -t");
+
         exec_tmout = atoi(optarg);
 
         if (exec_tmout < 10 || optarg[0] == '-')
@@ -982,18 +934,20 @@ int main(int argc, char **argv, char **envp) {
 
   if (optind == argc || !in_file) usage(argv[0]);
 
+  map_size = get_map_size();
+
   use_hex_offsets = !!get_afl_env("AFL_ANALYZE_HEX");
 
   check_environment_vars(envp);
 
   sharedmem_t shm = {0};
-  trace_bits = afl_shm_init(&shm, MAP_SIZE, 0);
+  trace_bits = afl_shm_init(&shm, map_size, 0);
   atexit(at_exit_handler);
   setup_signal_handlers();
 
   set_up_environment();
 
-  find_binary(argv[optind]);
+  target_path = find_binary(argv[optind]);
   detect_file_args(argv + optind, prog_in, &use_stdin);
 
   if (qemu_mode) {
@@ -1016,7 +970,7 @@ int main(int argc, char **argv, char **envp) {
   ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
        mem_limit, exec_tmout, edges_only ? ", edges only" : "");
 
-  run_target(use_argv, in_data, in_len, 1);
+  analyze_run_target(use_argv, in_data, in_len, 1);
 
   if (child_timed_out)
     FATAL("Target binary times out (adjusting -t may help).");
@@ -1028,6 +982,8 @@ int main(int argc, char **argv, char **envp) {
 
   OKF("We're done here. Have a nice day!\n");
 
+  if (target_path) ck_free(target_path);
+
   afl_shm_deinit(&shm);
 
   exit(0);
diff --git a/src/afl-common.c b/src/afl-common.c
index 73b3fa8a..6ef7a195 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -37,9 +37,14 @@
 #include <unistd.h>
 #endif
 #include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
 
 u8  be_quiet = 0;
 u8 *doc_path = "";
+u8  last_intr = 0;
 
 char *afl_environment_variables[] = {
 
@@ -58,15 +63,16 @@ char *afl_environment_variables[] = {
     "AFL_LD_HARD_FAIL", "AFL_LD_LIMIT_MB", "AFL_LD_NO_CALLOC_OVER",
     "AFL_LD_PRELOAD", "AFL_LD_VERBOSE", "AFL_LLVM_CMPLOG", "AFL_LLVM_INSTRIM",
     "AFL_LLVM_CTX", "AFL_LLVM_INSTRUMENT", "AFL_LLVM_INSTRIM_LOOPHEAD",
+    "AFL_LLVM_LTO_AUTODICTIONARY", "AFL_LLVM_AUTODICTIONARY",
     "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK", "AFL_LLVM_LAF_SPLIT_COMPARES",
     "AFL_LLVM_LAF_SPLIT_COMPARES_BITW", "AFL_LLVM_LAF_SPLIT_FLOATS",
     "AFL_LLVM_LAF_SPLIT_SWITCHES", "AFL_LLVM_LAF_TRANSFORM_COMPARES",
     "AFL_LLVM_NGRAM_SIZE", "AFL_NGRAM_SIZE", "AFL_LLVM_NOT_ZERO",
     "AFL_LLVM_WHITELIST", "AFL_NO_AFFINITY", "AFL_LLVM_LTO_STARTID",
     "AFL_LLVM_LTO_DONTWRITEID", "AFL_NO_ARITH", "AFL_NO_BUILTIN",
-    "AFL_NO_CPU_RED", "AFL_NO_FORKSRV", "AFL_NO_UI",
+    "AFL_NO_CPU_RED", "AFL_NO_FORKSRV", "AFL_NO_UI", "AFL_NO_PYTHON",
     "AFL_NO_X86",  // not really an env but we dont want to warn on it
-    "AFL_PATH", "AFL_PERFORMANCE_FILE",
+    "AFL_MAP_SIZE", "AFL_MAPSIZE", "AFL_PATH", "AFL_PERFORMANCE_FILE",
     //"AFL_PERSISTENT", // not implemented anymore, so warn additionally
     "AFL_POST_LIBRARY", "AFL_PRELOAD", "AFL_PYTHON_MODULE", "AFL_QEMU_COMPCOV",
     "AFL_QEMU_COMPCOV_DEBUG", "AFL_QEMU_DEBUG_MAPS", "AFL_QEMU_DISABLE_CACHE",
@@ -139,7 +145,7 @@ void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) {
 
 char **argv_cpy_dup(int argc, char **argv) {
 
-  u32 i = 0;
+  int i = 0;
 
   char **ret = ck_alloc((argc + 1) * sizeof(char *));
 
@@ -216,10 +222,12 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
 
     }
 
-  } else
+  } else {
 
     ck_free(own_copy);
 
+  }
+
   if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
 
     if (cp) ck_free(cp);
@@ -233,7 +241,7 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
        "Oops, unable to find the 'afl-qemu-trace' binary. The binary must be "
        "built\n"
        "    separately by following the instructions in "
-       "afl->qemu_mode/README.md. "
+       "qemu_mode/README.md. "
        "If you\n"
        "    already have the binary installed, you may need to specify "
        "AFL_PATH in the\n"
@@ -290,11 +298,10 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
     *rsl = 0;
 
     cp = alloc_printf("%s/afl-qemu-trace", own_copy);
-    ck_free(own_copy);
 
-    if (!access(cp, X_OK)) {
+    if (cp && !access(cp, X_OK)) {
 
-      if (cp != NULL) ck_free(cp);
+      ck_free(cp);
 
       cp = alloc_printf("%s/afl-wine-trace", own_copy);
 
@@ -307,10 +314,14 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
 
     }
 
-  } else
+    ck_free(own_copy);
+
+  } else {
 
     ck_free(own_copy);
 
+  }
+
   u8 *ncp = BIN_PATH "/afl-qemu-trace";
 
   if (!access(ncp, X_OK)) {
@@ -330,7 +341,7 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
        "Oops, unable to find the '%s' binary. The binary must be "
        "built\n"
        "    separately by following the instructions in "
-       "afl->qemu_mode/README.md. "
+       "qemu_mode/README.md. "
        "If you\n"
        "    already have the binary installed, you may need to specify "
        "AFL_PATH in the\n"
@@ -348,12 +359,85 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
 
 }
 
+/* Find binary, used by analyze, showmap, tmin
+   @returns the path, allocating the string */
+
+u8 *find_binary(u8 *fname) {
+
+  // TODO: Merge this function with check_binary of afl-fuzz-init.c
+
+  u8 *env_path = NULL;
+  u8 *target_path = NULL;
+
+  struct stat st;
+
+  if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
+
+    target_path = ck_strdup(fname);
+
+    if (stat(target_path, &st) || !S_ISREG(st.st_mode) ||
+        !(st.st_mode & 0111) || st.st_size < 4) {
+
+      free(target_path);
+      FATAL("Program '%s' not found or not executable", fname);
+
+    }
+
+  } else {
+
+    while (env_path) {
+
+      u8 *cur_elem, *delim = strchr(env_path, ':');
+
+      if (delim) {
+
+        cur_elem = ck_alloc(delim - env_path + 1);
+        memcpy(cur_elem, env_path, delim - env_path);
+        delim++;
+
+      } else {
+
+        cur_elem = ck_strdup(env_path);
+
+      }
+
+      env_path = delim;
+
+      if (cur_elem[0]) {
+
+        target_path = alloc_printf("%s/%s", cur_elem, fname);
+
+      } else {
+
+        target_path = ck_strdup(fname);
+
+      }
+
+      ck_free(cur_elem);
+
+      if (!stat(target_path, &st) && S_ISREG(st.st_mode) &&
+          (st.st_mode & 0111) && st.st_size >= 4)
+        break;
+
+      ck_free(target_path);
+      target_path = NULL;
+
+    }
+
+    if (!target_path) FATAL("Program '%s' not found or not executable", fname);
+
+  }
+
+  return target_path;
+
+}
+
 void check_environment_vars(char **envp) {
 
   if (be_quiet) return;
 
   int   index = 0, found = 0;
-  char *env;
+  char *env, *val;
   while ((env = envp[index++]) != NULL) {
 
     if (strncmp(env, "ALF_", 4) == 0) {
@@ -367,10 +451,21 @@ void check_environment_vars(char **envp) {
       while (match == 0 && afl_environment_variables[i] != NULL)
         if (strncmp(env, afl_environment_variables[i],
                     strlen(afl_environment_variables[i])) == 0 &&
-            env[strlen(afl_environment_variables[i])] == '=')
+            env[strlen(afl_environment_variables[i])] == '=') {
+
           match = 1;
-        else
+          if ((val = getenv(afl_environment_variables[i])) && !*val)
+            WARNF(
+                "AFL environment variable %s defined but is empty, this can "
+                "lead to unexpected consequences",
+                afl_environment_variables[i]);
+
+        } else {
+
           i++;
+
+        }
+
       if (match == 0) {
 
         WARNF("Mistyped AFL environment variable: %s", env);
@@ -398,6 +493,20 @@ char *get_afl_env(char *env) {
 
 }
 
+/* Read mask bitmap from file. This is for the -B option. */
+
+void read_bitmap(u8 *fname, u8 *map, size_t len) {
+
+  s32 fd = open(fname, O_RDONLY);
+
+  if (fd < 0) PFATAL("Unable to open '%s'", fname);
+
+  ck_read(fd, map, len, fname);
+
+  close(fd);
+
+}
+
 u64 get_cur_time(void) {
 
   struct timeval  tv;
@@ -743,7 +852,8 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) {
   Returns the time passed to read.
   If the wait times out, returns timeout_ms + 1;
   Returns 0 if an error occurred (fd closed, signal, ...); */
-u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms) {
+u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms,
+               volatile u8 *stop_soon_p) {
 
   struct timeval timeout;
   fd_set         readfds;
@@ -768,8 +878,8 @@ u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms) {
 
     } else if (sret < 0) {
 
-      // perror("sret malloc");
-      // TODO: catch other (errno == EINTR) than ctrl+c?
+      /* Retry select for all signals other than than ctrl+c */
+      if (errno == EINTR && !*stop_soon_p) { continue; }
       return 0;
 
     }
@@ -788,3 +898,21 @@ u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms) {
 
 }
 
+u32 get_map_size() {
+
+  uint32_t map_size = MAP_SIZE;
+  char *   ptr;
+
+  if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) {
+
+    map_size = atoi(ptr);
+    if (map_size < 8 || map_size > (1 << 29))
+      FATAL("illegal AFL_MAP_SIZE %u, must be between 2^3 and 2^30", map_size);
+    if (map_size % 8) map_size = (((map_size >> 3) + 1) << 3);
+
+  }
+
+  return map_size;
+
+}
+
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 11b359da..9b915a7a 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -8,7 +8,9 @@
 
    Now maintained by Marc Heuse <mh@mh-sec.de>,
                         Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
-                        Andrea Fioraldi <andreafioraldi@gmail.com>
+                        Andrea Fioraldi <andreafioraldi@gmail.com> and
+                        Dominik Maier <mail@dmnk.co>
+
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
    Copyright 2019-2020 AFLplusplus Project. All rights reserved.
@@ -38,10 +40,12 @@
 #include <time.h>
 #include <errno.h>
 #include <signal.h>
+#include <fcntl.h>
 #include <sys/time.h>
 #include <sys/wait.h>
 #include <sys/resource.h>
 #include <sys/select.h>
+#include <sys/stat.h>
 
 /**
  * The correct fds for reading and writing pipes
@@ -51,6 +55,12 @@
 
 list_t fsrv_list = {.element_prealloc_count = 0};
 
+static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) {
+
+  execv(fsrv->target_path, argv);
+
+}
+
 /* Initializes the struct */
 
 void afl_fsrv_init(afl_forkserver_t *fsrv) {
@@ -58,33 +68,68 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
   // this structure needs default so we initialize it if this was not done
   // already
 
-  fsrv->use_stdin = 1;
   fsrv->out_fd = -1;
   fsrv->out_dir_fd = -1;
   fsrv->dev_null_fd = -1;
 #ifndef HAVE_ARC4RANDOM
   fsrv->dev_urandom_fd = -1;
 #endif
+  /* Settings */
+  fsrv->use_stdin = 1;
+  fsrv->no_unlink = 0;
   fsrv->exec_tmout = EXEC_TIMEOUT;
   fsrv->mem_limit = MEM_LIMIT;
-  fsrv->child_pid = -1;
-  fsrv->out_dir_fd = -1;
+  fsrv->out_file = NULL;
 
+  /* exec related stuff */
+  fsrv->child_pid = -1;
+  fsrv->map_size = MAP_SIZE;
   fsrv->use_fauxsrv = 0;
-  fsrv->prev_timed_out = 0;
+  fsrv->last_run_timed_out = 0;
+
+  fsrv->init_child_func = fsrv_exec_child;
 
   list_append(&fsrv_list, fsrv);
 
 }
 
+/* Initialize a new forkserver instance, duplicating "global" settings */
+void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
+
+  fsrv_to->use_stdin = from->use_stdin;
+  fsrv_to->out_fd = from->out_fd;
+  fsrv_to->dev_null_fd = from->dev_null_fd;
+  fsrv_to->exec_tmout = from->exec_tmout;
+  fsrv_to->mem_limit = from->mem_limit;
+  fsrv_to->map_size = from->map_size;
+
+#ifndef HAVE_ARC4RANDOM
+  fsrv_to->dev_urandom_fd = from->dev_urandom_fd;
+#endif
+
+  // These are forkserver specific.
+  fsrv_to->out_dir_fd = -1;
+  fsrv_to->child_pid = -1;
+  fsrv_to->use_fauxsrv = 0;
+  fsrv_to->last_run_timed_out = 0;
+  fsrv_to->out_file = NULL;
+
+  fsrv_to->init_child_func = fsrv_exec_child;
+
+  list_append(&fsrv_list, fsrv_to);
+
+}
+
 /* Internal forkserver for dumb_mode=1 and non-forkserver mode runs.
   It execvs for each fork, forwarding exit codes and child pids to afl. */
 
 static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
 
-  unsigned char tmp[4] = {0};
+  unsigned char tmp[4] = {0, 0, 0, 0};
   pid_t         child_pid = -1;
 
+  if (!be_quiet) ACTF("Using Fauxserver:");
+
   /* Phone home and tell the parent that we're OK. If parent isn't there,
      assume we're not running in forkserver mode and just execute program. */
 
@@ -160,19 +205,29 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
    cloning a stopped child. So, we just execute once, and then send commands
    through a pipe. The other part of this logic is in afl-as.h / llvm_mode */
 
-void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
+void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
+                    volatile u8 *stop_soon_p, u8 debug_child_output) {
 
   int st_pipe[2], ctl_pipe[2];
   int status;
   s32 rlen;
 
-  if (fsrv->use_fauxsrv) ACTF("Using Fauxserver:");
+  if (!be_quiet) ACTF("Spinning up the fork server...");
+
+  if (fsrv->use_fauxsrv) {
+
+    /* TODO: Come up with sone nice way to initalize this all */
+
+    if (fsrv->init_child_func != fsrv_exec_child)
+      FATAL("Different forkserver not compatible with fauxserver");
 
-  if (!getenv("AFL_QUIET")) ACTF("Spinning up the fork server...");
+    fsrv->init_child_func = afl_fauxsrv_execv;
+
+  }
 
   if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed");
 
-  fsrv->child_timed_out = 0;
+  fsrv->last_run_timed_out = 0;
   fsrv->fsrv_pid = fork();
 
   if (fsrv->fsrv_pid < 0) PFATAL("fork() failed");
@@ -220,7 +275,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
 
     setsid();
 
-    if (!get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) {
+    if (!(debug_child_output)) {
 
       dup2(fsrv->dev_null_fd, 1);
       dup2(fsrv->dev_null_fd, 2);
@@ -253,7 +308,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
 #ifndef HAVE_ARC4RANDOM
     close(fsrv->dev_urandom_fd);
 #endif
-    close(fsrv->plot_file == NULL ? -1 : fileno(fsrv->plot_file));
+    if (fsrv->plot_file != NULL) fclose(fsrv->plot_file);
 
     /* This should improve performance a bit, since it stops the linker from
        doing extra work post-fork(). */
@@ -282,15 +337,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
            "msan_track_origins=0",
            0);
 
-    if (fsrv->use_fauxsrv) {
-
-      afl_fauxsrv_execv(fsrv, argv);
-
-    } else {
-
-      execv(fsrv->target_path, argv);
-
-    }
+    fsrv->init_child_func(fsrv, argv);
 
     /* Use a distinctive bitmap signature to tell the parent about execv()
        falling through. */
@@ -315,18 +362,23 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
   rlen = 0;
   if (fsrv->exec_tmout) {
 
-    rlen = 4;
-    u32 time = read_timed(fsrv->fsrv_st_fd, &status, rlen,
-                          fsrv->exec_tmout * FORK_WAIT_MULT);
+    u32 time = read_timed(fsrv->fsrv_st_fd, &status, 4,
+                          fsrv->exec_tmout * FORK_WAIT_MULT, stop_soon_p);
 
-    if (time > fsrv->exec_tmout * FORK_WAIT_MULT) {
+    if (!time) {
 
-      fsrv->child_timed_out = 1;
       kill(fsrv->fsrv_pid, SIGKILL);
 
-    }
+    } else if (time > fsrv->exec_tmout * FORK_WAIT_MULT) {
+
+      fsrv->last_run_timed_out = 1;
+      kill(fsrv->fsrv_pid, SIGKILL);
+
+    } else {
+
+      rlen = 4;
 
-    if (!time) { kill(fsrv->fsrv_pid, SIGKILL); }
+    }
 
   } else {
 
@@ -339,12 +391,113 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
 
   if (rlen == 4) {
 
-    if (!getenv("AFL_QUIET")) OKF("All right - fork server is up.");
+    if (!be_quiet) OKF("All right - fork server is up.");
+
+    if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
+
+      if (!be_quiet && getenv("AFL_DEBUG"))
+        ACTF("Extended forkserver functions received (%08x).", status);
+
+      if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) {
+
+        fsrv->snapshot = 1;
+        if (!be_quiet) ACTF("Using SNAPSHOT feature.");
+
+      }
+
+      if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) {
+
+        u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status);
+
+        if (!fsrv->map_size) fsrv->map_size = MAP_SIZE;
+
+        if (unlikely(tmp_map_size % 8)) {
+
+          // should not happen
+          WARNF("Target reported non-aligned map size of %ud", tmp_map_size);
+          tmp_map_size = (((tmp_map_size + 8) >> 3) << 3);
+
+        }
+
+        if (!be_quiet) ACTF("Target map size: %u", tmp_map_size);
+        if (tmp_map_size > fsrv->map_size)
+          FATAL(
+              "Target's coverage map size of %u is larger than the one this "
+              "afl++ is set with (%u) (change MAP_SIZE_POW2 in config.h and "
+              "recompile or set AFL_MAP_SIZE)\n",
+              tmp_map_size, fsrv->map_size);
+        fsrv->map_size = tmp_map_size;
+
+      }
+
+      if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) {
+
+        if (fsrv->function_ptr == NULL || fsrv->function_opt == NULL) {
+
+          // this is not afl-fuzz - we deny and return
+          status = (0xffffffff ^ (FS_OPT_ENABLED | FS_OPT_AUTODICT));
+          if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4)
+            FATAL("Writing to forkserver failed.");
+          return;
+
+        }
+
+        if (!be_quiet) ACTF("Using AUTODICT feature.");
+        status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
+        if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4)
+          FATAL("Writing to forkserver failed.");
+        if (read(fsrv->fsrv_st_fd, &status, 4) != 4)
+          FATAL("Reading from forkserver failed.");
+
+        if (status < 2 || (u32)status > 0xffffff)
+          FATAL("Dictionary has an illegal size: %d", status);
+
+        u32 len = status, offset = 0, count = 0;
+        u8 *dict = ck_alloc(len);
+        if (dict == NULL)
+          FATAL("Could not allocate %u bytes of autodictionary memory", len);
+
+        while (len != 0) {
+
+          rlen = read(fsrv->fsrv_st_fd, dict + offset, len);
+          if (rlen > 0) {
+
+            len -= rlen;
+            offset += rlen;
+
+          } else {
+
+            FATAL(
+                "Reading autodictionary fail at position %u with %u bytes "
+                "left.",
+                offset, len);
+
+          }
+
+        }
+
+        offset = 0;
+        while (offset < status && (u8)dict[offset] + offset < status) {
+
+          fsrv->function_ptr(fsrv->function_opt, dict + offset + 1,
+                             (u8)dict[offset]);
+          offset += (1 + dict[offset]);
+          count++;
+
+        }
+
+        if (!be_quiet) ACTF("Loaded %u autodictionary entries", count);
+        ck_free(dict);
+
+      }
+
+    }
+
     return;
 
   }
 
-  if (fsrv->child_timed_out)
+  if (fsrv->last_run_timed_out)
     FATAL("Timeout while initializing fork server (adjusting -t may help)");
 
   if (waitpid(fsrv->fsrv_pid, &status, 0) <= 0) PFATAL("waitpid() failed");
@@ -496,11 +649,186 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
 
 }
 
+static void afl_fsrv_kill(afl_forkserver_t *fsrv) {
+
+  if (fsrv->child_pid > 0) kill(fsrv->child_pid, SIGKILL);
+  if (fsrv->fsrv_pid > 0) {
+
+    kill(fsrv->fsrv_pid, SIGKILL);
+    if (waitpid(fsrv->fsrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); }
+
+  }
+
+}
+
+/* Delete the current testcase and write the buf to the testcase file */
+
+void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
+
+  s32 fd = fsrv->out_fd;
+
+  if (fsrv->out_file) {
+
+    if (fsrv->no_unlink) {
+
+      fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+
+    } else {
+
+      unlink(fsrv->out_file);                             /* Ignore errors. */
+      fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
+
+    }
+
+    if (fd < 0) PFATAL("Unable to create '%s'", fsrv->out_file);
+
+  } else {
+
+    lseek(fd, 0, SEEK_SET);
+
+  }
+
+  ck_write(fd, buf, len, fsrv->out_file);
+
+  if (!fsrv->out_file) {
+
+    if (ftruncate(fd, len)) PFATAL("ftruncate() failed");
+    lseek(fd, 0, SEEK_SET);
+
+  } else {
+
+    close(fd);
+
+  }
+
+}
+
+/* Execute target application, monitoring for timeouts. Return status
+   information. The called program will update afl->fsrv->trace_bits. */
+
+fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
+                                      volatile u8 *stop_soon_p) {
+
+  s32 res;
+  u32 exec_ms;
+
+  int status = 0;
+
+  /* After this memset, fsrv->trace_bits[] are effectively volatile, so we
+     must prevent any earlier operations from venturing into that
+     territory. */
+
+  memset(fsrv->trace_bits, 0, fsrv->map_size);
+
+  MEM_BARRIER();
+
+  /* we have the fork server (or faux server) up and running
+  First, tell it if the previous run timed out. */
+
+  if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->last_run_timed_out, 4)) != 4) {
+
+    if (*stop_soon_p) return 0;
+    RPFATAL(res, "Unable to request new process from fork server (OOM?)");
+
+  }
+
+  fsrv->last_run_timed_out = 0;
+
+  if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) {
+
+    if (*stop_soon_p) return 0;
+    RPFATAL(res, "Unable to request new process from fork server (OOM?)");
+
+  }
+
+  if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)");
+
+  exec_ms = read_timed(fsrv->fsrv_st_fd, &status, 4, timeout, stop_soon_p);
+
+  if (exec_ms > timeout) {
+
+    /* If there was no response from forkserver after timeout seconds,
+    we kill the child. The forkserver should inform us afterwards */
+
+    kill(fsrv->child_pid, SIGKILL);
+    fsrv->last_run_timed_out = 1;
+    if (read(fsrv->fsrv_st_fd, &status, 4) < 4) exec_ms = 0;
+
+  }
+
+  if (!exec_ms) {
+
+    if (*stop_soon_p) return 0;
+    SAYF("\n" cLRD "[-] " cRST
+         "Unable to communicate with fork server. Some possible reasons:\n\n"
+         "    - You've run out of memory. Use -m to increase the the memory "
+         "limit\n"
+         "      to something higher than %lld.\n"
+         "    - The binary or one of the libraries it uses manages to "
+         "create\n"
+         "      threads before the forkserver initializes.\n"
+         "    - The binary, at least in some circumstances, exits in a way "
+         "that\n"
+         "      also kills the parent process - raise() could be the "
+         "culprit.\n"
+         "    - If using persistent mode with QEMU, "
+         "AFL_QEMU_PERSISTENT_ADDR "
+         "is\n"
+         "      probably not valid (hint: add the base address in case of "
+         "PIE)"
+         "\n\n"
+         "If all else fails you can disable the fork server via "
+         "AFL_NO_FORKSRV=1.\n",
+         fsrv->mem_limit);
+    RPFATAL(res, "Unable to communicate with fork server");
+
+  }
+
+  if (!WIFSTOPPED(status)) fsrv->child_pid = 0;
+
+  fsrv->total_execs++;
+
+  /* Any subsequent operations on fsrv->trace_bits must not be moved by the
+     compiler below this point. Past this location, fsrv->trace_bits[]
+     behave very normally and do not have to be treated as volatile. */
+
+  MEM_BARRIER();
+
+  /* Report outcome to caller. */
+
+  if (WIFSIGNALED(status) && !*stop_soon_p) {
+
+    fsrv->last_kill_signal = WTERMSIG(status);
+
+    if (fsrv->last_run_timed_out && fsrv->last_kill_signal == SIGKILL)
+      return FSRV_RUN_TMOUT;
+
+    return FSRV_RUN_CRASH;
+
+  }
+
+  /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and
+     must use a special exit code. */
+
+  if (fsrv->uses_asan && WEXITSTATUS(status) == MSAN_ERROR) {
+
+    fsrv->last_kill_signal = 0;
+    return FSRV_RUN_CRASH;
+
+  }
+
+  // Fauxserver should handle this now.
+  // if (tb4 == EXEC_FAIL_SIG) return FSRV_RUN_ERROR;
+
+  return FSRV_RUN_OK;
+
+}
+
 void afl_fsrv_killall() {
 
   LIST_FOREACH(&fsrv_list, afl_forkserver_t, {
 
-    if (el->child_pid > 0) kill(el->child_pid, SIGKILL);
+    afl_fsrv_kill(el);
 
   });
 
@@ -508,6 +836,7 @@ void afl_fsrv_killall() {
 
 void afl_fsrv_deinit(afl_forkserver_t *fsrv) {
 
+  afl_fsrv_kill(fsrv);
   list_remove(&fsrv_list, fsrv);
 
 }
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index c5347dcb..0823deed 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -43,21 +43,7 @@ void write_bitmap(afl_state_t *afl) {
 
   if (fd < 0) PFATAL("Unable to open '%s'", fname);
 
-  ck_write(fd, afl->virgin_bits, MAP_SIZE, fname);
-
-  close(fd);
-
-}
-
-/* Read bitmap from file. This is for the -B option again. */
-
-void read_bitmap(afl_state_t *afl, u8 *fname) {
-
-  s32 fd = open(fname, O_RDONLY);
-
-  if (fd < 0) PFATAL("Unable to open '%s'", fname);
-
-  ck_read(fd, afl->virgin_bits, MAP_SIZE, fname);
+  ck_write(fd, afl->virgin_bits, afl->fsrv.map_size, fname);
 
   close(fd);
 
@@ -78,16 +64,18 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
   u64 *current = (u64 *)afl->fsrv.trace_bits;
   u64 *virgin = (u64 *)virgin_map;
 
-  u32 i = (MAP_SIZE >> 3);
+  u32 i = (afl->fsrv.map_size >> 3);
 
 #else
 
   u32 *current = (u32 *)afl->fsrv.trace_bits;
   u32 *virgin = (u32 *)virgin_map;
 
-  u32 i = (MAP_SIZE >> 2);
+  u32 i = (afl->fsrv.map_size >> 2);
 
 #endif                                                     /* ^WORD_SIZE_64 */
+  // the map size must be a minimum of 8 bytes.
+  // for variable/dynamic map sizes this is ensured in the forkserver
 
   u8 ret = 0;
 
@@ -97,6 +85,7 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
        that have not been already cleared from the virgin map - since this will
        almost always be the case. */
 
+    // the (*current) is unnecessary but speeds up the overall comparison
     if (unlikely(*current) && unlikely(*current & *virgin)) {
 
       if (likely(ret < 2)) {
@@ -109,18 +98,20 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
 
 #ifdef WORD_SIZE_64
 
-        if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) ||
-            (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff) ||
-            (cur[4] && vir[4] == 0xff) || (cur[5] && vir[5] == 0xff) ||
-            (cur[6] && vir[6] == 0xff) || (cur[7] && vir[7] == 0xff))
+        if (*virgin == 0xffffffffffffffff || (cur[0] && vir[0] == 0xff) ||
+            (cur[1] && vir[1] == 0xff) || (cur[2] && vir[2] == 0xff) ||
+            (cur[3] && vir[3] == 0xff) || (cur[4] && vir[4] == 0xff) ||
+            (cur[5] && vir[5] == 0xff) || (cur[6] && vir[6] == 0xff) ||
+            (cur[7] && vir[7] == 0xff))
           ret = 2;
         else
           ret = 1;
 
 #else
 
-        if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) ||
-            (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff))
+        if (*virgin == 0xffffffff || (cur[0] && vir[0] == 0xff) ||
+            (cur[1] && vir[1] == 0xff) || (cur[2] && vir[2] == 0xff) ||
+            (cur[3] && vir[3] == 0xff))
           ret = 2;
         else
           ret = 1;
@@ -138,7 +129,7 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
 
   }
 
-  if (unlikely(ret) && unlikely(virgin_map == afl->virgin_bits))
+  if (unlikely(ret) && likely(virgin_map == afl->virgin_bits))
     afl->bitmap_changed = 1;
 
   return ret;
@@ -148,10 +139,10 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
 /* Count the number of bits set in the provided bitmap. Used for the status
    screen several times every second, does not have to be fast. */
 
-u32 count_bits(u8 *mem) {
+u32 count_bits(afl_state_t *afl, u8 *mem) {
 
   u32 *ptr = (u32 *)mem;
-  u32  i = (MAP_SIZE >> 2);
+  u32  i = (afl->fsrv.map_size >> 2);
   u32  ret = 0;
 
   while (i--) {
@@ -182,10 +173,10 @@ u32 count_bits(u8 *mem) {
    mostly to update the status screen or calibrate and examine confirmed
    new paths. */
 
-u32 count_bytes(u8 *mem) {
+u32 count_bytes(afl_state_t *afl, u8 *mem) {
 
   u32 *ptr = (u32 *)mem;
-  u32  i = (MAP_SIZE >> 2);
+  u32  i = (afl->fsrv.map_size >> 2);
   u32  ret = 0;
 
   while (i--) {
@@ -207,10 +198,10 @@ u32 count_bytes(u8 *mem) {
 /* Count the number of non-255 bytes set in the bitmap. Used strictly for the
    status screen, several calls per second or so. */
 
-u32 count_non_255_bytes(u8 *mem) {
+u32 count_non_255_bytes(afl_state_t *afl, u8 *mem) {
 
   u32 *ptr = (u32 *)mem;
-  u32  i = (MAP_SIZE >> 2);
+  u32  i = (afl->fsrv.map_size >> 2);
   u32  ret = 0;
 
   while (i--) {
@@ -245,9 +236,9 @@ const u8 simplify_lookup[256] = {
 
 #ifdef WORD_SIZE_64
 
-void simplify_trace(u64 *mem) {
+void simplify_trace(afl_state_t *afl, u64 *mem) {
 
-  u32 i = MAP_SIZE >> 3;
+  u32 i = (afl->fsrv.map_size >> 3);
 
   while (i--) {
 
@@ -278,9 +269,9 @@ void simplify_trace(u64 *mem) {
 
 #else
 
-void simplify_trace(u32 *mem) {
+void simplify_trace(afl_state_t *afl, u32 *mem) {
 
-  u32 i = MAP_SIZE >> 2;
+  u32 i = (afl->fsrv.map_size >> 2);
 
   while (i--) {
 
@@ -340,9 +331,11 @@ void init_count_class16(void) {
 
 #ifdef WORD_SIZE_64
 
-void classify_counts(u64 *mem) {
+void classify_counts(afl_forkserver_t *fsrv) {
+
+  u64 *mem = (u64 *)fsrv->trace_bits;
 
-  u32 i = MAP_SIZE >> 3;
+  u32 i = (fsrv->map_size >> 3);
 
   while (i--) {
 
@@ -367,9 +360,11 @@ void classify_counts(u64 *mem) {
 
 #else
 
-void classify_counts(u32 *mem) {
+void classify_counts(afl_forkserver_t *fsrv) {
+
+  u32 *mem = (u32 *)fsrv->trace_bits;
 
-  u32 i = MAP_SIZE >> 2;
+  u32 i = (fsrv->map_size >> 2);
 
   while (i--) {
 
@@ -396,11 +391,11 @@ void classify_counts(u32 *mem) {
    count information here. This is called only sporadically, for some
    new paths. */
 
-void minimize_bits(u8 *dst, u8 *src) {
+void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) {
 
   u32 i = 0;
 
-  while (i < MAP_SIZE) {
+  while (i < afl->fsrv.map_size) {
 
     if (*(src++)) dst[i >> 3] |= 1 << (i & 7);
     ++i;
@@ -520,14 +515,14 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
   if (unlikely(len == 0)) return 0;
 
   u8 *queue_fn = "";
-  u8  hnb;
+  u8  hnb = '\0';
   s32 fd;
   u8  keeping = 0, res;
 
   u8 fn[PATH_MAX];
 
   /* Update path frequency. */
-  u32 cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+  u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
 
   struct queue_entry *q = afl->queue;
   while (q) {
@@ -583,7 +578,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 
     res = calibrate_case(afl, afl->queue_top, mem, afl->queue_cycle - 1, 0);
 
-    if (unlikely(res == FAULT_ERROR))
+    if (unlikely(res == FSRV_RUN_ERROR))
       FATAL("Unable to execute target application");
 
     fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
@@ -597,7 +592,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 
   switch (fault) {
 
-    case FAULT_TMOUT:
+    case FSRV_RUN_TMOUT:
 
       /* Timeouts are not very interesting, but we're still obliged to keep
          a handful of samples. We use the presence of new bits in the
@@ -611,9 +606,9 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
       if (likely(!afl->dumb_mode)) {
 
 #ifdef WORD_SIZE_64
-        simplify_trace((u64 *)afl->fsrv.trace_bits);
+        simplify_trace(afl, (u64 *)afl->fsrv.trace_bits);
 #else
-        simplify_trace((u32 *)afl->fsrv.trace_bits);
+        simplify_trace(afl, (u32 *)afl->fsrv.trace_bits);
 #endif                                                     /* ^WORD_SIZE_64 */
 
         if (!has_new_bits(afl, afl->virgin_tmout)) return keeping;
@@ -630,15 +625,15 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 
         u8 new_fault;
         write_to_testcase(afl, mem, len);
-        new_fault = run_target(afl, afl->hang_tmout);
+        new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout);
 
         /* A corner case that one user reported bumping into: increasing the
            timeout actually uncovers a crash. Make sure we don't discard it if
            so. */
 
-        if (!afl->stop_soon && new_fault == FAULT_CRASH) goto keep_as_crash;
+        if (!afl->stop_soon && new_fault == FSRV_RUN_CRASH) goto keep_as_crash;
 
-        if (afl->stop_soon || new_fault != FAULT_TMOUT) return keeping;
+        if (afl->stop_soon || new_fault != FSRV_RUN_TMOUT) return keeping;
 
       }
 
@@ -660,7 +655,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 
       break;
 
-    case FAULT_CRASH:
+    case FSRV_RUN_CRASH:
 
     keep_as_crash:
 
@@ -675,9 +670,9 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
       if (likely(!afl->dumb_mode)) {
 
 #ifdef WORD_SIZE_64
-        simplify_trace((u64 *)afl->fsrv.trace_bits);
+        simplify_trace(afl, (u64 *)afl->fsrv.trace_bits);
 #else
-        simplify_trace((u32 *)afl->fsrv.trace_bits);
+        simplify_trace(afl, (u32 *)afl->fsrv.trace_bits);
 #endif                                                     /* ^WORD_SIZE_64 */
 
         if (!has_new_bits(afl, afl->virgin_crash)) return keeping;
@@ -689,7 +684,8 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 #ifndef SIMPLE_FILES
 
       snprintf(fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s", afl->out_dir,
-               afl->unique_crashes, afl->kill_signal, describe_op(afl, 0));
+               afl->unique_crashes, afl->fsrv.last_kill_signal,
+               describe_op(afl, 0));
 
 #else
 
@@ -703,9 +699,11 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 
         // if the user wants to be informed on new crashes - do that
 #if !TARGET_OS_IPHONE
-        if (system(afl->infoexec) == -1)
-          hnb += 0;  // we dont care if system errors, but we dont want a
-                     // compiler warning either
+        // we dont care if system errors, but we dont want a
+        // compiler warning either
+        // See
+        // https://stackoverflow.com/questions/11888594/ignoring-return-values-in-c
+        (void)(system(afl->infoexec) + 1);
 #else
         WARNF("command execution unsupported");
 #endif
@@ -713,11 +711,11 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
       }
 
       afl->last_crash_time = get_cur_time();
-      afl->last_crash_execs = afl->total_execs;
+      afl->last_crash_execs = afl->fsrv.total_execs;
 
       break;
 
-    case FAULT_ERROR: FATAL("Unable to execute target application");
+    case FSRV_RUN_ERROR: FATAL("Unable to execute target application");
 
     default: return keeping;
 
diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c
index f932f33b..12c814ba 100644
--- a/src/afl-fuzz-cmplog.c
+++ b/src/afl-fuzz-cmplog.c
@@ -29,478 +29,18 @@
 #include "afl-fuzz.h"
 #include "cmplog.h"
 
-void init_cmplog_forkserver(afl_state_t *afl) {
+typedef struct cmplog_data {
 
-  int st_pipe[2], ctl_pipe[2];
-  int status;
-  s32 rlen;
+} cmplog_data_t;
 
-  ACTF("Spinning up the cmplog fork server...");
+void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) {
 
-  if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed");
+  setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1);
 
-  afl->fsrv.child_timed_out = 0;
-  afl->cmplog_fsrv_pid = fork();
+  if (!fsrv->qemu_mode && argv[0] != fsrv->cmplog_binary)
+    argv[0] = fsrv->cmplog_binary;
 
-  if (afl->cmplog_fsrv_pid < 0) PFATAL("fork() failed");
-
-  if (!afl->cmplog_fsrv_pid) {
-
-    /* CHILD PROCESS */
-
-    struct rlimit r;
-
-    /* Umpf. On OpenBSD, the default fd limit for root users is set to
-       soft 128. Let's try to fix that... */
-
-    if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) {
-
-      r.rlim_cur = FORKSRV_FD + 2;
-      setrlimit(RLIMIT_NOFILE, &r);                        /* Ignore errors */
-
-    }
-
-    if (afl->fsrv.mem_limit) {
-
-      r.rlim_max = r.rlim_cur = ((rlim_t)afl->fsrv.mem_limit) << 20;
-
-#ifdef RLIMIT_AS
-      setrlimit(RLIMIT_AS, &r);                            /* Ignore errors */
-#else
-      /* This takes care of OpenBSD, which doesn't have RLIMIT_AS, but
-         according to reliable sources, RLIMIT_DATA covers anonymous
-         maps - so we should be getting good protection against OOM bugs. */
-
-      setrlimit(RLIMIT_DATA, &r);                          /* Ignore errors */
-#endif                                                        /* ^RLIMIT_AS */
-
-    }
-
-    /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered
-       before the dump is complete. */
-
-    //    r.rlim_max = r.rlim_cur = 0;
-    //    setrlimit(RLIMIT_CORE, &r);                      /* Ignore errors */
-
-    /* Isolate the process and configure standard descriptors. If
-       afl->fsrv.out_file is specified, stdin is /dev/null; otherwise,
-       afl->fsrv.out_fd is cloned instead. */
-
-    setsid();
-
-    if (!(afl->afl_env.afl_debug_child_output)) {
-
-      dup2(afl->fsrv.dev_null_fd, 1);
-      dup2(afl->fsrv.dev_null_fd, 2);
-
-    }
-
-    if (!afl->fsrv.use_stdin) {
-
-      dup2(afl->fsrv.dev_null_fd, 0);
-
-    } else {
-
-      dup2(afl->fsrv.out_fd, 0);
-      close(afl->fsrv.out_fd);
-
-    }
-
-    /* Set up control and status pipes, close the unneeded original fds. */
-
-    if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) PFATAL("dup2() failed");
-    if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) PFATAL("dup2() failed");
-
-    close(ctl_pipe[0]);
-    close(ctl_pipe[1]);
-    close(st_pipe[0]);
-    close(st_pipe[1]);
-
-    close(afl->fsrv.out_dir_fd);
-    close(afl->fsrv.dev_null_fd);
-#ifndef HAVE_ARC4RANDOM
-    close(afl->fsrv.dev_urandom_fd);
-#endif
-    close(afl->fsrv.plot_file == NULL ? -1 : fileno(afl->fsrv.plot_file));
-
-    /* This should improve performance a bit, since it stops the linker from
-       doing extra work post-fork(). */
-
-    if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0);
-
-    /* Set sane defaults for ASAN if nothing else specified. */
-
-    setenv("ASAN_OPTIONS",
-           "abort_on_error=1:"
-           "detect_leaks=0:"
-           "malloc_context_size=0:"
-           "symbolize=0:"
-           "allocator_may_return_null=1",
-           0);
-
-    /* MSAN is tricky, because it doesn't support abort_on_error=1 at this
-       point. So, we do this in a very hacky way. */
-
-    setenv("MSAN_OPTIONS",
-           "exit_code=" STRINGIFY(MSAN_ERROR) ":"
-           "symbolize=0:"
-           "abort_on_error=1:"
-           "malloc_context_size=0:"
-           "allocator_may_return_null=1:"
-           "msan_track_origins=0",
-           0);
-
-    setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1);
-
-    if (!afl->qemu_mode && afl->argv[0] != afl->cmplog_binary) {
-
-      ck_free(afl->argv[0]);
-      afl->argv[0] = afl->cmplog_binary;
-
-    }
-
-    execv(afl->argv[0], afl->argv);
-
-    /* Use a distinctive bitmap signature to tell the parent about execv()
-       falling through. */
-
-    *(u32 *)afl->fsrv.trace_bits = EXEC_FAIL_SIG;
-    exit(0);
-
-  }
-
-  /* PARENT PROCESS */
-
-  /* Close the unneeded endpoints. */
-
-  close(ctl_pipe[0]);
-  close(st_pipe[1]);
-
-  afl->cmplog_fsrv_ctl_fd = ctl_pipe[1];
-  afl->cmplog_fsrv_st_fd = st_pipe[0];
-
-  /* Wait for the fork server to come up, but don't wait too long. */
-
-  rlen = 0;
-  if (afl->fsrv.exec_tmout) {
-
-    rlen = 4;
-    u32 timeout_ms = afl->fsrv.exec_tmout * FORK_WAIT_MULT;
-    /* Reuse readfds as exceptfds to see when the child closed the pipe */
-    u32 exec_ms = read_timed(afl->cmplog_fsrv_st_fd, &status, rlen, timeout_ms);
-
-    if (!exec_ms) {
-
-      PFATAL("Error in timed read");
-
-    } else if (exec_ms > timeout_ms) {
-
-      afl->fsrv.child_timed_out = 1;
-      kill(afl->cmplog_fsrv_pid, SIGKILL);
-      rlen = read(afl->cmplog_fsrv_st_fd, &status, 4);
-
-    }
-
-  } else {
-
-    rlen = read(afl->cmplog_fsrv_st_fd, &status, 4);
-
-  }
-
-  /* If we have a four-byte "hello" message from the server, we're all set.
-     Otherwise, try to figure out what went wrong. */
-
-  if (afl->fsrv.child_timed_out)
-    FATAL(
-        "Timeout while initializing cmplog fork server (adjusting -t may "
-        "help)");
-
-  if (rlen == 4) {
-
-    OKF("All right - fork server is up.");
-    return;
-
-  }
-
-  if (waitpid(afl->cmplog_fsrv_pid, &status, 0) <= 0)
-    PFATAL("waitpid() failed");
-
-  if (WIFSIGNALED(status)) {
-
-    if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 500 &&
-        afl->fsrv.uses_asan) {
-
-      SAYF("\n" cLRD "[-] " cRST
-           "Whoops, the target binary crashed suddenly, "
-           "before receiving any input\n"
-           "    from the fuzzer! Since it seems to be built with ASAN and you "
-           "have a\n"
-           "    restrictive memory limit configured, this is expected; please "
-           "read\n"
-           "    %s/notes_for_asan.md for help.\n",
-           doc_path);
-
-    } else if (!afl->fsrv.mem_limit) {
-
-      SAYF("\n" cLRD "[-] " cRST
-           "Whoops, the target binary crashed suddenly, "
-           "before receiving any input\n"
-           "    from the fuzzer! There are several probable explanations:\n\n"
-
-           "    - The binary is just buggy and explodes entirely on its own. "
-           "If so, you\n"
-           "      need to fix the underlying problem or find a better "
-           "replacement.\n\n"
-
-           MSG_FORK_ON_APPLE
-
-           "    - Less likely, there is a horrible bug in the fuzzer. If other "
-           "options\n"
-           "      fail, poke <afl-users@googlegroups.com> for troubleshooting "
-           "tips.\n");
-
-    } else {
-
-      u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
-
-      SAYF("\n" cLRD "[-] " cRST
-           "Whoops, the target binary crashed suddenly, "
-           "before receiving any input\n"
-           "    from the fuzzer! There are several probable explanations:\n\n"
-
-           "    - The current memory limit (%s) is too restrictive, causing "
-           "the\n"
-           "      target to hit an OOM condition in the dynamic linker. Try "
-           "bumping up\n"
-           "      the limit with the -m setting in the command line. A simple "
-           "way confirm\n"
-           "      this diagnosis would be:\n\n"
-
-           MSG_ULIMIT_USAGE
-           " /path/to/fuzzed_app )\n\n"
-
-           "      Tip: you can use http://jwilk.net/software/recidivm to "
-           "quickly\n"
-           "      estimate the required amount of virtual memory for the "
-           "binary.\n\n"
-
-           "    - The binary is just buggy and explodes entirely on its own. "
-           "If so, you\n"
-           "      need to fix the underlying problem or find a better "
-           "replacement.\n\n"
-
-           MSG_FORK_ON_APPLE
-
-           "    - Less likely, there is a horrible bug in the fuzzer. If other "
-           "options\n"
-           "      fail, poke <afl-users@googlegroups.com> for troubleshooting "
-           "tips.\n",
-           stringify_mem_size(val_buf, sizeof(val_buf),
-                              afl->fsrv.mem_limit << 20),
-           afl->fsrv.mem_limit - 1);
-
-    }
-
-    FATAL("Cmplog fork server crashed with signal %d", WTERMSIG(status));
-
-  }
-
-  if (*(u32 *)afl->fsrv.trace_bits == EXEC_FAIL_SIG)
-    FATAL("Unable to execute target application ('%s')", afl->argv[0]);
-
-  if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 500 && afl->fsrv.uses_asan) {
-
-    SAYF("\n" cLRD "[-] " cRST
-         "Hmm, looks like the target binary terminated "
-         "before we could complete a\n"
-         "    handshake with the injected code. Since it seems to be built "
-         "with ASAN and\n"
-         "    you have a restrictive memory limit configured, this is "
-         "expected; please\n"
-         "    read %s/notes_for_asan.md for help.\n",
-         doc_path);
-
-  } else if (!afl->fsrv.mem_limit) {
-
-    SAYF("\n" cLRD "[-] " cRST
-         "Hmm, looks like the target binary terminated "
-         "before we could complete a\n"
-         "    handshake with the injected code. Perhaps there is a horrible "
-         "bug in the\n"
-         "    fuzzer. Poke <afl-users@googlegroups.com> for troubleshooting "
-         "tips.\n");
-
-  } else {
-
-    u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
-
-    SAYF(
-        "\n" cLRD "[-] " cRST
-        "Hmm, looks like the target binary terminated "
-        "before we could complete a\n"
-        "    handshake with the injected code. There are %s probable "
-        "explanations:\n\n"
-
-        "%s"
-        "    - The current memory limit (%s) is too restrictive, causing an "
-        "OOM\n"
-        "      fault in the dynamic linker. This can be fixed with the -m "
-        "option. A\n"
-        "      simple way to confirm the diagnosis may be:\n\n"
-
-        MSG_ULIMIT_USAGE
-        " /path/to/fuzzed_app )\n\n"
-
-        "      Tip: you can use http://jwilk.net/software/recidivm to quickly\n"
-        "      estimate the required amount of virtual memory for the "
-        "binary.\n\n"
-
-        "    - Less likely, there is a horrible bug in the fuzzer. If other "
-        "options\n"
-        "      fail, poke <afl-users@googlegroups.com> for troubleshooting "
-        "tips.\n",
-        getenv(DEFER_ENV_VAR) ? "three" : "two",
-        getenv(DEFER_ENV_VAR)
-            ? "    - You are using deferred forkserver, but __AFL_INIT() is "
-              "never\n"
-              "      reached before the program terminates.\n\n"
-            : "",
-        stringify_mem_size(val_buf, sizeof(val_buf), afl->fsrv.mem_limit << 20),
-        afl->fsrv.mem_limit - 1);
-
-  }
-
-  FATAL("Cmplog fork server handshake failed");
-
-}
-
-u8 run_cmplog_target(afl_state_t *afl, u32 timeout) {
-
-  int status = 0;
-  u32 exec_ms;
-
-  u32 tb4;
-  s32 res;
-
-  afl->fsrv.child_timed_out = 0;
-
-  /* After this memset, afl->fsrv.trace_bits[] are effectively volatile, so we
-     must prevent any earlier operations from venturing into that
-     territory. */
-
-  memset(afl->fsrv.trace_bits, 0, MAP_SIZE);
-  MEM_BARRIER();
-
-  /* Since we always have a forkserver (or a fauxserver) running, we can simply
-  tell them to have at it and read back the pid from it.*/
-
-  if ((res = write(afl->cmplog_fsrv_ctl_fd, &afl->cmplog_prev_timed_out, 4)) !=
-      4) {
-
-    if (afl->stop_soon) return 0;
-    RPFATAL(res,
-            "Unable to request new process from cmplog fork server (OOM?)");
-
-  }
-
-  if ((res = read(afl->cmplog_fsrv_st_fd, &afl->cmplog_child_pid, 4)) != 4) {
-
-    if (afl->stop_soon) return 0;
-    RPFATAL(res,
-            "Unable to request new process from cmplog fork server (OOM?)");
-
-  }
-
-  if (afl->cmplog_child_pid <= 0)
-    FATAL("Cmplog fork server is misbehaving (OOM?)");
-
-  /* Configure timeout, as requested by user, then wait for child to terminate.
-   */
-  exec_ms = read_timed(afl->cmplog_fsrv_st_fd, &status, 4, timeout);
-
-  if (exec_ms > timeout) {
-
-    /* If there was no response from forkserver after timeout seconds,
-    we kill the child. The forkserver should inform us afterwards */
-
-    kill(afl->cmplog_child_pid, SIGKILL);
-    afl->fsrv.child_timed_out = 1;
-
-    /* After killing the child, the forkserver should tell us */
-    if (!read(afl->cmplog_fsrv_st_fd, &status, 4)) exec_ms = 0;
-
-  }
-
-  if (!exec_ms) {  // Something went wrong.
-
-    if (afl->stop_soon) return 0;
-    SAYF("\n" cLRD "[-] " cRST
-         "Unable to communicate with fork server. Some possible reasons:\n\n"
-         "    - You've run out of memory. Use -m to increase the the memory "
-         "limit\n"
-         "      to something higher than %lld.\n"
-         "    - The binary or one of the libraries it uses manages to create\n"
-         "      threads before the forkserver initializes.\n"
-         "    - The binary, at least in some circumstances, exits in a way "
-         "that\n"
-         "      also kills the parent process - raise() could be the "
-         "culprit.\n\n"
-         "If all else fails you can disable the fork server via "
-         "AFL_NO_FORKSRV=1.\n",
-         afl->fsrv.mem_limit);
-    RPFATAL(res, "Unable to communicate with fork server");
-
-  }
-
-  if (!WIFSTOPPED(status)) afl->cmplog_child_pid = 0;
-
-  if (afl->slowest_exec_ms < exec_ms) afl->slowest_exec_ms = exec_ms;
-
-  ++afl->total_execs;
-
-  /* Any subsequent operations on afl->fsrv.trace_bits must not be moved by the
-     compiler below this point. Past this location, afl->fsrv.trace_bits[]
-     behave very normally and do not have to be treated as volatile. */
-
-  MEM_BARRIER();
-
-  tb4 = *(u32 *)afl->fsrv.trace_bits;
-
-#ifdef WORD_SIZE_64
-  classify_counts((u64 *)afl->fsrv.trace_bits);
-#else
-  classify_counts((u32 *)afl->fsrv.trace_bits);
-#endif                                                     /* ^WORD_SIZE_64 */
-
-  afl->cmplog_prev_timed_out = afl->fsrv.child_timed_out;
-
-  /* Report outcome to caller. */
-
-  if (WIFSIGNALED(status) && !afl->stop_soon) {
-
-    afl->kill_signal = WTERMSIG(status);
-
-    if (afl->fsrv.child_timed_out && afl->kill_signal == SIGKILL)
-      return FAULT_TMOUT;
-
-    return FAULT_CRASH;
-
-  }
-
-  /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and
-     must use a special exit code. */
-
-  if (afl->fsrv.uses_asan && WEXITSTATUS(status) == MSAN_ERROR) {
-
-    afl->kill_signal = 0;
-    return FAULT_CRASH;
-
-  }
-
-  if ((afl->dumb_mode == 1 || afl->no_forkserver) && tb4 == EXEC_FAIL_SIG)
-    return FAULT_ERROR;
-
-  return FAULT_NONE;
+  execv(argv[0], argv);
 
 }
 
@@ -522,11 +62,11 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
 
   write_to_testcase(afl, out_buf, len);
 
-  fault = run_cmplog_target(afl, afl->fsrv.exec_tmout);
+  fault = fuzz_run_target(afl, &afl->cmplog_fsrv, afl->fsrv.exec_tmout);
 
   if (afl->stop_soon) return 1;
 
-  if (fault == FAULT_TMOUT) {
+  if (fault == FSRV_RUN_TMOUT) {
 
     if (afl->subseq_tmouts++ > TMOUT_LIMIT) {
 
diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c
index 16806934..c366cc5b 100644
--- a/src/afl-fuzz-extras.c
+++ b/src/afl-fuzz-extras.c
@@ -130,6 +130,8 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
 
     wptr = afl->extras[afl->extras_cnt].data = ck_alloc(rptr - lptr);
 
+    if (!wptr) PFATAL("no mem for data");
+
     while (*lptr) {
 
       char *hexdigits = "0123456789abcdef";
@@ -305,10 +307,14 @@ static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) {
 }
 
 /* Maybe add automatic extra. */
+/* Ugly hack: afl state is transfered as u8* because we import data via
+   afl-forkserver.c - which is shared with other afl tools that do not
+   have the afl state struct */
 
-void maybe_add_auto(afl_state_t *afl, u8 *mem, u32 len) {
+void maybe_add_auto(void *afl_tmp, u8 *mem, u32 len) {
 
-  u32 i;
+  afl_state_t *afl = (afl_state_t *)afl_tmp;
+  u32          i;
 
   /* Allow users to specify that they don't want auto dictionaries. */
 
@@ -469,7 +475,7 @@ void load_auto(afl_state_t *afl) {
     if (len < 0) PFATAL("Unable to read from '%s'", fn);
 
     if (len >= MIN_AUTO_EXTRA && len <= MAX_AUTO_EXTRA)
-      maybe_add_auto(afl, tmp, len);
+      maybe_add_auto((u8 *)afl, tmp, len);
 
     close(fd);
     ck_free(fn);
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index efdde463..3da348d2 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -134,8 +134,15 @@ void bind_to_free_cpu(afl_state_t *afl) {
   for (i = 0; i < proccount; i++) {
 
 #if defined(__FreeBSD__)
-    if (procs[i].ki_oncpu < sizeof(cpu_used) && procs[i].ki_pctcpu > 60)
-      cpu_used[procs[i].ki_oncpu] = 1;
+    if (!strcmp(procs[i].ki_comm, "idle")) continue;
+
+    // fix when ki_oncpu = -1
+    int oncpu;
+    oncpu = procs[i].ki_oncpu;
+    if (oncpu == -1) oncpu = procs[i].ki_lastcpu;
+
+    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)
@@ -435,21 +442,6 @@ void read_testcases(afl_state_t *afl) {
 
 }
 
-/* Examine map coverage. Called once, for first test case. */
-
-static void check_map_coverage(afl_state_t *afl) {
-
-  u32 i;
-
-  if (count_bytes(afl->fsrv.trace_bits) < 100) return;
-
-  for (i = (1 << (MAP_SIZE_POW2 - 1)); i < MAP_SIZE; ++i)
-    if (afl->fsrv.trace_bits[i]) return;
-
-  WARNF("Recompile binary with newer version of afl to improve coverage!");
-
-}
-
 /* Perform dry run of all test cases to confirm that the app is working as
    expected. This is done only for the initial inputs, and only once. */
 
@@ -484,21 +476,19 @@ void perform_dry_run(afl_state_t *afl) {
 
     if (afl->stop_soon) return;
 
-    if (res == afl->crash_mode || res == FAULT_NOBITS)
+    if (res == afl->crash_mode || res == FSRV_RUN_NOBITS)
       SAYF(cGRA "    len = %u, map size = %u, exec speed = %llu us\n" cRST,
            q->len, q->bitmap_size, q->exec_us);
 
     switch (res) {
 
-      case FAULT_NONE:
-
-        if (q == afl->queue) check_map_coverage(afl);
+      case FSRV_RUN_OK:
 
         if (afl->crash_mode) FATAL("Test case '%s' does *NOT* crash", fn);
 
         break;
 
-      case FAULT_TMOUT:
+      case FSRV_RUN_TMOUT:
 
         if (afl->timeout_given) {
 
@@ -547,7 +537,7 @@ void perform_dry_run(afl_state_t *afl) {
 
         }
 
-      case FAULT_CRASH:
+      case FSRV_RUN_CRASH:
 
         if (afl->crash_mode) break;
 
@@ -641,13 +631,13 @@ void perform_dry_run(afl_state_t *afl) {
 
         FATAL("Test case '%s' results in a crash", fn);
 
-      case FAULT_ERROR:
+      case FSRV_RUN_ERROR:
 
         FATAL("Unable to execute target application ('%s')", afl->argv[0]);
 
-      case FAULT_NOINST: FATAL("No instrumentation detected");
+      case FSRV_RUN_NOINST: FATAL("No instrumentation detected");
 
-      case FAULT_NOBITS:
+      case FSRV_RUN_NOBITS:
 
         ++afl->useless_at_start;
 
@@ -1410,6 +1400,8 @@ void setup_dirs_fds(afl_state_t *afl) {
           "# unix_time, cycles_done, cur_path, paths_total, "
           "pending_total, pending_favs, map_size, unique_crashes, "
           "unique_hangs, max_depth, execs_per_sec\n");
+  fflush(afl->fsrv.plot_file);
+
   /* ignore errors */
 
 }
@@ -1844,8 +1836,6 @@ static void handle_stop_sig(int sig) {
 
     if (el->fsrv.child_pid > 0) kill(el->fsrv.child_pid, SIGKILL);
     if (el->fsrv.fsrv_pid > 0) kill(el->fsrv.fsrv_pid, SIGKILL);
-    if (el->cmplog_child_pid > 0) kill(el->cmplog_child_pid, SIGKILL);
-    if (el->cmplog_fsrv_pid > 0) kill(el->cmplog_fsrv_pid, SIGKILL);
 
   });
 
@@ -1979,7 +1969,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
 
 #endif                                                       /* ^!__APPLE__ */
 
-  if (!afl->qemu_mode && !afl->unicorn_mode && !afl->dumb_mode &&
+  if (!afl->fsrv.qemu_mode && !afl->unicorn_mode && !afl->dumb_mode &&
       !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
 
     SAYF("\n" cLRD "[-] " cRST
@@ -2006,7 +1996,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
 
   }
 
-  if ((afl->qemu_mode) &&
+  if ((afl->fsrv.qemu_mode) &&
       memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
 
     SAYF("\n" cLRD "[-] " cRST
@@ -2171,6 +2161,8 @@ void save_cmdline(afl_state_t *afl, u32 argc, char **argv) {
 
     u32 l = strlen(argv[i]);
 
+    if (!argv[i] || !buf) FATAL("null deref detected");
+
     memcpy(buf, argv[i], l);
     buf += l;
 
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index 754b2190..434b4673 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -27,14 +27,11 @@
 #include "afl-fuzz.h"
 
 void load_custom_mutator(afl_state_t *, const char *);
-#ifdef USE_PYTHON
-void load_custom_mutator_py(afl_state_t *, char *);
-#endif
 
 void setup_custom_mutator(afl_state_t *afl) {
 
   /* Try mutator library first */
-  u8 *fn = getenv("AFL_CUSTOM_MUTATOR_LIBRARY");
+  u8 *fn = afl->afl_env.afl_custom_mutator_library;
 
   if (fn) {
 
@@ -52,7 +49,7 @@ void setup_custom_mutator(afl_state_t *afl) {
 
   /* Try Python module */
 #ifdef USE_PYTHON
-  u8 *module_name = getenv("AFL_PYTHON_MODULE");
+  u8 *module_name = afl->afl_env.afl_python_module;
 
   if (module_name) {
 
@@ -67,7 +64,7 @@ void setup_custom_mutator(afl_state_t *afl) {
   }
 
 #else
-  if (getenv("AFL_PYTHON_MODULE"))
+  if (afl->afl_env.afl_python_module)
     FATAL("Your AFL binary was built without Python support");
 #endif
 
@@ -239,12 +236,12 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
 
     write_to_testcase(afl, retbuf, retlen);
 
-    fault = run_target(afl, afl->fsrv.exec_tmout);
+    fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
     ++afl->trim_execs;
 
-    if (afl->stop_soon || fault == FAULT_ERROR) { goto abort_trimming; }
+    if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; }
 
-    cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+    cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
 
     if (cksum == q->exec_cksum) {
 
@@ -257,7 +254,8 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
       if (!needs_write) {
 
         needs_write = 1;
-        memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits, MAP_SIZE);
+        memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits,
+               afl->fsrv.map_size);
 
       }
 
@@ -307,7 +305,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
     ck_write(fd, in_buf, q->len, q->fname);
     close(fd);
 
-    memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, MAP_SIZE);
+    memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size);
     update_bitmap_score(afl, q);
 
   }
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index b20bde90..a4ba739e 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -27,7 +27,7 @@
 
 /* MOpt */
 
-int select_algorithm(afl_state_t *afl) {
+static int select_algorithm(afl_state_t *afl) {
 
   int i_puppet, j_puppet;
 
@@ -442,14 +442,14 @@ u8 fuzz_one_original(afl_state_t *afl) {
 
   if (unlikely(afl->queue_cur->cal_failed)) {
 
-    u8 res = FAULT_TMOUT;
+    u8 res = FSRV_RUN_TMOUT;
 
     if (afl->queue_cur->cal_failed < CAL_CHANCES) {
 
       res =
           calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1, 0);
 
-      if (unlikely(res == FAULT_ERROR))
+      if (unlikely(res == FSRV_RUN_ERROR))
         FATAL("Unable to execute target application");
 
     }
@@ -471,7 +471,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
 
     u8 res = trim_case(afl, afl->queue_cur, in_buf);
 
-    if (unlikely(res == FAULT_ERROR))
+    if (unlikely(res == FSRV_RUN_ERROR))
       FATAL("Unable to execute target application");
 
     if (unlikely(afl->stop_soon)) {
@@ -501,7 +501,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
 
   if (unlikely(afl->use_radamsa > 1)) goto radamsa_stage;
 
-  if (afl->shm.cmplog_mode) {
+  if (afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized) {
 
     if (input_to_state_stage(afl, in_buf, out_buf, len,
                              afl->queue_cur->exec_cksum))
@@ -601,7 +601,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
 
     if (!afl->dumb_mode && (afl->stage_cur & 7) == 7) {
 
-      u32 cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+      u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
 
       if (afl->stage_cur == afl->stage_max - 1 && cksum == prev_cksum) {
 
@@ -613,7 +613,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
         ++a_len;
 
         if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA)
-          maybe_add_auto(afl, a_collect, a_len);
+          maybe_add_auto((u8 *)afl, a_collect, a_len);
 
       } else if (cksum != prev_cksum) {
 
@@ -621,7 +621,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
            worthwhile queued up, and collect that if the answer is yes. */
 
         if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA)
-          maybe_add_auto(afl, a_collect, a_len);
+          maybe_add_auto((u8 *)afl, a_collect, a_len);
 
         a_len = 0;
         prev_cksum = cksum;
@@ -761,7 +761,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
          without wasting time on checksums. */
 
       if (!afl->dumb_mode && len >= EFF_MIN_LEN)
-        cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+        cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
       else
         cksum = ~afl->queue_cur->exec_cksum;
 
@@ -2366,7 +2366,7 @@ abandon_entry:
 }
 
 /* MOpt mode */
-u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
+static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
 
   if (!MOpt_globals.is_pilot_mode) {
 
@@ -2469,14 +2469,14 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
 
   if (afl->queue_cur->cal_failed) {
 
-    u8 res = FAULT_TMOUT;
+    u8 res = FSRV_RUN_TMOUT;
 
     if (afl->queue_cur->cal_failed < CAL_CHANCES) {
 
       res =
           calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1, 0);
 
-      if (res == FAULT_ERROR) FATAL("Unable to execute target application");
+      if (res == FSRV_RUN_ERROR) FATAL("Unable to execute target application");
 
     }
 
@@ -2497,7 +2497,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
 
     u8 res = trim_case(afl, afl->queue_cur, in_buf);
 
-    if (res == FAULT_ERROR) FATAL("Unable to execute target application");
+    if (res == FSRV_RUN_ERROR) FATAL("Unable to execute target application");
 
     if (afl->stop_soon) {
 
@@ -2522,20 +2522,15 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
 
   orig_perf = perf_score = calculate_score(afl, afl->queue_cur);
 
-  /* Skip right away if -d is given, if we have done deterministic fuzzing on
-     this entry ourselves (was_fuzzed), or if it has gone through deterministic
-     testing in earlier, resumed runs (passed_det). */
+  if (afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized) {
 
-  if (afl->skip_deterministic || afl->queue_cur->was_fuzzed ||
-      afl->queue_cur->passed_det)
-    goto havoc_stage;
+    if (input_to_state_stage(afl, in_buf, out_buf, len,
+                             afl->queue_cur->exec_cksum))
+      goto abandon_entry;
 
-  /* Skip deterministic fuzzing if exec path checksum puts this out of scope
-     for this master instance. */
+  }
 
-  if (afl->master_max &&
-      (afl->queue_cur->exec_cksum % afl->master_max) != afl->master_id - 1)
-    goto havoc_stage;
+  /* Go to pacemker fuzzing if MOpt is doing well */
 
   cur_ms_lv = get_cur_time();
   if (!(afl->key_puppet == 0 &&
@@ -2549,6 +2544,21 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
 
   }
 
+  /* Skip right away if -d is given, if we have done deterministic fuzzing on
+     this entry ourselves (was_fuzzed), or if it has gone through deterministic
+     testing in earlier, resumed runs (passed_det). */
+
+  if (afl->skip_deterministic || afl->queue_cur->was_fuzzed ||
+      afl->queue_cur->passed_det)
+    goto havoc_stage;
+
+  /* Skip deterministic fuzzing if exec path checksum puts this out of scope
+     for this master instance. */
+
+  if (afl->master_max &&
+      (afl->queue_cur->exec_cksum % afl->master_max) != afl->master_id - 1)
+    goto havoc_stage;
+
   doing_det = 1;
 
   /*********************************************
@@ -2615,7 +2625,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
 
     if (!afl->dumb_mode && (afl->stage_cur & 7) == 7) {
 
-      u32 cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+      u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
 
       if (afl->stage_cur == afl->stage_max - 1 && cksum == prev_cksum) {
 
@@ -2627,7 +2637,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
         ++a_len;
 
         if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA)
-          maybe_add_auto(afl, a_collect, a_len);
+          maybe_add_auto((u8 *)afl, a_collect, a_len);
 
       } else if (cksum != prev_cksum) {
 
@@ -2635,7 +2645,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
            worthwhile queued up, and collect that if the answer is yes. */
 
         if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA)
-          maybe_add_auto(afl, a_collect, a_len);
+          maybe_add_auto((u8 *)afl, a_collect, a_len);
 
         a_len = 0;
         prev_cksum = cksum;
@@ -2775,7 +2785,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
          without wasting time on checksums. */
 
       if (!afl->dumb_mode && len >= EFF_MIN_LEN)
-        cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+        cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
       else
         cksum = ~afl->queue_cur->exec_cksum;
 
@@ -3593,7 +3603,6 @@ pacemaker_fuzzing:
   }
 
   s32 temp_len_puppet;
-  cur_ms_lv = get_cur_time();
 
   // for (; afl->swarm_now < swarm_num; ++afl->swarm_now)
   {
@@ -4167,8 +4176,6 @@ pacemaker_fuzzing:
                  afl->orig_hit_cnt_puppet))) {
 
           afl->key_puppet = 0;
-          cur_ms_lv = get_cur_time();
-          new_hit_cnt = afl->queued_paths + afl->unique_crashes;
           afl->orig_hit_cnt_puppet = 0;
           afl->last_limit_time_start = 0;
 
@@ -4377,7 +4384,7 @@ void pso_updating(afl_state_t *afl) {
 
 u8 fuzz_one(afl_state_t *afl) {
 
-  int key_val_lv = 0;
+  int key_val_lv_1 = 0, key_val_lv_2 = 0;
 
 #ifdef _AFL_DOCUMENT_MUTATIONS
 
@@ -4397,22 +4404,22 @@ u8 fuzz_one(afl_state_t *afl) {
 
 #endif
 
-  if (afl->limit_time_sig == 0) {
+  // if limit_time_sig == -1 then both are run after each other
 
-    key_val_lv = fuzz_one_original(afl);
+  if (afl->limit_time_sig <= 0) { key_val_lv_1 = fuzz_one_original(afl); }
 
-  } else {
+  if (afl->limit_time_sig != 0) {
 
     if (afl->key_module == 0)
-      key_val_lv = pilot_fuzzing(afl);
+      key_val_lv_2 = pilot_fuzzing(afl);
     else if (afl->key_module == 1)
-      key_val_lv = core_fuzzing(afl);
+      key_val_lv_2 = core_fuzzing(afl);
     else if (afl->key_module == 2)
       pso_updating(afl);
 
   }
 
-  return key_val_lv;
+  return (key_val_lv_1 | key_val_lv_2);
 
 #undef BUF_PARAMS
 
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
index 12c3a09d..d4519c6d 100644
--- a/src/afl-fuzz-python.c
+++ b/src/afl-fuzz-python.c
@@ -41,8 +41,8 @@ it just fills in `&py_mutator->something_buf, &py_mutator->something_size`. */
   (void **)&((py_mutator_t *)py_mutator)->name##_buf, \
       &((py_mutator_t *)py_mutator)->name##_size
 
-size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf,
-               u8 *add_buf, size_t add_buf_size, size_t max_size) {
+static size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf,
+                      u8 *add_buf, size_t add_buf_size, size_t max_size) {
 
   size_t    mutated_size;
   PyObject *py_args, *py_value;
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index 174d7d92..121eb3f1 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -195,7 +195,7 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
 
   /* For every byte set in afl->fsrv.trace_bits[], see if there is a previous
      winner, and how it compares to us. */
-  for (i = 0; i < MAP_SIZE; ++i)
+  for (i = 0; i < afl->fsrv.map_size; ++i)
 
     if (afl->fsrv.trace_bits[i]) {
 
@@ -248,8 +248,9 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
 
       if (!q->trace_mini) {
 
-        q->trace_mini = ck_alloc(MAP_SIZE >> 3);
-        minimize_bits(q->trace_mini, afl->fsrv.trace_bits);
+        u32 len = (afl->fsrv.map_size >> 3);
+        q->trace_mini = ck_alloc(len);
+        minimize_bits(afl, q->trace_mini, afl->fsrv.trace_bits);
 
       }
 
@@ -268,14 +269,15 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
 void cull_queue(afl_state_t *afl) {
 
   struct queue_entry *q;
-  u8                  temp_v[MAP_SIZE >> 3];
+  u32                 len = (afl->fsrv.map_size >> 3);
   u32                 i;
+  u8 *                temp_v = afl->map_tmp_buf;
 
   if (afl->dumb_mode || !afl->score_changed) return;
 
   afl->score_changed = 0;
 
-  memset(temp_v, 255, MAP_SIZE >> 3);
+  memset(temp_v, 255, len);
 
   afl->queued_favored = 0;
   afl->pending_favored = 0;
@@ -292,10 +294,10 @@ void cull_queue(afl_state_t *afl) {
   /* Let's see if anything in the bitmap isn't captured in temp_v.
      If yes, and if it has a afl->top_rated[] contender, let's use it. */
 
-  for (i = 0; i < MAP_SIZE; ++i)
+  for (i = 0; i < afl->fsrv.map_size; ++i)
     if (afl->top_rated[i] && (temp_v[i >> 3] & (1 << (i & 7)))) {
 
-      u32 j = MAP_SIZE >> 3;
+      u32 j = len;
 
       /* Remove all bits belonging to the current entry from temp_v. */
 
@@ -433,6 +435,8 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) {
 
       }
 
+      if (unlikely(!n_paths)) FATAL("Queue state corrupt");
+
       fuzz_mu = fuzz_total / n_paths;
       if (fuzz <= fuzz_mu) {
 
@@ -485,7 +489,7 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) {
       // the more often fuzz result paths are equal to this queue entry,
       // reduce its value
       perf_score *=
-          (1 - (double)((double)q->n_fuzz / (double)afl->total_execs));
+          (1 - (double)((double)q->n_fuzz / (double)afl->fsrv.total_execs));
 
       break;
 
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index 4acc204b..3e9af088 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -37,7 +37,7 @@ struct range {
 
 };
 
-struct range *add_range(struct range *ranges, u32 start, u32 end) {
+static struct range *add_range(struct range *ranges, u32 start, u32 end) {
 
   struct range *r = ck_alloc_nozero(sizeof(struct range));
   r->start = start;
@@ -47,7 +47,7 @@ struct range *add_range(struct range *ranges, u32 start, u32 end) {
 
 }
 
-struct range *pop_biggest_range(struct range **ranges) {
+static struct range *pop_biggest_range(struct range **ranges) {
 
   struct range *r = *ranges;
   struct range *prev = NULL;
@@ -88,7 +88,7 @@ static u8 get_exec_checksum(afl_state_t *afl, u8 *buf, u32 len, u32 *cksum) {
 
   if (unlikely(common_fuzz_stuff(afl, buf, len))) return 1;
 
-  *cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+  *cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
   return 0;
 
 }
@@ -115,32 +115,46 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u32 exec_cksum) {
   afl->stage_short = "colorization";
   afl->stage_max = 1000;
 
-  struct range *rng;
+  struct range *rng = NULL;
   afl->stage_cur = 0;
   while ((rng = pop_biggest_range(&ranges)) != NULL &&
          afl->stage_cur < afl->stage_max) {
 
     u32 s = rng->end - rng->start;
-    if (s == 0) goto empty_range;
 
-    memcpy(backup, buf + rng->start, s);
-    rand_replace(afl, buf + rng->start, s);
+    if (s != 0) {
 
-    u32 cksum;
-    if (unlikely(get_exec_checksum(afl, buf, len, &cksum))) goto checksum_fail;
+      /* Range not empty */
 
-    if (cksum != exec_cksum) {
+      memcpy(backup, buf + rng->start, s);
+      rand_replace(afl, buf + rng->start, s);
 
-      ranges = add_range(ranges, rng->start, rng->start + s / 2);
-      ranges = add_range(ranges, rng->start + s / 2 + 1, rng->end);
-      memcpy(buf + rng->start, backup, s);
+      u32 cksum;
+      u64 start_us = get_cur_time_us();
+      if (unlikely(get_exec_checksum(afl, buf, len, &cksum)))
+        goto checksum_fail;
 
-    } else
+      u64 stop_us = get_cur_time_us();
 
-      needs_write = 1;
+      /* Discard if the mutations change the paths or if it is too decremental
+        in speed */
+      if (cksum != exec_cksum ||
+          (stop_us - start_us > 2 * afl->queue_cur->exec_us)) {
+
+        ranges = add_range(ranges, rng->start, rng->start + s / 2);
+        ranges = add_range(ranges, rng->start + s / 2 + 1, rng->end);
+        memcpy(buf + rng->start, backup, s);
+
+      } else {
+
+        needs_write = 1;
+
+      }
+
+    }
 
-  empty_range:
     ck_free(rng);
+    rng = NULL;
     ++afl->stage_cur;
 
   }
@@ -157,6 +171,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u32 exec_cksum) {
     rng = ranges;
     ranges = ranges->next;
     ck_free(rng);
+    rng = NULL;
 
   }
 
@@ -189,6 +204,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u32 exec_cksum) {
   return 0;
 
 checksum_fail:
+  if (rng) ck_free(rng);
   ck_free(backup);
 
   while (ranges) {
@@ -196,9 +212,12 @@ checksum_fail:
     rng = ranges;
     ranges = ranges->next;
     ck_free(rng);
+    rng = NULL;
 
   }
 
+  // TODO: clang notices a _potential_ leak of mem pointed to by rng
+
   return 1;
 
 }
@@ -225,24 +244,25 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) {
 }
 
 static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
-                              u64 pattern, u64 repl, u32 idx, u8 *orig_buf,
-                              u8 *buf, u32 len, u8 do_reverse, u8 *status) {
+                              u64 pattern, u64 repl, u64 o_pattern, u32 idx,
+                              u8 *orig_buf, u8 *buf, u32 len, u8 do_reverse,
+                              u8 *status) {
 
   u64 *buf_64 = (u64 *)&buf[idx];
   u32 *buf_32 = (u32 *)&buf[idx];
   u16 *buf_16 = (u16 *)&buf[idx];
-  // u8*  buf_8  = &buf[idx];
-  // u64* o_buf_64 = (u64*)&orig_buf[idx];
-  // u32* o_buf_32 = (u32*)&orig_buf[idx];
-  // u16* o_buf_16 = (u16*)&orig_buf[idx];
-  // u8*  o_buf_8  = &orig_buf[idx];
+  u8 * buf_8 = &buf[idx];
+  u64 *o_buf_64 = (u64 *)&orig_buf[idx];
+  u32 *o_buf_32 = (u32 *)&orig_buf[idx];
+  u16 *o_buf_16 = (u16 *)&orig_buf[idx];
+  u8 * o_buf_8 = &orig_buf[idx];
 
   u32 its_len = len - idx;
   *status = 0;
 
   if (SHAPE_BYTES(h->shape) == 8) {
 
-    if (its_len >= 8 && *buf_64 == pattern) {  // && *o_buf_64 == pattern) {
+    if (its_len >= 8 && *buf_64 == pattern && *o_buf_64 == o_pattern) {
 
       *buf_64 = repl;
       if (unlikely(its_fuzz(afl, buf, len, status))) return 1;
@@ -253,15 +273,16 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
     // reverse encoding
     if (do_reverse)
       if (unlikely(cmp_extend_encoding(afl, h, SWAP64(pattern), SWAP64(repl),
-                                       idx, orig_buf, buf, len, 0, status)))
+                                       SWAP64(o_pattern), idx, orig_buf, buf,
+                                       len, 0, status)))
         return 1;
 
   }
 
   if (SHAPE_BYTES(h->shape) == 4 || *status == 2) {
 
-    if (its_len >= 4 &&
-        *buf_32 == (u32)pattern) {  // && *o_buf_32 == (u32)pattern) {
+    if (its_len >= 4 && *buf_32 == (u32)pattern &&
+        *o_buf_32 == (u32)o_pattern) {
 
       *buf_32 = (u32)repl;
       if (unlikely(its_fuzz(afl, buf, len, status))) return 1;
@@ -272,15 +293,16 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
     // reverse encoding
     if (do_reverse)
       if (unlikely(cmp_extend_encoding(afl, h, SWAP32(pattern), SWAP32(repl),
-                                       idx, orig_buf, buf, len, 0, status)))
+                                       SWAP32(o_pattern), idx, orig_buf, buf,
+                                       len, 0, status)))
         return 1;
 
   }
 
   if (SHAPE_BYTES(h->shape) == 2 || *status == 2) {
 
-    if (its_len >= 2 &&
-        *buf_16 == (u16)pattern) {  // && *o_buf_16 == (u16)pattern) {
+    if (its_len >= 2 && *buf_16 == (u16)pattern &&
+        *o_buf_16 == (u16)o_pattern) {
 
       *buf_16 = (u16)repl;
       if (unlikely(its_fuzz(afl, buf, len, status))) return 1;
@@ -291,23 +313,23 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
     // reverse encoding
     if (do_reverse)
       if (unlikely(cmp_extend_encoding(afl, h, SWAP16(pattern), SWAP16(repl),
-                                       idx, orig_buf, buf, len, 0, status)))
+                                       SWAP16(o_pattern), idx, orig_buf, buf,
+                                       len, 0, status)))
         return 1;
 
   }
 
-  /*if (SHAPE_BYTES(h->shape) == 1 || *status == 2) {
+  if (SHAPE_BYTES(h->shape) == 1 || *status == 2) {
 
-    if (its_len >= 2 && *buf_8 == (u8)pattern) {// && *o_buf_8 == (u8)pattern) {
+    if (its_len >= 1 && *buf_8 == (u8)pattern && *o_buf_8 == (u8)o_pattern) {
 
       *buf_8 = (u8)repl;
-      if (unlikely(its_fuzz(afl, buf, len, status)))
-        return 1;
-      *buf_16 = (u16)pattern;
+      if (unlikely(its_fuzz(afl, buf, len, status))) return 1;
+      *buf_8 = (u8)pattern;
 
     }
 
-  }*/
+  }
 
   return 0;
 
@@ -332,7 +354,7 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) {
 
   }
 
-  maybe_add_auto(afl, (u8 *)&v, shape);
+  maybe_add_auto((u8 *)afl, (u8 *)&v, shape);
 
   u64 rev;
   switch (shape) {
@@ -340,15 +362,15 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) {
     case 1: break;
     case 2:
       rev = SWAP16((u16)v);
-      maybe_add_auto(afl, (u8 *)&rev, shape);
+      maybe_add_auto((u8 *)afl, (u8 *)&rev, shape);
       break;
     case 4:
       rev = SWAP32((u32)v);
-      maybe_add_auto(afl, (u8 *)&rev, shape);
+      maybe_add_auto((u8 *)afl, (u8 *)&rev, shape);
       break;
     case 8:
       rev = SWAP64(v);
-      maybe_add_auto(afl, (u8 *)&rev, shape);
+      maybe_add_auto((u8 *)afl, (u8 *)&rev, shape);
       break;
 
   }
@@ -363,14 +385,44 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
   u32 loggeds = h->hits;
   if (h->hits > CMP_MAP_H) loggeds = CMP_MAP_H;
 
-  u8 status;
+  u8 status = 0;
   // opt not in the paper
-  u32 fails = 0;
+  u32 fails;
+  u8  found_one = 0;
+
+  /* loop cmps are useless, detect and blacklist them */
+  u64 s_v0, s_v1;
+  u8  s_v0_fixed = 1, s_v1_fixed = 1;
+  u8  s_v0_inc = 1, s_v1_inc = 1;
+  u8  s_v0_dec = 1, s_v1_dec = 1;
 
   for (i = 0; i < loggeds; ++i) {
 
+    fails = 0;
+
     struct cmp_operands *o = &afl->shm.cmp_map->log[key][i];
 
+    // loop detection code
+    if (i == 0) {
+
+      s_v0 = o->v0;
+      s_v1 = o->v1;
+
+    } else {
+
+      if (s_v0 != o->v0) s_v0_fixed = 0;
+      if (s_v1 != o->v1) s_v1_fixed = 0;
+      if (s_v0 + 1 != o->v0) s_v0_inc = 0;
+      if (s_v1 + 1 != o->v1) s_v1_inc = 0;
+      if (s_v0 - 1 != o->v0) s_v0_dec = 0;
+      if (s_v1 - 1 != o->v1) s_v1_dec = 0;
+      s_v0 = o->v0;
+      s_v1 = o->v1;
+
+    }
+
+    struct cmp_operands *orig_o = &afl->orig_cmp_map->log[key][i];
+
     // opt not in the paper
     for (j = 0; j < i; ++j)
       if (afl->shm.cmp_map->log[key][j].v0 == o->v0 &&
@@ -379,16 +431,16 @@ 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) {
 
-      if (unlikely(cmp_extend_encoding(afl, h, o->v0, o->v1, idx, orig_buf, buf,
-                                       len, 1, &status)))
+      if (unlikely(cmp_extend_encoding(afl, h, o->v0, o->v1, orig_o->v0, idx,
+                                       orig_buf, buf, len, 1, &status)))
         return 1;
       if (status == 2)
         ++fails;
       else if (status == 1)
         break;
 
-      if (unlikely(cmp_extend_encoding(afl, h, o->v1, o->v0, idx, orig_buf, buf,
-                                       len, 1, &status)))
+      if (unlikely(cmp_extend_encoding(afl, h, o->v1, o->v0, orig_o->v1, idx,
+                                       orig_buf, buf, len, 1, &status)))
         return 1;
       if (status == 2)
         ++fails;
@@ -397,11 +449,17 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
 
     }
 
+    if (status == 1) found_one = 1;
+
     // If failed, add to dictionary
     if (fails == 8) {
 
-      try_to_add_to_dict(afl, o->v0, SHAPE_BYTES(h->shape));
-      try_to_add_to_dict(afl, o->v1, SHAPE_BYTES(h->shape));
+      if (afl->pass_stats[key].total == 0) {
+
+        try_to_add_to_dict(afl, o->v0, SHAPE_BYTES(h->shape));
+        try_to_add_to_dict(afl, o->v1, SHAPE_BYTES(h->shape));
+
+      }
 
     }
 
@@ -410,13 +468,28 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
 
   }
 
+  if (loggeds > 3 && ((s_v0_fixed && s_v1_inc) || (s_v1_fixed && s_v0_inc) ||
+                      (s_v0_fixed && s_v1_dec) || (s_v1_fixed && s_v0_dec))) {
+
+    afl->pass_stats[key].total = afl->pass_stats[key].faileds = 0xff;
+
+  }
+
+  if (!found_one && afl->pass_stats[key].faileds < 0xff) {
+
+    afl->pass_stats[key].faileds++;
+
+  }
+
+  if (afl->pass_stats[key].total < 0xff) afl->pass_stats[key].total++;
+
   return 0;
 
 }
 
 static u8 rtn_extend_encoding(afl_state_t *afl, struct cmp_header *h,
-                              u8 *pattern, u8 *repl, u32 idx, u8 *orig_buf,
-                              u8 *buf, u32 len, u8 *status) {
+                              u8 *pattern, u8 *repl, u8 *o_pattern, u32 idx,
+                              u8 *orig_buf, u8 *buf, u32 len, u8 *status) {
 
   u32 i;
   u32 its_len = MIN(32, len - idx);
@@ -428,7 +501,9 @@ static u8 rtn_extend_encoding(afl_state_t *afl, struct cmp_header *h,
 
   for (i = 0; i < its_len; ++i) {
 
-    if (pattern[idx + i] != buf[idx + i] || *status == 1) break;
+    if (pattern[idx + i] != buf[idx + i] ||
+        o_pattern[idx + i] != orig_buf[idx + i] || *status == 1)
+      break;
 
     buf[idx + i] = repl[idx + i];
     if (unlikely(its_fuzz(afl, buf, len, status))) return 1;
@@ -448,15 +523,21 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
   u32 loggeds = h->hits;
   if (h->hits > CMP_MAP_RTN_H) loggeds = CMP_MAP_RTN_H;
 
-  u8 status;
+  u8 status = 0;
   // opt not in the paper
   u32 fails = 0;
+  u8  found_one = 0;
 
   for (i = 0; i < loggeds; ++i) {
 
+    fails = 0;
+
     struct cmpfn_operands *o =
         &((struct cmpfn_operands *)afl->shm.cmp_map->log[key])[i];
 
+    struct cmpfn_operands *orig_o =
+        &((struct cmpfn_operands *)afl->orig_cmp_map->log[key])[i];
+
     // opt not in the paper
     for (j = 0; j < i; ++j)
       if (!memcmp(&((struct cmpfn_operands *)afl->shm.cmp_map->log[key])[j], o,
@@ -465,16 +546,16 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
 
     for (idx = 0; idx < len && fails < 8; ++idx) {
 
-      if (unlikely(rtn_extend_encoding(afl, h, o->v0, o->v1, idx, orig_buf, buf,
-                                       len, &status)))
+      if (unlikely(rtn_extend_encoding(afl, h, o->v0, o->v1, orig_o->v0, idx,
+                                       orig_buf, buf, len, &status)))
         return 1;
       if (status == 2)
         ++fails;
       else if (status == 1)
         break;
 
-      if (unlikely(rtn_extend_encoding(afl, h, o->v1, o->v0, idx, orig_buf, buf,
-                                       len, &status)))
+      if (unlikely(rtn_extend_encoding(afl, h, o->v1, o->v0, orig_o->v1, idx,
+                                       orig_buf, buf, len, &status)))
         return 1;
       if (status == 2)
         ++fails;
@@ -483,11 +564,17 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
 
     }
 
+    if (status == 1) found_one = 1;
+
     // If failed, add to dictionary
     if (fails == 8) {
 
-      maybe_add_auto(afl, o->v0, SHAPE_BYTES(h->shape));
-      maybe_add_auto(afl, o->v1, SHAPE_BYTES(h->shape));
+      if (afl->pass_stats[key].total == 0) {
+
+        maybe_add_auto((u8 *)afl, o->v0, SHAPE_BYTES(h->shape));
+        maybe_add_auto((u8 *)afl, o->v1, SHAPE_BYTES(h->shape));
+
+      }
 
     }
 
@@ -496,6 +583,14 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
 
   }
 
+  if (!found_one && afl->pass_stats[key].faileds < 0xff) {
+
+    afl->pass_stats[key].faileds++;
+
+  }
+
+  if (afl->pass_stats[key].total < 0xff) afl->pass_stats[key].total++;
+
   return 0;
 
 }
@@ -507,6 +602,18 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len,
                         u32 exec_cksum) {
 
   u8 r = 1;
+  if (afl->orig_cmp_map == NULL)
+    afl->orig_cmp_map = ck_alloc_nozero(sizeof(struct cmp_map));
+
+  if (afl->pass_stats == NULL)
+    afl->pass_stats = ck_alloc(sizeof(struct afl_pass_stat) * CMP_MAP_W);
+
+  // do it manually, forkserver clear only afl->fsrv.trace_bits
+  memset(afl->shm.cmp_map->headers, 0, sizeof(afl->shm.cmp_map->headers));
+
+  if (unlikely(common_fuzz_cmplog_stuff(afl, buf, len))) return 1;
+
+  memcpy(afl->orig_cmp_map, afl->shm.cmp_map, sizeof(struct cmp_map));
 
   if (unlikely(colorization(afl, buf, len, exec_cksum))) return 1;
 
@@ -516,7 +623,7 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len,
   if (unlikely(common_fuzz_cmplog_stuff(afl, buf, len))) return 1;
 
   u64 orig_hit_cnt, new_hit_cnt;
-  u64 orig_execs = afl->total_execs;
+  u64 orig_execs = afl->fsrv.total_execs;
   orig_hit_cnt = afl->queued_paths + afl->unique_crashes;
 
   afl->stage_name = "input-to-state";
@@ -528,6 +635,13 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len,
   for (k = 0; k < CMP_MAP_W; ++k) {
 
     if (!afl->shm.cmp_map->headers[k].hits) continue;
+
+    if (afl->pass_stats[k].total &&
+        (rand_below(afl, afl->pass_stats[k].total) >=
+             afl->pass_stats[k].faileds ||
+         afl->pass_stats[k].total == 0xff))
+      afl->shm.cmp_map->headers[k].hits = 0;  // blacklist this cmp
+
     if (afl->shm.cmp_map->headers[k].type == CMP_TYPE_INS)
       afl->stage_max += MIN((u32)afl->shm.cmp_map->headers[k].hits, CMP_MAP_H);
     else
@@ -555,11 +669,11 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len,
   r = 0;
 
 exit_its:
-  memcpy(orig_buf, buf, len);
-
   new_hit_cnt = afl->queued_paths + afl->unique_crashes;
   afl->stage_finds[STAGE_ITS] += new_hit_cnt - orig_hit_cnt;
-  afl->stage_cycles[STAGE_ITS] += afl->total_execs - orig_execs;
+  afl->stage_cycles[STAGE_ITS] += afl->fsrv.total_execs - orig_execs;
+
+  memcpy(orig_buf, buf, len);
 
   return r;
 
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 47f6e9d9..30ba0e65 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -6,7 +6,8 @@
 
    Now maintained by Marc Heuse <mh@mh-sec.de>,
                         Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
-                        Andrea Fioraldi <andreafioraldi@gmail.com>
+                        Andrea Fioraldi <andreafioraldi@gmail.com> and
+                        Dominik Maier <mail@dmnk.co>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
    Copyright 2019-2020 AFLplusplus Project. All rights reserved.
@@ -27,134 +28,18 @@
 #include <sys/time.h>
 #include <signal.h>
 
-/* Execute target application, monitoring for timeouts. Return status
-   information. The called program will update afl->fsrv.trace_bits. */
-
-u8 run_target(afl_state_t *afl, u32 timeout) {
-
-  s32 res;
-  u32 exec_ms;
-
-  int status = 0;
-  u32 tb4;
-
-  afl->fsrv.child_timed_out = 0;
-
-  /* After this memset, afl->fsrv.trace_bits[] are effectively volatile, so we
-     must prevent any earlier operations from venturing into that
-     territory. */
-
-  memset(afl->fsrv.trace_bits, 0, MAP_SIZE);
-
-  MEM_BARRIER();
-
-  /* we have the fork server (or faux server) up and running, so simply
-      tell it to have at it, and then read back PID. */
-
-  if ((res = write(afl->fsrv.fsrv_ctl_fd, &afl->fsrv.prev_timed_out, 4)) != 4) {
-
-    if (afl->stop_soon) return 0;
-    RPFATAL(res, "Unable to request new process from fork server (OOM?)");
-
-  }
-
-  if ((res = read(afl->fsrv.fsrv_st_fd, &afl->fsrv.child_pid, 4)) != 4) {
-
-    if (afl->stop_soon) return 0;
-    RPFATAL(res, "Unable to request new process from fork server (OOM?)");
-
-  }
-
-  if (afl->fsrv.child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)");
-
-  exec_ms = read_timed(afl->fsrv.fsrv_st_fd, &status, 4, timeout);
-
-  if (exec_ms > timeout) {
-
-    /* If there was no response from forkserver after timeout seconds,
-    we kill the child. The forkserver should inform us afterwards */
-
-    kill(afl->fsrv.child_pid, SIGKILL);
-    afl->fsrv.child_timed_out = 1;
-    if (read(afl->fsrv.fsrv_st_fd, &status, 4) < 4) exec_ms = 0;
-
-  }
-
-  if (!exec_ms) {
-
-    if (afl->stop_soon) return 0;
-    SAYF("\n" cLRD "[-] " cRST
-         "Unable to communicate with fork server. Some possible reasons:\n\n"
-         "    - You've run out of memory. Use -m to increase the the memory "
-         "limit\n"
-         "      to something higher than %lld.\n"
-         "    - The binary or one of the libraries it uses manages to "
-         "create\n"
-         "      threads before the forkserver initializes.\n"
-         "    - The binary, at least in some circumstances, exits in a way "
-         "that\n"
-         "      also kills the parent process - raise() could be the "
-         "culprit.\n"
-         "    - If using persistent mode with QEMU, "
-         "AFL_QEMU_PERSISTENT_ADDR "
-         "is\n"
-         "      probably not valid (hint: add the base address in case of "
-         "PIE)"
-         "\n\n"
-         "If all else fails you can disable the fork server via "
-         "AFL_NO_FORKSRV=1.\n",
-         afl->fsrv.mem_limit);
-    RPFATAL(res, "Unable to communicate with fork server");
-
-  }
-
-  if (!WIFSTOPPED(status)) afl->fsrv.child_pid = 0;
-
-  ++afl->total_execs;
-
-  /* Any subsequent operations on afl->fsrv.trace_bits must not be moved by the
-     compiler below this point. Past this location, afl->fsrv.trace_bits[]
-     behave very normally and do not have to be treated as volatile. */
-
-  MEM_BARRIER();
-
-  tb4 = *(u32 *)afl->fsrv.trace_bits;
-
-#ifdef WORD_SIZE_64
-  classify_counts((u64 *)afl->fsrv.trace_bits);
-#else
-  classify_counts((u32 *)afl->fsrv.trace_bits);
-#endif                                                     /* ^WORD_SIZE_64 */
-
-  afl->fsrv.prev_timed_out = afl->fsrv.child_timed_out;
-
-  /* Report outcome to caller. */
-
-  if (WIFSIGNALED(status) && !afl->stop_soon) {
-
-    afl->kill_signal = WTERMSIG(status);
-
-    if (afl->fsrv.child_timed_out && afl->kill_signal == SIGKILL)
-      return FAULT_TMOUT;
-
-    return FAULT_CRASH;
-
-  }
+#include "cmplog.h"
 
-  /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and
-     must use a special exit code. */
-
-  if (afl->fsrv.uses_asan && WEXITSTATUS(status) == MSAN_ERROR) {
-
-    afl->kill_signal = 0;
-    return FAULT_CRASH;
-
-  }
+/* Execute target application, monitoring for timeouts. Return status
+   information. The called program will update afl->fsrv->trace_bits. */
 
-  if ((afl->dumb_mode == 1 || afl->no_forkserver) && tb4 == EXEC_FAIL_SIG)
-    return FAULT_ERROR;
+fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
+                                  u32 timeout) {
 
-  return FAULT_NONE;
+  fsrv_run_result_t res = afl_fsrv_run_target(fsrv, timeout, &afl->stop_soon);
+  // TODO: Don't classify for faults?
+  classify_counts(fsrv);
+  return res;
 
 }
 
@@ -164,13 +49,11 @@ u8 run_target(afl_state_t *afl, u32 timeout) {
 
 void write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
 
-  s32 fd = afl->fsrv.out_fd;
-
 #ifdef _AFL_DOCUMENT_MUTATIONS
   s32  doc_fd;
   char fn[PATH_MAX];
-  snprintf(fn, PATH_MAX, ("%s/mutations/%09u:%s", afl->out_dir,
-                          afl->document_counter++, describe_op(afl, 0));
+  snprintf(fn, PATH_MAX, "%s/mutations/%09u:%s", afl->out_dir,
+           afl->document_counter++, describe_op(afl, 0));
 
   if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0) {
 
@@ -182,25 +65,6 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
 
 #endif
 
-  if (afl->fsrv.out_file) {
-
-    if (afl->no_unlink) {
-
-      fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
-
-    } else {
-
-      unlink(afl->fsrv.out_file);                         /* Ignore errors. */
-      fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
-
-    }
-
-    if (fd < 0) PFATAL("Unable to create '%s'", afl->fsrv.out_file);
-
-  } else
-
-    lseek(fd, 0, SEEK_SET);
-
   if (unlikely(afl->mutator && afl->mutator->afl_custom_pre_save)) {
 
     u8 *new_buf = NULL;
@@ -212,24 +76,15 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
       FATAL("Custom_pre_save failed (ret: %lu)", (long unsigned)new_size);
 
     /* everything as planned. use the new data. */
-    ck_write(fd, new_buf, new_size, afl->fsrv.out_file);
+    afl_fsrv_write_to_testcase(&afl->fsrv, new_buf, new_size);
 
   } else {
 
     /* boring uncustom. */
-    ck_write(fd, mem, len, afl->fsrv.out_file);
+    afl_fsrv_write_to_testcase(&afl->fsrv, mem, len);
 
   }
 
-  if (!afl->fsrv.out_file) {
-
-    if (ftruncate(fd, len)) PFATAL("ftruncate() failed");
-    lseek(fd, 0, SEEK_SET);
-
-  } else
-
-    close(fd);
-
 }
 
 /* The same, but with an adjustable gap. Used for trimming. */
@@ -308,12 +163,22 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
   /* Make sure the forkserver is up before we do anything, and let's not
      count its spin-up time toward binary calibration. */
 
-  if (!afl->fsrv.fsrv_pid) afl_fsrv_start(&afl->fsrv, afl->argv);
-  if (afl->dumb_mode != 1 && !afl->no_forkserver && !afl->cmplog_fsrv_pid &&
-      afl->shm.cmplog_mode)
-    init_cmplog_forkserver(afl);
+  if (!afl->fsrv.fsrv_pid) {
+
+    if (afl->fsrv.cmplog_binary &&
+        afl->fsrv.init_child_func != cmplog_exec_child) {
+
+      FATAL("BUG in afl-fuzz detected. Cmplog mode not set correctly.");
+
+    }
+
+    afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
+                   afl->afl_env.afl_debug_child_output);
+
+  }
 
-  if (q->exec_cksum) memcpy(afl->first_trace, afl->fsrv.trace_bits, MAP_SIZE);
+  if (q->exec_cksum)
+    memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
 
   start_us = get_cur_time_us();
 
@@ -326,7 +191,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
 
     write_to_testcase(afl, use_mem, q->len);
 
-    fault = run_target(afl, use_tmout);
+    fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
 
     /* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed,
        we want to bail out quickly. */
@@ -334,14 +199,14 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
     if (afl->stop_soon || fault != afl->crash_mode) goto abort_calibration;
 
     if (!afl->dumb_mode && !afl->stage_cur &&
-        !count_bytes(afl->fsrv.trace_bits)) {
+        !count_bytes(afl, afl->fsrv.trace_bits)) {
 
-      fault = FAULT_NOINST;
+      fault = FSRV_RUN_NOINST;
       goto abort_calibration;
 
     }
 
-    cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+    cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
 
     if (q->exec_cksum != cksum) {
 
@@ -352,7 +217,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
 
         u32 i;
 
-        for (i = 0; i < MAP_SIZE; ++i) {
+        for (i = 0; i < afl->fsrv.map_size; ++i) {
 
           if (unlikely(!afl->var_bytes[i]) &&
               unlikely(afl->first_trace[i] != afl->fsrv.trace_bits[i]))
@@ -366,7 +231,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
       } else {
 
         q->exec_cksum = cksum;
-        memcpy(afl->first_trace, afl->fsrv.trace_bits, MAP_SIZE);
+        memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
 
       }
 
@@ -383,7 +248,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
      This is used for fuzzing air time calculations in calculate_score(). */
 
   q->exec_us = (stop_us - start_us) / afl->stage_max;
-  q->bitmap_size = count_bytes(afl->fsrv.trace_bits);
+  q->bitmap_size = count_bytes(afl, afl->fsrv.trace_bits);
   q->handicap = handicap;
   q->cal_failed = 0;
 
@@ -396,7 +261,8 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
      parent. This is a non-critical problem, but something to warn the user
      about. */
 
-  if (!afl->dumb_mode && first_run && !fault && !new_bits) fault = FAULT_NOBITS;
+  if (!afl->dumb_mode && first_run && !fault && !new_bits)
+    fault = FSRV_RUN_NOBITS;
 
 abort_calibration:
 
@@ -411,7 +277,7 @@ abort_calibration:
 
   if (var_detected) {
 
-    afl->var_byte_count = count_bytes(afl->var_bytes);
+    afl->var_byte_count = count_bytes(afl, afl->var_bytes);
 
     if (!q->var_behavior) {
 
@@ -543,7 +409,7 @@ void sync_fuzzers(afl_state_t *afl) {
 
         write_to_testcase(afl, mem, st.st_size);
 
-        fault = run_target(afl, afl->fsrv.exec_tmout);
+        fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
 
         if (afl->stop_soon) goto close_sync;
 
@@ -630,15 +496,15 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
 
       write_with_gap(afl, in_buf, q->len, remove_pos, trim_avail);
 
-      fault = run_target(afl, afl->fsrv.exec_tmout);
+      fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
       ++afl->trim_execs;
 
-      if (afl->stop_soon || fault == FAULT_ERROR) goto abort_trimming;
+      if (afl->stop_soon || fault == FSRV_RUN_ERROR) goto abort_trimming;
 
       /* Note that we don't keep track of crashes or hangs here; maybe TODO?
        */
 
-      cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+      cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
 
       /* If the deletion had no impact on the trace, make it permanent. This
          isn't perfect for variable-path inputs, but we're just making a
@@ -661,7 +527,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
         if (!needs_write) {
 
           needs_write = 1;
-          memcpy(afl->clean_trace, afl->fsrv.trace_bits, MAP_SIZE);
+          memcpy(afl->clean_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
 
         }
 
@@ -703,7 +569,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
     ck_write(fd, in_buf, q->len, q->fname);
     close(fd);
 
-    memcpy(afl->fsrv.trace_bits, afl->clean_trace, MAP_SIZE);
+    memcpy(afl->fsrv.trace_bits, afl->clean_trace, afl->fsrv.map_size);
     update_bitmap_score(afl, q);
 
   }
@@ -737,11 +603,11 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
 
   write_to_testcase(afl, out_buf, len);
 
-  fault = run_target(afl, afl->fsrv.exec_tmout);
+  fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
 
   if (afl->stop_soon) return 1;
 
-  if (fault == FAULT_TMOUT) {
+  if (fault == FSRV_RUN_TMOUT) {
 
     if (afl->subseq_tmouts++ > TMOUT_LIMIT) {
 
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index 80176a10..de7a4481 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -75,12 +75,14 @@ list_t afl_states = {.element_prealloc_count = 0};
 
 /* Initializes an afl_state_t. */
 
-void afl_state_init(afl_state_t *afl) {
+void afl_state_init(afl_state_t *afl, uint32_t map_size) {
 
   /* thanks to this memset, growing vars like out_buf
   and out_size are NULL/0 by default. */
   memset(afl, 0, sizeof(afl_state_t));
 
+  if (!map_size) afl->shm.map_size = MAP_SIZE;
+
   afl->w_init = 0.9;
   afl->w_end = 0.3;
   afl->g_max = 5000;
@@ -97,7 +99,20 @@ void afl_state_init(afl_state_t *afl) {
   afl->cpu_aff = -1;                    /* Selected CPU core                */
 #endif                                                     /* HAVE_AFFINITY */
 
+  afl->virgin_bits = ck_alloc(map_size);
+  afl->virgin_tmout = ck_alloc(map_size);
+  afl->virgin_crash = ck_alloc(map_size);
+  afl->var_bytes = ck_alloc(map_size);
+  afl->top_rated = ck_alloc(map_size * sizeof(void *));
+  afl->clean_trace = ck_alloc(map_size);
+  afl->clean_trace_custom = ck_alloc(map_size);
+  afl->first_trace = ck_alloc(map_size);
+  afl->map_tmp_buf = ck_alloc(map_size);
+
   afl->fsrv.use_stdin = 1;
+  afl->fsrv.map_size = map_size;
+  afl->fsrv.function_opt = (u8 *)afl;
+  afl->fsrv.function_ptr = &maybe_add_auto;
 
   afl->cal_cycles = CAL_CYCLES;
   afl->cal_cycles_long = CAL_CYCLES_LONG;
@@ -280,6 +295,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
             afl->afl_env.afl_autoresume =
                 get_afl_env(afl_environment_variables[i]) ? 1 : 0;
 
+          } else if (!strncmp(env, "AFL_CAL_FAST",
+
+                              afl_environment_variable_len)) {
+
+            afl->afl_env.afl_cal_fast =
+                get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
           } else if (!strncmp(env, "AFL_TMPDIR",
 
                               afl_environment_variable_len)) {
@@ -348,13 +370,27 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
 void afl_state_deinit(afl_state_t *afl) {
 
   if (afl->post_deinit) afl->post_deinit(afl->post_data);
-
-  free(afl->out_buf);
-  free(afl->out_scratch_buf);
-  free(afl->eff_buf);
-  free(afl->in_buf);
-  free(afl->in_scratch_buf);
-  free(afl->ex_buf);
+  if (afl->in_place_resume) ck_free(afl->in_dir);
+  if (afl->sync_id) ck_free(afl->out_dir);
+  if (afl->pass_stats) ck_free(afl->pass_stats);
+  if (afl->orig_cmp_map) ck_free(afl->orig_cmp_map);
+
+  if (afl->out_buf) free(afl->out_buf);
+  if (afl->out_scratch_buf) free(afl->out_scratch_buf);
+  if (afl->eff_buf) free(afl->eff_buf);
+  if (afl->in_buf) free(afl->in_buf);
+  if (afl->in_scratch_buf) free(afl->in_scratch_buf);
+  if (afl->ex_buf) free(afl->ex_buf);
+
+  ck_free(afl->virgin_bits);
+  ck_free(afl->virgin_tmout);
+  ck_free(afl->virgin_crash);
+  ck_free(afl->var_bytes);
+  ck_free(afl->top_rated);
+  ck_free(afl->clean_trace);
+  ck_free(afl->clean_trace_custom);
+  ck_free(afl->first_trace);
+  ck_free(afl->map_tmp_buf);
 
   list_remove(&afl_states, afl);
 
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 850555b5..c507b7f7 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -37,7 +37,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->virgin_bits);
+  uint32_t               t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
 
   snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
 
@@ -56,7 +56,6 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
 
     bitmap_cvg = afl->last_bitmap_cvg;
     stability = afl->last_stability;
-    eps = afl->last_eps;
 
   } else {
 
@@ -109,14 +108,15 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
       afl->start_time / 1000, cur_time / 1000,
       (cur_time - afl->start_time) / 1000, getpid(),
       afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds,
-      afl->total_execs,
-      afl->total_execs / ((double)(get_cur_time() - afl->start_time) / 1000),
+      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->total_execs - afl->last_crash_execs,
+      afl->last_hang_time / 1000, afl->fsrv.total_execs - afl->last_crash_execs,
       afl->fsrv.exec_tmout, afl->slowest_exec_ms,
 #ifdef __APPLE__
       (unsigned long int)(rus.ru_maxrss >> 20),
@@ -124,12 +124,12 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
       (unsigned long int)(rus.ru_maxrss >> 10),
 #endif
       t_bytes, afl->var_byte_count, afl->use_banner,
-      afl->unicorn_mode ? "unicorn" : "", afl->qemu_mode ? "qemu " : "",
+      afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "",
       afl->dumb_mode ? " dumb " : "", afl->no_forkserver ? "no_fsrv " : "",
       afl->crash_mode ? "crash " : "",
       afl->persistent_mode ? "persistent " : "",
       afl->deferred_mode ? "deferred " : "",
-      (afl->unicorn_mode || afl->qemu_mode || afl->dumb_mode ||
+      (afl->unicorn_mode || afl->fsrv.qemu_mode || afl->dumb_mode ||
        afl->no_forkserver || afl->crash_mode || afl->persistent_mode ||
        afl->deferred_mode)
           ? ""
@@ -145,14 +145,15 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
 
 void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) {
 
-  if (afl->plot_prev_qp == afl->queued_paths &&
-      afl->plot_prev_pf == afl->pending_favored &&
-      afl->plot_prev_pnf == afl->pending_not_fuzzed &&
-      afl->plot_prev_ce == afl->current_entry &&
-      afl->plot_prev_qc == afl->queue_cycle &&
-      afl->plot_prev_uc == afl->unique_crashes &&
-      afl->plot_prev_uh == afl->unique_hangs &&
-      afl->plot_prev_md == afl->max_depth)
+  if (unlikely(afl->plot_prev_qp == afl->queued_paths &&
+               afl->plot_prev_pf == afl->pending_favored &&
+               afl->plot_prev_pnf == afl->pending_not_fuzzed &&
+               afl->plot_prev_ce == afl->current_entry &&
+               afl->plot_prev_qc == afl->queue_cycle &&
+               afl->plot_prev_uc == afl->unique_crashes &&
+               afl->plot_prev_uh == afl->unique_hangs &&
+               afl->plot_prev_md == afl->max_depth) ||
+      unlikely(!afl->queue_cycle))
     return;
 
   afl->plot_prev_qp = afl->queued_paths;
@@ -215,6 +216,28 @@ void show_stats(afl_state_t *afl) {
 
   cur_ms = get_cur_time();
 
+  if (afl->most_time_key) {
+
+    if (afl->most_time * 1000 < cur_ms - afl->start_time) {
+
+      afl->most_time_key = 2;
+      afl->stop_soon = 2;
+
+    }
+
+  }
+
+  if (afl->most_execs_key == 1) {
+
+    if (afl->most_execs <= afl->fsrv.total_execs) {
+
+      afl->most_execs_key = 2;
+      afl->stop_soon = 2;
+
+    }
+
+  }
+
   /* If not enough time has passed since last UI update, bail out. */
 
   if (cur_ms - afl->stats_last_ms < 1000 / UI_TARGET_HZ &&
@@ -230,11 +253,11 @@ void show_stats(afl_state_t *afl) {
   if (!afl->stats_last_execs) {
 
     afl->stats_avg_exec =
-        ((double)afl->total_execs) * 1000 / (cur_ms - afl->start_time);
+        ((double)afl->fsrv.total_execs) * 1000 / (cur_ms - afl->start_time);
 
   } else {
 
-    double cur_avg = ((double)(afl->total_execs - afl->stats_last_execs)) *
+    double cur_avg = ((double)(afl->fsrv.total_execs - afl->stats_last_execs)) *
                      1000 / (cur_ms - afl->stats_last_ms);
 
     /* If there is a dramatic (5x+) jump in speed, reset the indicator
@@ -249,7 +272,7 @@ void show_stats(afl_state_t *afl) {
   }
 
   afl->stats_last_ms = cur_ms;
-  afl->stats_last_execs = afl->total_execs;
+  afl->stats_last_execs = afl->fsrv.total_execs;
 
   /* Tell the callers when to contact us (as measured in execs). */
 
@@ -258,8 +281,8 @@ void show_stats(afl_state_t *afl) {
 
   /* Do some bitmap stats. */
 
-  t_bytes = count_non_255_bytes(afl->virgin_bits);
-  t_byte_ratio = ((double)t_bytes * 100) / MAP_SIZE;
+  t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
+  t_byte_ratio = ((double)t_bytes * 100) / afl->fsrv.map_size;
 
   if (likely(t_bytes) && unlikely(afl->var_byte_count))
     stab_ratio = 100 - (((double)afl->var_byte_count * 100) / t_bytes);
@@ -305,7 +328,7 @@ void show_stats(afl_state_t *afl) {
 
   /* Compute some mildly useful bitmap stats. */
 
-  t_bits = (MAP_SIZE << 3) - count_bits(afl->virgin_bits);
+  t_bits = (afl->fsrv.map_size << 3) - count_bits(afl, afl->virgin_bits);
 
   /* Now, for the visuals... */
 
@@ -465,7 +488,8 @@ void show_stats(afl_state_t *afl) {
   SAYF(bV bSTOP "  now processing : " cRST "%-16s " bSTG bV bSTOP, tmp);
 
   sprintf(tmp, "%0.02f%% / %0.02f%%",
-          ((double)afl->queue_cur->bitmap_size) * 100 / MAP_SIZE, t_byte_ratio);
+          ((double)afl->queue_cur->bitmap_size) * 100 / afl->fsrv.map_size,
+          t_byte_ratio);
 
   SAYF("    map density : %s%-21s" bSTG bV "\n",
        t_byte_ratio > 70 ? cLRD
@@ -521,14 +545,14 @@ void show_stats(afl_state_t *afl) {
 
     SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP
                   "   new crashes : %s%-22s" bSTG         bV "\n",
-         u_stringify_int(IB(0), afl->total_execs),
+         u_stringify_int(IB(0), afl->fsrv.total_execs),
          afl->unique_crashes ? cLRD : cRST, tmp);
 
   } else {
 
     SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP
                   " total crashes : %s%-22s" bSTG         bV "\n",
-         u_stringify_int(IB(0), afl->total_execs),
+         u_stringify_int(IB(0), afl->fsrv.total_execs),
          afl->unique_crashes ? cLRD : cRST, tmp);
 
   }
@@ -736,6 +760,8 @@ void show_stats(afl_state_t *afl) {
 
   if (afl->cpu_core_count) {
 
+    char *spacing = SP10, snap[24] = " " cLGN "snapshot" cRST " ";
+
     double cur_runnable = get_runnable_processes();
     u32    cur_utilization = cur_runnable * 100 / afl->cpu_core_count;
 
@@ -750,23 +776,25 @@ void show_stats(afl_state_t *afl) {
 
     if (!afl->no_cpu_meter_red && cur_utilization >= 150) cpu_color = cLRD;
 
+    if (afl->fsrv.snapshot) spacing = snap;
+
 #ifdef HAVE_AFFINITY
 
     if (afl->cpu_aff >= 0) {
 
-      SAYF(SP10 cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, MIN(afl->cpu_aff, 999),
-           cpu_color, MIN(cur_utilization, 999));
+      SAYF("%s" cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, spacing,
+           MIN(afl->cpu_aff, 999), cpu_color, MIN(cur_utilization, 999));
 
     } else {
 
-      SAYF(SP10 cGRA "   [cpu:%s%3u%%" cGRA "]\r" cRST, cpu_color,
+      SAYF("%s" cGRA "   [cpu:%s%3u%%" cGRA "]\r" cRST, spacing, cpu_color,
            MIN(cur_utilization, 999));
 
     }
 
 #else
 
-    SAYF(SP10 cGRA "   [cpu:%s%3u%%" cGRA "]\r" cRST, cpu_color,
+    SAYF("%s" cGRA "   [cpu:%s%3u%%" cGRA "]\r" cRST, spacing, cpu_color,
          MIN(cur_utilization, 999));
 
 #endif                                                    /* ^HAVE_AFFINITY */
@@ -819,7 +847,7 @@ void show_init_stats(afl_state_t *afl) {
 
   SAYF("\n");
 
-  if (avg_us > ((afl->qemu_mode || afl->unicorn_mode) ? 50000 : 10000))
+  if (avg_us > ((afl->fsrv.qemu_mode || afl->unicorn_mode) ? 50000 : 10000))
     WARNF(cLRD "The target binary is pretty slow! See %s/perf_tips.md.",
           doc_path);
 
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 5010c3ea..efb65ba6 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -24,6 +24,8 @@
  */
 
 #include "afl-fuzz.h"
+#include "cmplog.h"
+#include <limits.h>
 
 static u8 *get_libradamsa_path(u8 *own_loc) {
 
@@ -108,12 +110,12 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) {
       "Mutator settings:\n"
       "  -R[R]         - add Radamsa as mutator, add another -R to exclusivly "
       "run it\n"
-      "  -L minutes    - use MOpt(imize) mode and set the limit time for "
+      "  -L minutes    - use MOpt(imize) mode and set the time limit for "
       "entering the\n"
-      "                  pacemaker mode (minutes of no new paths, 0 = "
-      "immediately).\n"
-      "                  a recommended value is 10-60. see "
-      "docs/README.MOpt.md\n"
+      "                  pacemaker mode (minutes of no new paths). 0 = "
+      "immediately,\n"
+      "                  -1 = immediately and together with normal mutation).\n"
+      "                  See docs/README.MOpt.md\n"
       "  -c program    - enable CmpLog by specifying a binary compiled for "
       "it.\n"
       "                  if using QEMU, just use -c 0.\n\n"
@@ -128,12 +130,11 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) {
 
       "Testing settings:\n"
       "  -s seed       - use a fixed seed for the RNG\n"
-      "  -V seconds    - fuzz for a maximum total time of seconds then "
+      "  -V seconds    - fuzz for a specific time then terminate\n"
+      "  -E execs      - fuzz for a approx. no of total executions then "
       "terminate\n"
-      "  -E execs      - fuzz for a maximum number of total executions then "
-      "terminate\n"
-      "  Note: -V/-E are not precise, they are checked after a queue entry "
-      "is done\n  which can be many minutes/execs later\n\n"
+      "                  Note: not precise and can have several more "
+      "executions.\n\n"
 
       "Other stuff:\n"
       "  -T text       - text banner to show on the screen\n"
@@ -143,51 +144,53 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) {
       "  -B bitmap.txt - mutate a specific test case, use the out/fuzz_bitmap "
       "file\n"
       "  -C            - crash exploration mode (the peruvian rabbit thing)\n"
-      "  -e ext        - File extension for the temporarily generated test "
+      "  -e ext        - file extension for the temporarily generated test "
       "case\n\n",
       argv0, EXEC_TIMEOUT, MEM_LIMIT);
 
   if (more_help > 1)
     SAYF(
       "Environment variables used:\n"
-      "AFL_PATH: path to AFL support binaries\n"
-      "AFL_QUIET: suppress forkserver status messages\n"
-      "AFL_DEBUG_CHILD_OUTPUT: do not suppress stdout/stderr from target\n"
       "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
+      "ASAN_OPTIONS: custom settings for ASAN\n"
+      "              (must contain abort_on_error=1 and symbolize=0)\n"
+      "MSAN_OPTIONS: custom settings for MSAN\n"
+      "              (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
+      "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n"
       "AFL_BENCH_JUST_ONE: run the target just once\n"
-      "AFL_DUMB_FORKSRV: use fork server without feedback from target\n"
+      "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n"
       "AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\n"
       "AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n"
-      "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n"
       "AFL_DEBUG: extra debugging output for Python mode trimming\n"
+      "AFL_DEBUG_CHILD_OUTPUT: do not suppress stdout/stderr from target\n"
       "AFL_DISABLE_TRIM: disable the trimming of test cases\n"
-      "AFL_NO_UI: switch status screen off\n"
-      "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n"
-      "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n"
-      "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n"
-      "AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n"
-      "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n"
-      "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n"
-      "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
+      "AFL_DUMB_FORKSRV: use fork server without feedback from target\n"
+      "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n"
       "AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n"
+      "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n"
       "AFL_HANG_TMOUT: override timeout value (in milliseconds)\n"
-      "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
-      "AFL_TMPDIR: directory to use for input file generation (ramdisk recommended)\n"
+      "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n"
       "AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n"
+      "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
+      "              the target was compiled for\n"
       "AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n"
+      "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n"
+      "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n"
+      "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n"
+      "AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n"
+      "AFL_NO_UI: switch status screen off\n"
+      "AFL_PATH: path to AFL support binaries\n"
       "AFL_POST_LIBRARY: postprocess generated test cases before use as target input\n"
-      "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n"
-      "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n"
-      "ASAN_OPTIONS: custom settings for ASAN\n"
-      "              (must contain abort_on_error=1 and symbolize=0)\n"
-      "MSAN_OPTIONS: custom settings for MSAN\n"
-      "              (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
+      "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n"
+      "AFL_QUIET: suppress forkserver status messages\n"
+      "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
+      "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
       "AFL_SKIP_BIN_CHECK: skip the check, if the target is an excutable\n"
+      "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n"
+      "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n"
+      "AFL_TMPDIR: directory to use for input file generation (ramdisk recommended)\n"
       //"AFL_PERSISTENT: not supported anymore -> no effect, just a warning\n"
       //"AFL_DEFER_FORKSRV: not supported anymore -> no effect, just a warning\n"
-      "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n"
-      "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n"
-      "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n"
       "\n"
     );
   else
@@ -213,6 +216,8 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) {
 
 static int stricmp(char const *a, char const *b) {
 
+  if (!a || !b) FATAL("Null reference");
+
   for (;; ++a, ++b) {
 
     int d;
@@ -229,7 +234,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   s32    opt;
   u64    prev_queued = 0;
-  u32    sync_interval_cnt = 0, seek_to, show_help = 0;
+  u32    sync_interval_cnt = 0, seek_to, show_help = 0, map_size = MAP_SIZE;
   u8 *   extras_dir = 0;
   u8     mem_limit_given = 0, exit_1 = 0;
   char **use_argv;
@@ -242,10 +247,14 @@ int main(int argc, char **argv_orig, char **envp) {
   afl_state_t *afl = calloc(1, sizeof(afl_state_t));
   if (!afl) { FATAL("Could not create afl state"); }
 
-  afl_state_init(afl);
+  if (get_afl_env("AFL_DEBUG")) afl->debug = 1;
+
+  map_size = get_map_size();
+  afl_state_init(afl, map_size);
   afl_fsrv_init(&afl->fsrv);
 
   read_afl_environment(afl, envp);
+  if (afl->shm.map_size) afl->fsrv.map_size = afl->shm.map_size;
   exit_1 = !!afl->afl_env.afl_bench_just_one;
 
   SAYF(cCYA "afl-fuzz" VERSION cRST
@@ -417,6 +426,8 @@ int main(int argc, char **argv_orig, char **envp) {
         if (mem_limit_given) FATAL("Multiple -m options not supported");
         mem_limit_given = 1;
 
+        if (!optarg) FATAL("Wrong usage of -m");
+
         if (!strcmp(optarg, "none")) {
 
           afl->fsrv.mem_limit = 0;
@@ -471,13 +482,13 @@ int main(int argc, char **argv_orig, char **envp) {
         if (afl->in_bitmap) FATAL("Multiple -B options not supported");
 
         afl->in_bitmap = optarg;
-        read_bitmap(afl, afl->in_bitmap);
+        read_bitmap(afl->in_bitmap, afl->virgin_bits, afl->fsrv.map_size);
         break;
 
       case 'C':                                               /* crash mode */
 
         if (afl->crash_mode) FATAL("Multiple -C options not supported");
-        afl->crash_mode = FAULT_CRASH;
+        afl->crash_mode = FSRV_RUN_CRASH;
         break;
 
       case 'n':                                                /* dumb mode */
@@ -498,8 +509,8 @@ int main(int argc, char **argv_orig, char **envp) {
 
       case 'Q':                                                /* QEMU mode */
 
-        if (afl->qemu_mode) FATAL("Multiple -Q options not supported");
-        afl->qemu_mode = 1;
+        if (afl->fsrv.qemu_mode) FATAL("Multiple -Q options not supported");
+        afl->fsrv.qemu_mode = 1;
 
         if (!mem_limit_given) afl->fsrv.mem_limit = MEM_LIMIT_QEMU;
 
@@ -524,7 +535,7 @@ int main(int argc, char **argv_orig, char **envp) {
       case 'W':                                           /* Wine+QEMU mode */
 
         if (afl->use_wine) FATAL("Multiple -W options not supported");
-        afl->qemu_mode = 1;
+        afl->fsrv.qemu_mode = 1;
         afl->use_wine = 1;
 
         if (!mem_limit_given) afl->fsrv.mem_limit = 0;
@@ -550,20 +561,33 @@ int main(int argc, char **argv_orig, char **envp) {
       case 'L': {                                              /* MOpt mode */
 
         if (afl->limit_time_sig) FATAL("Multiple -L options not supported");
-        afl->limit_time_sig = 1;
         afl->havoc_max_mult = HAVOC_MAX_MULT_MOPT;
 
-        if (sscanf(optarg, "%llu", &afl->limit_time_puppet) < 1 ||
-            optarg[0] == '-')
+        if (sscanf(optarg, "%d", &afl->limit_time_puppet) < 1)
           FATAL("Bad syntax used for -L");
 
+        if (afl->limit_time_puppet == -1) {
+
+          afl->limit_time_sig = -1;
+          afl->limit_time_puppet = 0;
+
+        } else if (afl->limit_time_puppet < 0) {
+
+          FATAL("-L value must be between 0 and 2000000 or -1");
+
+        } else {
+
+          afl->limit_time_sig = 1;
+
+        }
+
         u64 limit_time_puppet2 = afl->limit_time_puppet * 60 * 1000;
 
         if (limit_time_puppet2 < afl->limit_time_puppet)
           FATAL("limit_time overflow");
         afl->limit_time_puppet = limit_time_puppet2;
 
-        SAYF("limit_time_puppet %llu\n", afl->limit_time_puppet);
+        SAYF("limit_time_puppet %d\n", afl->limit_time_puppet);
         afl->swarm_now = 0;
 
         if (afl->limit_time_puppet == 0) afl->key_puppet = 1;
@@ -687,7 +711,7 @@ int main(int argc, char **argv_orig, char **envp) {
   OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL");
 
   if (afl->sync_id && afl->force_deterministic &&
-      getenv("AFL_CUSTOM_MUTATOR_ONLY"))
+      afl->afl_env.afl_custom_mutator_only)
     WARNF(
         "Using -M master with the AFL_CUSTOM_MUTATOR_ONLY mutator options will "
         "result in no deterministic mutations being done!");
@@ -698,11 +722,14 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (afl->use_radamsa) {
 
-    if (afl->limit_time_sig)
+    if (afl->limit_time_sig > 0)
       FATAL(
-          "MOpt and Radamsa are mutually exclusive. We accept pull requests "
-          "that integrates MOpt with the optional mutators "
-          "(custom/radamsa/redquenn/...).");
+          "MOpt and Radamsa are mutually exclusive unless you specify -L -1. "
+          "We accept pull requests that integrates MOpt with the optional "
+          "mutators (custom/radamsa/redqueen/...).");
+
+    if (afl->limit_time_sig && afl->use_radamsa > 1)
+      FATAL("Radamsa in radamsa-only mode can not run together with -L");
 
     OKF("Using Radamsa add-on");
 
@@ -748,7 +775,7 @@ int main(int argc, char **argv_orig, char **envp) {
   if (afl->dumb_mode) {
 
     if (afl->crash_mode) FATAL("-C and -n are mutually exclusive");
-    if (afl->qemu_mode) FATAL("-Q and -n are mutually exclusive");
+    if (afl->fsrv.qemu_mode) FATAL("-Q and -n are mutually exclusive");
     if (afl->unicorn_mode) FATAL("-U and -n are mutually exclusive");
 
   }
@@ -816,7 +843,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (afl->afl_env.afl_preload) {
 
-    if (afl->qemu_mode) {
+    if (afl->fsrv.qemu_mode) {
 
       u8 *qemu_preload = getenv("QEMU_SET_ENV");
       u8 *afl_preload = getenv("AFL_PRELOAD");
@@ -862,7 +889,7 @@ int main(int argc, char **argv_orig, char **envp) {
   check_if_tty(afl);
   if (afl->afl_env.afl_force_ui) afl->not_on_tty = 0;
 
-  if (get_afl_env("AFL_CAL_FAST")) {
+  if (afl->afl_env.afl_cal_fast) {
 
     /* Use less calibration cycles, for slow applications */
     afl->cal_cycles = 3;
@@ -870,8 +897,6 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
-  if (get_afl_env("AFL_DEBUG")) afl->debug = 1;
-
   if (afl->afl_env.afl_custom_mutator_only) {
 
     /* This ensures we don't proceed to havoc/splice */
@@ -891,13 +916,14 @@ int main(int argc, char **argv_orig, char **envp) {
   check_crash_handling();
   check_cpu_governor(afl);
 
-  afl->fsrv.trace_bits = afl_shm_init(&afl->shm, MAP_SIZE, afl->dumb_mode);
+  afl->fsrv.trace_bits =
+      afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->dumb_mode);
 
   setup_post(afl);
 
-  if (!afl->in_bitmap) memset(afl->virgin_bits, 255, MAP_SIZE);
-  memset(afl->virgin_tmout, 255, MAP_SIZE);
-  memset(afl->virgin_crash, 255, MAP_SIZE);
+  if (!afl->in_bitmap) memset(afl->virgin_bits, 255, afl->fsrv.map_size);
+  memset(afl->virgin_tmout, 255, afl->fsrv.map_size);
+  memset(afl->virgin_crash, 255, afl->fsrv.map_size);
 
   init_count_class16();
 
@@ -919,21 +945,21 @@ int main(int argc, char **argv_orig, char **envp) {
   if ((afl->tmp_dir = afl->afl_env.afl_tmpdir) != NULL &&
       !afl->in_place_resume) {
 
-    char tmpfile[afl->file_extension ? strlen(afl->tmp_dir) + 1 + 10 + 1 +
-                                           strlen(afl->file_extension) + 1
-                                     : strlen(afl->tmp_dir) + 1 + 10 + 1];
+    char tmpfile[PATH_MAX];
+
     if (afl->file_extension) {
 
-      sprintf(tmpfile, "%s/.cur_input.%s", afl->tmp_dir, afl->file_extension);
+      snprintf(tmpfile, PATH_MAX, "%s/.cur_input.%s", afl->tmp_dir,
+               afl->file_extension);
 
     } else {
 
-      sprintf(tmpfile, "%s/.cur_input", afl->tmp_dir);
+      snprintf(tmpfile, PATH_MAX, "%s/.cur_input", afl->tmp_dir);
 
     }
 
-    if (access(tmpfile, F_OK) !=
-        -1)  // there is still a race condition here, but well ...
+    /* there is still a race condition here, but well ... */
+    if (access(tmpfile, F_OK) != -1)
       FATAL(
           "AFL_TMPDIR already has an existing temporary input file: %s - if "
           "this is not from another instance, then just remove the file.",
@@ -983,15 +1009,9 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (afl->cmplog_binary) {
 
-    if (afl->limit_time_sig)
-      FATAL(
-          "MOpt and CmpLog are mutually exclusive. We accept pull requests "
-          "that integrates MOpt with the optional mutators "
-          "(custom/radamsa/redquenn/...).");
-
     if (afl->unicorn_mode)
       FATAL("CmpLog and Unicorn mode are not compatible at the moment, sorry");
-    if (!afl->qemu_mode) check_binary(afl, afl->cmplog_binary);
+    if (!afl->fsrv.qemu_mode) check_binary(afl, afl->cmplog_binary);
 
   }
 
@@ -999,7 +1019,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   afl->start_time = get_cur_time();
 
-  if (afl->qemu_mode) {
+  if (afl->fsrv.qemu_mode) {
 
     if (afl->use_wine)
       use_argv = get_wine_argv(argv[0], &afl->fsrv.target_path, argc - optind,
@@ -1015,6 +1035,21 @@ int main(int argc, char **argv_orig, char **envp) {
   }
 
   afl->argv = use_argv;
+
+  if (afl->cmplog_binary) {
+
+    ACTF("Spawning cmplog forkserver");
+    afl_fsrv_init_dup(&afl->cmplog_fsrv, &afl->fsrv);
+    // TODO: this is semi-nice
+    afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
+    afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode;
+    afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary;
+    afl->cmplog_fsrv.init_child_func = cmplog_exec_child;
+    afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
+                   afl->afl_env.afl_debug_child_output);
+
+  }
+
   perform_dry_run(afl);
 
   cull_queue(afl);
@@ -1109,55 +1144,6 @@ int main(int argc, char **argv_orig, char **envp) {
     afl->queue_cur = afl->queue_cur->next;
     ++afl->current_entry;
 
-    if (afl->most_time_key == 1) {
-
-      u64 cur_ms_lv = get_cur_time();
-      if (afl->most_time * 1000 < cur_ms_lv - afl->start_time) {
-
-        afl->most_time_key = 2;
-        afl->stop_soon = 2;
-        break;
-
-      }
-
-    }
-
-    if (afl->most_execs_key == 1) {
-
-      if (afl->most_execs <= afl->total_execs) {
-
-        afl->most_execs_key = 2;
-        afl->stop_soon = 2;
-        break;
-
-      }
-
-    }
-
-  }
-
-  // if (afl->queue_cur) show_stats(afl);
-
-  /*
-   * ATTENTION - the following 10 lines were copied from a PR to Google's afl
-   * repository - and slightly fixed.
-   * These lines have nothing to do with the purpose of original PR though.
-   * Looks like when an exit condition was completed (AFL_BENCH_JUST_ONE,
-   * AFL_EXIT_WHEN_DONE or AFL_BENCH_UNTIL_CRASH) the child and forkserver
-   * where not killed?
-   */
-  /* if we stopped programmatically, we kill the forkserver and the current
-     runner. if we stopped manually, this is done by the signal handler */
-  if (afl->stop_soon == 2) {
-
-    if (afl->fsrv.child_pid > 0) kill(afl->fsrv.child_pid, SIGKILL);
-    if (afl->fsrv.fsrv_pid > 0) kill(afl->fsrv.fsrv_pid, SIGKILL);
-    if (afl->cmplog_child_pid > 0) kill(afl->cmplog_child_pid, SIGKILL);
-    if (afl->cmplog_fsrv_pid > 0) kill(afl->cmplog_fsrv_pid, SIGKILL);
-    /* Now that we've killed the forkserver, we wait for it to be able to get
-     * rusage stats. */
-    if (waitpid(afl->fsrv.fsrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); }
-
   }
 
   write_bitmap(afl);
@@ -1200,6 +1186,7 @@ stop_fuzzing:
   ck_free(afl->fsrv.target_path);
   ck_free(afl->fsrv.out_file);
   ck_free(afl->sync_id);
+  afl_state_deinit(afl);
   free(afl);                                                 /* not tracked */
 
   argv_cpy_free(argv);
diff --git a/src/afl-gcc.c b/src/afl-gcc.c
index b0153b49..1ae10975 100644
--- a/src/afl-gcc.c
+++ b/src/afl-gcc.c
@@ -142,12 +142,12 @@ static void edit_params(u32 argc, char **argv) {
     if (!strcmp(name, "afl-clang++")) {
 
       u8 *alt_cxx = getenv("AFL_CXX");
-      cc_params[0] = alt_cxx ? alt_cxx : (u8 *)"clang++";
+      cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)"clang++";
 
     } else {
 
       u8 *alt_cc = getenv("AFL_CC");
-      cc_params[0] = alt_cc ? alt_cc : (u8 *)"clang";
+      cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"clang";
 
     }
 
@@ -187,17 +187,17 @@ static void edit_params(u32 argc, char **argv) {
     if (!strcmp(name, "afl-g++")) {
 
       u8 *alt_cxx = getenv("AFL_CXX");
-      cc_params[0] = alt_cxx ? alt_cxx : (u8 *)"g++";
+      cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)"g++";
 
     } else if (!strcmp(name, "afl-gcj")) {
 
       u8 *alt_cc = getenv("AFL_GCJ");
-      cc_params[0] = alt_cc ? alt_cc : (u8 *)"gcj";
+      cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"gcj";
 
     } else {
 
       u8 *alt_cc = getenv("AFL_CC");
-      cc_params[0] = alt_cc ? alt_cc : (u8 *)"gcc";
+      cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"gcc";
 
     }
 
@@ -411,6 +411,15 @@ int main(int argc, char **argv) {
 
   }
 
+  u8 *ptr;
+  if (!be_quiet &&
+      ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE")))) {
+
+    u32 map_size = atoi(ptr);
+    if (map_size != MAP_SIZE) FATAL("AFL_MAP_SIZE is not supported by afl-gcc");
+
+  }
+
   find_as(argv[0]);
 
   edit_params(argc, argv);
diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c
index 7bdf8d03..a130411e 100644
--- a/src/afl-sharedmem.c
+++ b/src/afl-sharedmem.c
@@ -40,7 +40,6 @@
 
 #include <stdio.h>
 #include <unistd.h>
-#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
@@ -61,18 +60,19 @@
 #include <sys/shm.h>
 #endif
 
-list_t shm_list = {.element_prealloc_count = 0};
+static list_t shm_list = {.element_prealloc_count = 0};
 
 /* Get rid of shared memory. */
 
 void afl_shm_deinit(sharedmem_t *shm) {
 
+  // TODO: clang reports a potential UAF in this function/makro(?)
   list_remove(&shm_list, shm);
 
 #ifdef USEMMAP
   if (shm->map != NULL) {
 
-    munmap(shm->map, shm->size_alloc);
+    munmap(shm->map, shm->map_size);
     shm->map = NULL;
 
   }
@@ -93,21 +93,13 @@ void afl_shm_deinit(sharedmem_t *shm) {
 
 }
 
-/* At exit, remove all leftover maps */
-
-void afl_shm_atexit() {
-
-  LIST_FOREACH(&shm_list, sharedmem_t, { afl_shm_deinit(el); });
-
-}
-
 /* Configure shared memory.
    Returns a pointer to shm->map for ease of use.
 */
 
 u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, unsigned char dumb_mode) {
 
-  shm->size_alloc = shm->size_used = map_size;
+  shm->map_size = map_size;
 
   shm->map = NULL;
 
@@ -207,7 +199,6 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, unsigned char dumb_mode) {
 #endif
 
   list_append(&shm_list, shm);
-  atexit(afl_shm_atexit);
 
   return shm->map;
 
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index e4463dc4..59b4963d 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -8,7 +8,8 @@
 
    Now maintained by Marc Heuse <mh@mh-sec.de>,
                         Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
-                        Andrea Fioraldi <andreafioraldi@gmail.com>
+                        Andrea Fioraldi <andreafioraldi@gmail.com> and
+                        Dominik Maier <mail@dmnk.co>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
    Copyright 2019-2020 AFLplusplus Project. All rights reserved.
@@ -51,6 +52,7 @@
 #include <signal.h>
 #include <dirent.h>
 #include <fcntl.h>
+#include <limits.h>
 
 #include <sys/wait.h>
 #include <sys/time.h>
@@ -59,19 +61,21 @@
 #include <sys/types.h>
 #include <sys/resource.h>
 
-char *stdin_file;                      /* stdin file                        */
+static char *stdin_file;               /* stdin file                        */
 
-u8 *in_dir,                            /* input folder                      */
-    *at_file = NULL;              /* Substitution string for @@             */
+static u8 *in_dir = NULL,              /* input folder                      */
+    *out_file = NULL, *at_file = NULL;        /* Substitution string for @@ */
 
 static u8 *in_data;                    /* Input data                        */
 
 static u32 total, highest;             /* tuple content information         */
 
 static u32 in_len,                     /* Input data length                 */
-    arg_offset, total_execs;           /* Total number of execs             */
+    arg_offset;                        /* Total number of execs             */
 
-u8 quiet_mode,                         /* Hide non-essential messages?      */
+static u32 map_size = MAP_SIZE;
+
+static u8 quiet_mode,                  /* Hide non-essential messages?      */
     edges_only,                        /* Ignore hit counts?                */
     raw_instr_output,                  /* Do not apply AFL filters          */
     cmin_mode,                         /* Generate output in afl-cmin mode? */
@@ -81,8 +85,6 @@ u8 quiet_mode,                         /* Hide non-essential messages?      */
 static volatile u8 stop_soon,          /* Ctrl-C pressed?                   */
     child_crashed;                     /* Child crashed?                    */
 
-static u8 qemu_mode;
-
 /* Classify tuple counts. Instead of mapping to individual bits, as in
    afl-fuzz.c, we map to more user-friendly numbers between 1 and 8. */
 
@@ -108,9 +110,12 @@ static const u8 count_class_binary[256] = {
 
 };
 
-static void classify_counts(u8 *mem, const u8 *map) {
+static void classify_counts(afl_forkserver_t *fsrv) {
 
-  u32 i = MAP_SIZE;
+  u8 *      mem = fsrv->trace_bits;
+  const u8 *map = binary_mode ? count_class_binary : count_class_human;
+
+  u32 i = map_size;
 
   if (edges_only) {
 
@@ -156,7 +161,7 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
 
     fd = open(outfile, O_WRONLY);
 
-    if (fd < 0) PFATAL("Unable to open '%s'", fsrv->out_file);
+    if (fd < 0) PFATAL("Unable to open '%s'", out_file);
 
   } else if (!strcmp(outfile, "-")) {
 
@@ -173,10 +178,10 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
 
   if (binary_mode) {
 
-    for (i = 0; i < MAP_SIZE; i++)
+    for (i = 0; i < map_size; i++)
       if (fsrv->trace_bits[i]) ret++;
 
-    ck_write(fd, fsrv->trace_bits, MAP_SIZE, outfile);
+    ck_write(fd, fsrv->trace_bits, map_size, outfile);
     close(fd);
 
   } else {
@@ -185,7 +190,7 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
 
     if (!f) PFATAL("fdopen() failed");
 
-    for (i = 0; i < MAP_SIZE; i++) {
+    for (i = 0; i < map_size; i++) {
 
       if (!fsrv->trace_bits[i]) continue;
       ret++;
@@ -195,7 +200,7 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
 
       if (cmin_mode) {
 
-        if (fsrv->child_timed_out) break;
+        if (fsrv->last_run_timed_out) break;
         if (!caa && child_crashed != cco) break;
 
         fprintf(f, "%u%u\n", fsrv->trace_bits[i], i);
@@ -214,96 +219,21 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
 
 }
 
-/* Write results. */
-
-static u32 write_results(afl_forkserver_t *fsrv) {
-
-  return write_results_to_file(fsrv, fsrv->out_file);
-
-}
-
-/* Write modified data to file for testing. If use_stdin is clear, the old file
-   is unlinked and a new one is created. Otherwise, out_fd is rewound and
-   truncated. */
-
-static void write_to_testcase(afl_forkserver_t *fsrv, void *mem, u32 len) {
-
-  lseek(fsrv->out_fd, 0, SEEK_SET);
-  ck_write(fsrv->out_fd, mem, len, fsrv->out_file);
-  if (ftruncate(fsrv->out_fd, len)) PFATAL("ftruncate() failed");
-  lseek(fsrv->out_fd, 0, SEEK_SET);
-
-}
-
-/* Execute target application. Returns 0 if the changes are a dud, or
-   1 if they should be kept. */
-
-static u8 run_target_forkserver(afl_forkserver_t *fsrv, char **argv, u8 *mem,
-                                u32 len) {
-
-  struct itimerval it;
-  int              status = 0;
-
-  memset(fsrv->trace_bits, 0, MAP_SIZE);
-  MEM_BARRIER();
-
-  write_to_testcase(fsrv, mem, len);
-
-  s32 res;
-
-  /* we have the fork server up and running, so simply
-     tell it to have at it, and then read back PID. */
-
-  if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->prev_timed_out, 4)) != 4) {
-
-    if (stop_soon) return 0;
-    RPFATAL(res, "Unable to request new process from fork server (OOM?)");
-
-  }
-
-  if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) {
+/* Execute target application. */
 
-    if (stop_soon) return 0;
-    RPFATAL(res, "Unable to request new process from fork server (OOM?)");
+static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, char **argv,
+                                          u8 *mem, u32 len) {
 
-  }
+  afl_fsrv_write_to_testcase(fsrv, mem, len);
 
-  if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)");
+  if (afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon) ==
+      FSRV_RUN_ERROR) {
 
-  /* Configure timeout, wait for child, cancel timeout. */
-
-  if (fsrv->exec_tmout) {
-
-    it.it_value.tv_sec = (fsrv->exec_tmout / 1000);
-    it.it_value.tv_usec = (fsrv->exec_tmout % 1000) * 1000;
+    FATAL("Error running target");
 
   }
 
-  setitimer(ITIMER_REAL, &it, NULL);
-
-  if ((res = read(fsrv->fsrv_st_fd, &status, 4)) != 4) {
-
-    if (stop_soon) return 0;
-    RPFATAL(res, "Unable to communicate with fork server (OOM?)");
-
-  }
-
-  fsrv->child_pid = 0;
-  it.it_value.tv_sec = 0;
-  it.it_value.tv_usec = 0;
-
-  setitimer(ITIMER_REAL, &it, NULL);
-
-  MEM_BARRIER();
-
-  /* Clean up bitmap, analyze exit condition, etc. */
-
-  if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG)
-    FATAL("Unable to execute '%s'", argv[0]);
-
-  classify_counts(fsrv->trace_bits,
-                  binary_mode ? count_class_binary : count_class_human);
-  total_execs++;
+  classify_counts(fsrv);
 
   if (stop_soon) {
 
@@ -312,27 +242,11 @@ static u8 run_target_forkserver(afl_forkserver_t *fsrv, char **argv, u8 *mem,
 
   }
 
-  /* Always discard inputs that time out. */
-
-  if (fsrv->child_timed_out) { return 0; }
-
-  /* Handle crashing inputs depending on current mode. */
-
-  if (WIFSIGNALED(status) ||
-      (WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) ||
-      (WIFEXITED(status) && WEXITSTATUS(status))) {
-
-    return 0;
-
-  }
-
-  return 0;
-
 }
 
 /* Read initial file. */
 
-u32 read_file(u8 *in_file) {
+static u32 read_file(u8 *in_file) {
 
   struct stat st;
   s32         fd = open(in_file, O_RDONLY);
@@ -357,7 +271,7 @@ u32 read_file(u8 *in_file) {
 
 /* Execute target application. */
 
-static void run_target(afl_forkserver_t *fsrv, char **argv) {
+static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
 
   static struct itimerval it;
   int                     status = 0;
@@ -427,7 +341,7 @@ static void run_target(afl_forkserver_t *fsrv, char **argv) {
 
   if (fsrv->exec_tmout) {
 
-    fsrv->child_timed_out = 0;
+    fsrv->last_run_timed_out = 0;
     it.it_value.tv_sec = (fsrv->exec_tmout / 1000);
     it.it_value.tv_usec = (fsrv->exec_tmout % 1000) * 1000;
 
@@ -449,17 +363,16 @@ static void run_target(afl_forkserver_t *fsrv, char **argv) {
   if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG)
     FATAL("Unable to execute '%s'", argv[0]);
 
-  classify_counts(fsrv->trace_bits,
-                  binary_mode ? count_class_binary : count_class_human);
+  classify_counts(fsrv);
 
   if (!quiet_mode) SAYF(cRST "-- Program output ends --\n");
 
-  if (!fsrv->child_timed_out && !stop_soon && WIFSIGNALED(status))
+  if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(status))
     child_crashed = 1;
 
   if (!quiet_mode) {
 
-    if (fsrv->child_timed_out)
+    if (fsrv->last_run_timed_out)
       SAYF(cLRD "\n+++ Program timed off +++\n" cRST);
     else if (stop_soon)
       SAYF(cLRD "\n+++ Program aborted by user +++\n" cRST);
@@ -482,7 +395,7 @@ static void handle_stop_sig(int sig) {
 
 /* Do basic preparations - persistent fds, filenames, etc. */
 
-static void set_up_environment(void) {
+static void set_up_environment(afl_forkserver_t *fsrv) {
 
   setenv("ASAN_OPTIONS",
          "abort_on_error=1:"
@@ -499,7 +412,7 @@ static void set_up_environment(void) {
 
   if (get_afl_env("AFL_PRELOAD")) {
 
-    if (qemu_mode) {
+    if (fsrv->qemu_mode) {
 
       u8 *qemu_preload = getenv("QEMU_SET_ENV");
       u8 *afl_preload = getenv("AFL_PRELOAD");
@@ -576,11 +489,9 @@ static void usage(u8 *argv0) {
       "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
 
       "Required parameters:\n"
-
       "  -o file       - file to write the trace data to\n\n"
 
       "Execution control settings:\n"
-
       "  -t msec       - timeout for each run (none)\n"
       "  -m megs       - memory limit for child process (%d MB)\n"
       "  -Q            - use binary-only instrumentation (QEMU mode)\n"
@@ -588,9 +499,7 @@ static void usage(u8 *argv0) {
       "  -W            - use qemu-based instrumentation with Wine (Wine mode)\n"
       "                  (Not necessary, here for consistency with other afl-* "
       "tools)\n\n"
-
       "Other settings:\n"
-
       "  -i dir        - process all files in this directory, -o must be a "
       "directory\n"
       "                  and each bitmap will be written there individually.\n"
@@ -603,75 +512,22 @@ static void usage(u8 *argv0) {
       "For additional help, consult %s/README.md.\n\n"
 
       "Environment variables used:\n"
-      "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
-      "AFL_DEBUG: enable extra developer output\n"
-      "AFL_QUIET: do not print extra informational output"
+      "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
       "AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing "
       "inputs\n"
       "AFL_CMIN_ALLOW_ANY: (cmin_mode) write tuples for crashing inputs also\n"
-      "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n",
+      "AFL_DEBUG: enable extra developer output\n"
+      "AFL_MAP_SIZE: the shared memory size for that target. must be >= the "
+      "size\n"
+      "              the target was compiled for\n"
+      "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
+      "AFL_QUIET: do not print extra informational output",
       argv0, MEM_LIMIT, doc_path);
 
   exit(1);
 
 }
 
-/* Find binary. */
-
-static void find_binary(afl_forkserver_t *fsrv, u8 *fname) {
-
-  u8 *        env_path = 0;
-  struct stat st;
-
-  if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
-
-    fsrv->target_path = ck_strdup(fname);
-
-    if (stat(fsrv->target_path, &st) || !S_ISREG(st.st_mode) ||
-        !(st.st_mode & 0111) || st.st_size < 4)
-      FATAL("Program '%s' not found or not executable", fname);
-
-  } else {
-
-    while (env_path) {
-
-      u8 *cur_elem, *delim = strchr(env_path, ':');
-
-      if (delim) {
-
-        cur_elem = ck_alloc(delim - env_path + 1);
-        memcpy(cur_elem, env_path, delim - env_path);
-        delim++;
-
-      } else
-
-        cur_elem = ck_strdup(env_path);
-
-      env_path = delim;
-
-      if (cur_elem[0])
-        fsrv->target_path = alloc_printf("%s/%s", cur_elem, fname);
-      else
-        fsrv->target_path = ck_strdup(fname);
-
-      ck_free(cur_elem);
-
-      if (!stat(fsrv->target_path, &st) && S_ISREG(st.st_mode) &&
-          (st.st_mode & 0111) && st.st_size >= 4)
-        break;
-
-      ck_free(fsrv->target_path);
-      fsrv->target_path = 0;
-
-    }
-
-    if (!fsrv->target_path)
-      FATAL("Program '%s' not found or not executable", fname);
-
-  }
-
-}
-
 /* Main entry point */
 
 int main(int argc, char **argv_orig, char **envp) {
@@ -688,6 +544,8 @@ int main(int argc, char **argv_orig, char **envp) {
   afl_forkserver_t  fsrv_var = {0};
   afl_forkserver_t *fsrv = &fsrv_var;
   afl_fsrv_init(fsrv);
+  map_size = get_map_size();
+  fsrv->map_size = map_size;
 
   doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
 
@@ -704,8 +562,8 @@ int main(int argc, char **argv_orig, char **envp) {
 
       case 'o':
 
-        if (fsrv->out_file) FATAL("Multiple -o options not supported");
-        fsrv->out_file = optarg;
+        if (out_file) FATAL("Multiple -o options not supported");
+        out_file = optarg;
         break;
 
       case 'm': {
@@ -715,6 +573,8 @@ int main(int argc, char **argv_orig, char **envp) {
         if (mem_limit_given) FATAL("Multiple -m options not supported");
         mem_limit_given = 1;
 
+        if (!optarg) FATAL("Wrong usage of -m");
+
         if (!strcmp(optarg, "none")) {
 
           fsrv->mem_limit = 0;
@@ -758,6 +618,8 @@ int main(int argc, char **argv_orig, char **envp) {
         if (timeout_given) FATAL("Multiple -t options not supported");
         timeout_given = 1;
 
+        if (!optarg) FATAL("Wrong usage of -t");
+
         if (strcmp(optarg, "none")) {
 
           fsrv->exec_tmout = atoi(optarg);
@@ -798,10 +660,10 @@ int main(int argc, char **argv_orig, char **envp) {
 
       case 'Q':
 
-        if (qemu_mode) FATAL("Multiple -Q options not supported");
+        if (fsrv->qemu_mode) FATAL("Multiple -Q options not supported");
         if (!mem_limit_given) fsrv->mem_limit = MEM_LIMIT_QEMU;
 
-        qemu_mode = 1;
+        fsrv->qemu_mode = 1;
         break;
 
       case 'U':
@@ -815,7 +677,7 @@ int main(int argc, char **argv_orig, char **envp) {
       case 'W':                                           /* Wine+QEMU mode */
 
         if (use_wine) FATAL("Multiple -W options not supported");
-        qemu_mode = 1;
+        fsrv->qemu_mode = 1;
         use_wine = 1;
 
         if (!mem_limit_given) fsrv->mem_limit = 0;
@@ -852,17 +714,17 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
-  if (optind == argc || !fsrv->out_file) usage(argv[0]);
+  if (optind == argc || !out_file) usage(argv[0]);
 
   check_environment_vars(envp);
 
   sharedmem_t shm = {0};
-  fsrv->trace_bits = afl_shm_init(&shm, MAP_SIZE, 0);
+  fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
   setup_signal_handlers();
 
-  set_up_environment();
+  set_up_environment(fsrv);
 
-  find_binary(fsrv, argv[optind]);
+  fsrv->target_path = find_binary(argv[optind]);
 
   if (!quiet_mode) {
 
@@ -885,7 +747,7 @@ int main(int argc, char **argv_orig, char **envp) {
   for (i = optind; i < argc; i++)
     if (strcmp(argv[i], "@@") == 0) arg_offset = i;
 
-  if (qemu_mode) {
+  if (fsrv->qemu_mode) {
 
     if (use_wine)
       use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind,
@@ -903,7 +765,7 @@ int main(int argc, char **argv_orig, char **envp) {
     DIR *          dir_in, *dir_out;
     struct dirent *dir_ent;
     int            done = 0;
-    u8             infile[4096], outfile[4096];
+    u8             infile[PATH_MAX], outfile[PATH_MAX];
 #if !defined(DT_REG)
     struct stat statbuf;
 #endif
@@ -913,9 +775,9 @@ int main(int argc, char **argv_orig, char **envp) {
 
     if (!(dir_in = opendir(in_dir))) PFATAL("cannot open directory %s", in_dir);
 
-    if (!(dir_out = opendir(fsrv->out_file)))
-      if (mkdir(fsrv->out_file, 0700))
-        PFATAL("cannot create output directory %s", fsrv->out_file);
+    if (!(dir_out = opendir(out_file)))
+      if (mkdir(out_file, 0700))
+        PFATAL("cannot create output directory %s", out_file);
 
     u8 *use_dir = ".";
 
@@ -930,7 +792,7 @@ int main(int argc, char **argv_orig, char **envp) {
     unlink(stdin_file);
     atexit(at_exit_handler);
     fsrv->out_fd = open(stdin_file, O_RDWR | O_CREAT | O_EXCL, 0600);
-    if (fsrv->out_fd < 0) PFATAL("Unable to create '%s'", fsrv->out_file);
+    if (fsrv->out_fd < 0) PFATAL("Unable to create '%s'", out_file);
 
     if (arg_offset && argv[arg_offset] != stdin_file) {
 
@@ -951,7 +813,8 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
-    afl_fsrv_start(fsrv, use_argv);
+    afl_fsrv_start(fsrv, use_argv, &stop_soon,
+                   get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0);
 
     while (done == 0 && (dir_ent = readdir(dir_in))) {
 
@@ -968,12 +831,11 @@ int main(int argc, char **argv_orig, char **envp) {
       if (-1 == stat(infile, &statbuf) || !S_ISREG(statbuf.st_mode)) continue;
 #endif
 
-      snprintf(outfile, sizeof(outfile), "%s/%s", fsrv->out_file,
-               dir_ent->d_name);
+      snprintf(outfile, sizeof(outfile), "%s/%s", out_file, dir_ent->d_name);
 
       if (read_file(infile)) {
 
-        run_target_forkserver(fsrv, use_argv, in_data, in_len);
+        showmap_run_target_forkserver(fsrv, use_argv, in_data, in_len);
         ck_free(in_data);
         tcnt = write_results_to_file(fsrv, outfile);
 
@@ -981,15 +843,15 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
-    if (!quiet_mode) OKF("Processed %u input files.", total_execs);
+    if (!quiet_mode) OKF("Processed %llu input files.", fsrv->total_execs);
 
     closedir(dir_in);
-    closedir(dir_out);
+    if (dir_out) closedir(dir_out);
 
   } else {
 
-    run_target(fsrv, use_argv);
-    tcnt = write_results(fsrv);
+    showmap_run_target(fsrv, use_argv);
+    tcnt = write_results_to_file(fsrv, out_file);
 
   }
 
@@ -997,7 +859,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
     if (!tcnt) FATAL("No instrumentation detected" cRST);
     OKF("Captured %u tuples (highest value %u, total values %u) in '%s'." cRST,
-        tcnt, highest, total, fsrv->out_file);
+        tcnt, highest, total, out_file);
 
   }
 
@@ -1011,7 +873,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   afl_shm_deinit(&shm);
 
-  u32 ret = child_crashed * 2 + fsrv->child_timed_out;
+  u32 ret = child_crashed * 2 + fsrv->last_run_timed_out;
 
   if (fsrv->target_path) ck_free(fsrv->target_path);
 
@@ -1019,6 +881,7 @@ int main(int argc, char **argv_orig, char **envp) {
   if (stdin_file) ck_free(stdin_file);
 
   argv_cpy_free(argv);
+  if (fsrv->qemu_mode) free(use_argv[2]);
 
   exit(ret);
 
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index 30e76d42..dab2a417 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -8,7 +8,8 @@
 
    Now maintained by Marc Heuse <mh@mh-sec.de>,
                         Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
-                        Andrea Fioraldi <andreafioraldi@gmail.com>
+                        Andrea Fioraldi <andreafioraldi@gmail.com> and
+                        Dominik Maier <mail@dmnk.co>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
    Copyright 2019-2020 AFLplusplus Project. All rights reserved.
@@ -60,19 +61,19 @@
 
 static u8 *mask_bitmap;                /* Mask for trace bits (-B)          */
 
-u8 *in_file,                           /* Minimizer input test case         */
-    *output_file;                      /* Minimizer output file             */
+static u8 *in_file,                    /* Minimizer input test case         */
+    *out_file, *output_file;           /* Minimizer output file             */
 
 static u8 *in_data;                    /* Input data for trimming           */
 
 static u32 in_len,                     /* Input data length                 */
     orig_cksum,                        /* Original checksum                 */
-    total_execs,                       /* Total number of execs             */
     missed_hangs,                      /* Misses due to hangs               */
     missed_crashes,                    /* Misses due to crashes             */
-    missed_paths;                      /* Misses due to exec path diffs     */
+    missed_paths,                      /* Misses due to exec path diffs     */
+    map_size = MAP_SIZE;
 
-u8 crash_mode,                         /* Crash-centric mode?               */
+static u8 crash_mode,                  /* Crash-centric mode?               */
     hang_mode,                         /* Minimize as long as it hangs      */
     exit_crash,                        /* Treat non-zero exit as crash?     */
     edges_only,                        /* Ignore hit counts?                */
@@ -80,8 +81,6 @@ u8 crash_mode,                         /* Crash-centric mode?               */
 
 static volatile u8 stop_soon;          /* Ctrl-C pressed?                   */
 
-static u8 qemu_mode;
-
 /*
  * forkserver section
  */
@@ -103,9 +102,28 @@ static const u8 count_class_lookup[256] = {
 
 };
 
-static void classify_counts(u8 *mem) {
+/* Apply mask to classified bitmap (if set). */
+
+static void apply_mask(u32 *mem, u32 *mask) {
+
+  u32 i = (map_size >> 2);
+
+  if (!mask) return;
+
+  while (i--) {
+
+    *mem &= ~*mask;
+    mem++;
+    mask++;
+
+  }
+
+}
+
+static void classify_counts(afl_forkserver_t *fsrv) {
 
-  u32 i = MAP_SIZE;
+  u8 *mem = fsrv->trace_bits;
+  u32 i = map_size;
 
   if (edges_only) {
 
@@ -129,30 +147,12 @@ static void classify_counts(u8 *mem) {
 
 }
 
-/* Apply mask to classified bitmap (if set). */
-
-static void apply_mask(u32 *mem, u32 *mask) {
-
-  u32 i = (MAP_SIZE >> 2);
-
-  if (!mask) return;
-
-  while (i--) {
-
-    *mem &= ~*mask;
-    mem++;
-    mask++;
-
-  }
-
-}
-
 /* See if any bytes are set in the bitmap. */
 
 static inline u8 anything_set(afl_forkserver_t *fsrv) {
 
   u32 *ptr = (u32 *)fsrv->trace_bits;
-  u32  i = (MAP_SIZE >> 2);
+  u32  i = (map_size >> 2);
 
   while (i--)
     if (*(ptr++)) return 1;
@@ -212,117 +212,18 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
 
 }
 
-/* Write modified data to file for testing. If use_stdin is clear, the old file
-   is unlinked and a new one is created. Otherwise, out_fd is rewound and
-   truncated. */
-
-static void write_to_testcase(afl_forkserver_t *fsrv, void *mem, u32 len) {
-
-  s32 fd = fsrv->out_fd;
-
-  if (!fsrv->use_stdin) {
-
-    unlink(fsrv->out_file);                               /* Ignore errors. */
-
-    fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
-
-    if (fd < 0) PFATAL("Unable to create '%s'", fsrv->out_file);
-
-  } else
-
-    lseek(fd, 0, SEEK_SET);
-
-  ck_write(fd, mem, len, fsrv->out_file);
-
-  if (fsrv->use_stdin) {
-
-    if (ftruncate(fd, len)) PFATAL("ftruncate() failed");
-    lseek(fd, 0, SEEK_SET);
-
-  } else
-
-    close(fd);
-
-}
-
 /* Execute target application. Returns 0 if the changes are a dud, or
    1 if they should be kept. */
 
-static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
-                     u8 first_run) {
-
-  struct itimerval it;
-  int              status = 0;
-
-  u32 cksum;
-
-  fsrv->child_timed_out = 0;
-
-  memset(fsrv->trace_bits, 0, MAP_SIZE);
-  MEM_BARRIER();
-
-  write_to_testcase(fsrv, mem, len);
-
-  s32 res;
-
-  /* we have the fork server up and running, so simply
-     tell it to have at it, and then read back PID. */
-
-  if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->prev_timed_out, 4)) != 4) {
-
-    if (stop_soon) return 0;
-    RPFATAL(res, "Unable to request new process from fork server (OOM?)");
-
-  }
-
-  if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) {
-
-    if (stop_soon) return 0;
-    RPFATAL(res, "Unable to request new process from fork server (OOM?)");
-
-  }
+static u8 tmin_run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
+                          u8 first_run) {
 
-  if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)");
+  afl_fsrv_write_to_testcase(fsrv, mem, len);
 
-  /* Configure timeout, wait for child, cancel timeout. */
+  fsrv_run_result_t ret =
+      afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon);
 
-  if (fsrv->exec_tmout) {
-
-    it.it_value.tv_sec = (fsrv->exec_tmout / 1000);
-    it.it_value.tv_usec = (fsrv->exec_tmout % 1000) * 1000;
-
-  }
-
-  setitimer(ITIMER_REAL, &it, NULL);
-
-  if ((res = read(fsrv->fsrv_st_fd, &status, 4)) != 4) {
-
-    if (stop_soon) return 0;
-    RPFATAL(res, "Unable to communicate with fork server (OOM?)");
-
-  }
-
-  fsrv->child_pid = 0;
-  it.it_value.tv_sec = 0;
-  it.it_value.tv_usec = 0;
-
-  setitimer(ITIMER_REAL, &it, NULL);
-
-  MEM_BARRIER();
-
-  /* Clean up bitmap, analyze exit condition, etc. */
-
-  if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG)
-    FATAL("Unable to execute '%s'", argv[0]);
-
-  if (!hang_mode) {
-
-    classify_counts(fsrv->trace_bits);
-    apply_mask((u32 *)fsrv->trace_bits, (u32 *)mask_bitmap);
-
-  }
-
-  total_execs++;
+  if (ret == FSRV_RUN_ERROR) FATAL("Couldn't run child");
 
   if (stop_soon) {
 
@@ -336,25 +237,20 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
 
   if (hang_mode) {
 
-    if (fsrv->child_timed_out) return 1;
-
-    if (WIFSIGNALED(status) ||
-        (WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) ||
-        (WIFEXITED(status) && WEXITSTATUS(status) && exit_crash)) {
+    switch (ret) {
 
-      missed_crashes++;
-
-    } else {
-
-      missed_hangs++;
+      case FSRV_RUN_TMOUT: return 1;
+      case FSRV_RUN_CRASH: missed_crashes++; return 0;
+      default: missed_hangs++; return 0;
 
     }
 
-    return 0;
-
   }
 
-  if (fsrv->child_timed_out) {
+  classify_counts(fsrv);
+  apply_mask((u32 *)fsrv->trace_bits, (u32 *)mask_bitmap);
+
+  if (ret == FSRV_RUN_TMOUT) {
 
     missed_hangs++;
     return 0;
@@ -363,9 +259,7 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
 
   /* Handle crashing inputs depending on current mode. */
 
-  if (WIFSIGNALED(status) ||
-      (WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) ||
-      (WIFEXITED(status) && WEXITSTATUS(status) && exit_crash)) {
+  if (ret == FSRV_RUN_CRASH) {
 
     if (first_run) crash_mode = 1;
 
@@ -393,7 +287,9 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
 
   }
 
-  cksum = hash32(fsrv->trace_bits, MAP_SIZE, HASH_CONST);
+  if (ret == FSRV_RUN_NOINST) FATAL("Binary not instrumented?");
+
+  u32 cksum = hash32(fsrv->trace_bits, fsrv->map_size, HASH_CONST);
 
   if (first_run) orig_cksum = cksum;
 
@@ -441,7 +337,7 @@ static void minimize(afl_forkserver_t *fsrv, char **argv) {
       memset(tmp_buf + set_pos, '0', use_len);
 
       u8 res;
-      res = run_target(fsrv, argv, tmp_buf, in_len, 0);
+      res = tmin_run_target(fsrv, argv, tmp_buf, in_len, 0);
 
       if (res) {
 
@@ -514,7 +410,7 @@ next_del_blksize:
     /* Tail */
     memcpy(tmp_buf + del_pos, in_data + del_pos + del_len, tail_len);
 
-    res = run_target(fsrv, argv, tmp_buf, del_pos + tail_len, 0);
+    res = tmin_run_target(fsrv, argv, tmp_buf, del_pos + tail_len, 0);
 
     if (res) {
 
@@ -577,7 +473,7 @@ next_del_blksize:
     for (r = 0; r < in_len; r++)
       if (tmp_buf[r] == i) tmp_buf[r] = '0';
 
-    res = run_target(fsrv, argv, tmp_buf, in_len, 0);
+    res = tmin_run_target(fsrv, argv, tmp_buf, in_len, 0);
 
     if (res) {
 
@@ -613,7 +509,7 @@ next_del_blksize:
     if (orig == '0') continue;
     tmp_buf[i] = '0';
 
-    res = run_target(fsrv, argv, tmp_buf, in_len, 0);
+    res = tmin_run_target(fsrv, argv, tmp_buf, in_len, 0);
 
     if (res) {
 
@@ -642,25 +538,27 @@ finalize_all:
 
     SAYF("\n" cGRA "     File size reduced by : " cRST
          "%0.02f%% (to %u byte%s)\n" cGRA "    Characters simplified : " cRST
-         "%0.02f%%\n" cGRA "     Number of execs done : " cRST "%u\n" cGRA
+         "%0.02f%%\n" cGRA "     Number of execs done : " cRST "%llu\n" cGRA
          "          Fruitless execs : " cRST "termination=%u crash=%u\n\n",
          100 - ((double)in_len) * 100 / orig_len, in_len,
          in_len == 1 ? "" : "s",
-         ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1), total_execs,
-         missed_paths, missed_crashes);
+         ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1),
+         fsrv->total_execs, missed_paths, missed_crashes);
     return;
 
   }
 
   SAYF("\n" cGRA "     File size reduced by : " cRST
        "%0.02f%% (to %u byte%s)\n" cGRA "    Characters simplified : " cRST
-       "%0.02f%%\n" cGRA "     Number of execs done : " cRST "%u\n" cGRA
+       "%0.02f%%\n" cGRA "     Number of execs done : " cRST "%llu\n" cGRA
        "          Fruitless execs : " cRST "path=%u crash=%u hang=%s%u\n\n",
        100 - ((double)in_len) * 100 / orig_len, in_len, in_len == 1 ? "" : "s",
-       ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1), total_execs,
-       missed_paths, missed_crashes, missed_hangs ? cLRD : "", missed_hangs);
+       ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1),
+       fsrv->total_execs, missed_paths, missed_crashes,
+       missed_hangs ? cLRD : "", missed_hangs);
 
-  if (total_execs > 50 && missed_hangs * 10 > total_execs && !hang_mode)
+  if (fsrv->total_execs > 50 && missed_hangs * 10 > fsrv->total_execs &&
+      !hang_mode)
     WARNF(cLRD "Frequent timeouts - results may be skewed." cRST);
 
 }
@@ -683,7 +581,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
   fsrv->dev_null_fd = open("/dev/null", O_RDWR);
   if (fsrv->dev_null_fd < 0) PFATAL("Unable to open /dev/null");
 
-  if (!fsrv->out_file) {
+  if (!out_file) {
 
     u8 *use_dir = ".";
 
@@ -694,15 +592,15 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
 
     }
 
-    fsrv->out_file = alloc_printf("%s/.afl-tmin-temp-%u", use_dir, getpid());
+    out_file = alloc_printf("%s/.afl-tmin-temp-%u", use_dir, getpid());
 
   }
 
-  unlink(fsrv->out_file);
+  unlink(out_file);
 
-  fsrv->out_fd = open(fsrv->out_file, O_RDWR | O_CREAT | O_EXCL, 0600);
+  fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, 0600);
 
-  if (fsrv->out_fd < 0) PFATAL("Unable to create '%s'", fsrv->out_file);
+  if (fsrv->out_fd < 0) PFATAL("Unable to create '%s'", out_file);
 
   /* Set sane defaults... */
 
@@ -746,7 +644,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
 
   if (get_afl_env("AFL_PRELOAD")) {
 
-    if (qemu_mode) {
+    if (fsrv->qemu_mode) {
 
       u8 *qemu_preload = getenv("QEMU_SET_ENV");
       u8 *afl_preload = getenv("AFL_PRELOAD");
@@ -843,7 +741,9 @@ static void usage(u8 *argv0) {
       "              (must contain abort_on_error=1 and symbolize=0)\n"
       "MSAN_OPTIONS: custom settings for MSAN\n"
       "              (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
-      "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
+      "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
+      "              the target was compiled for\n"
+      "AFL_PRELOAD:  LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
       "AFL_TMIN_EXACT: require execution paths to match for crashing inputs\n"
 
       , argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
@@ -852,76 +752,6 @@ static void usage(u8 *argv0) {
 
 }
 
-/* Find binary. */
-
-static void find_binary(afl_forkserver_t *fsrv, u8 *fname) {
-
-  u8 *        env_path = 0;
-  struct stat st;
-
-  if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
-
-    fsrv->target_path = ck_strdup(fname);
-
-    if (stat(fsrv->target_path, &st) || !S_ISREG(st.st_mode) ||
-        !(st.st_mode & 0111) || st.st_size < 4)
-      FATAL("Program '%s' not found or not executable", fname);
-
-  } else {
-
-    while (env_path) {
-
-      u8 *cur_elem, *delim = strchr(env_path, ':');
-
-      if (delim) {
-
-        cur_elem = ck_alloc(delim - env_path + 1);
-        memcpy(cur_elem, env_path, delim - env_path);
-        delim++;
-
-      } else
-
-        cur_elem = ck_strdup(env_path);
-
-      env_path = delim;
-
-      if (cur_elem[0])
-        fsrv->target_path = alloc_printf("%s/%s", cur_elem, fname);
-      else
-        fsrv->target_path = ck_strdup(fname);
-
-      ck_free(cur_elem);
-
-      if (!stat(fsrv->target_path, &st) && S_ISREG(st.st_mode) &&
-          (st.st_mode & 0111) && st.st_size >= 4)
-        break;
-
-      ck_free(fsrv->target_path);
-      fsrv->target_path = NULL;
-
-    }
-
-    if (!fsrv->target_path)
-      FATAL("Program '%s' not found or not executable", fname);
-
-  }
-
-}
-
-/* Read mask bitmap from file. This is for the -B option. */
-
-static void read_bitmap(u8 *fname) {
-
-  s32 fd = open(fname, O_RDONLY);
-
-  if (fd < 0) PFATAL("Unable to open '%s'", fname);
-
-  ck_read(fd, mask_bitmap, MAP_SIZE, fname);
-
-  close(fd);
-
-}
-
 /* Main entry point */
 
 int main(int argc, char **argv_orig, char **envp) {
@@ -935,6 +765,8 @@ int main(int argc, char **argv_orig, char **envp) {
   afl_forkserver_t  fsrv_var = {0};
   afl_forkserver_t *fsrv = &fsrv_var;
   afl_fsrv_init(fsrv);
+  map_size = get_map_size();
+  fsrv->map_size = map_size;
 
   doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
 
@@ -958,9 +790,9 @@ int main(int argc, char **argv_orig, char **envp) {
 
       case 'f':
 
-        if (fsrv->out_file) FATAL("Multiple -f options not supported");
+        if (out_file) FATAL("Multiple -f options not supported");
         fsrv->use_stdin = 0;
-        fsrv->out_file = optarg;
+        out_file = optarg;
         break;
 
       case 'e':
@@ -984,6 +816,8 @@ int main(int argc, char **argv_orig, char **envp) {
         if (mem_limit_given) FATAL("Multiple -m options not supported");
         mem_limit_given = 1;
 
+        if (!optarg) FATAL("Wrong usage of -m");
+
         if (!strcmp(optarg, "none")) {
 
           fsrv->mem_limit = 0;
@@ -1020,6 +854,8 @@ int main(int argc, char **argv_orig, char **envp) {
         if (timeout_given) FATAL("Multiple -t options not supported");
         timeout_given = 1;
 
+        if (!optarg) FATAL("Wrong usage of -t");
+
         fsrv->exec_tmout = atoi(optarg);
 
         if (fsrv->exec_tmout < 10 || optarg[0] == '-')
@@ -1029,10 +865,10 @@ int main(int argc, char **argv_orig, char **envp) {
 
       case 'Q':
 
-        if (qemu_mode) FATAL("Multiple -Q options not supported");
+        if (fsrv->qemu_mode) FATAL("Multiple -Q options not supported");
         if (!mem_limit_given) fsrv->mem_limit = MEM_LIMIT_QEMU;
 
-        qemu_mode = 1;
+        fsrv->qemu_mode = 1;
         break;
 
       case 'U':
@@ -1046,7 +882,7 @@ int main(int argc, char **argv_orig, char **envp) {
       case 'W':                                           /* Wine+QEMU mode */
 
         if (use_wine) FATAL("Multiple -W options not supported");
-        qemu_mode = 1;
+        fsrv->qemu_mode = 1;
         use_wine = 1;
 
         if (!mem_limit_given) fsrv->mem_limit = 0;
@@ -1079,8 +915,8 @@ int main(int argc, char **argv_orig, char **envp) {
            to be useful. */
 
         if (mask_bitmap) FATAL("Multiple -B options not supported");
-        mask_bitmap = ck_alloc(MAP_SIZE);
-        read_bitmap(optarg);
+        mask_bitmap = ck_alloc(map_size);
+        read_bitmap(optarg, mask_bitmap, map_size);
         break;
 
       case 'h':
@@ -1097,17 +933,17 @@ int main(int argc, char **argv_orig, char **envp) {
   check_environment_vars(envp);
 
   sharedmem_t shm = {0};
-  fsrv->trace_bits = afl_shm_init(&shm, MAP_SIZE, 0);
+  fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
 
   atexit(at_exit_handler);
   setup_signal_handlers();
 
   set_up_environment(fsrv);
 
-  find_binary(fsrv, argv[optind]);
-  detect_file_args(argv + optind, fsrv->out_file, &fsrv->use_stdin);
+  fsrv->target_path = find_binary(argv[optind]);
+  detect_file_args(argv + optind, out_file, &fsrv->use_stdin);
 
-  if (qemu_mode) {
+  if (fsrv->qemu_mode) {
 
     if (use_wine)
       use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind,
@@ -1133,20 +969,21 @@ int main(int argc, char **argv_orig, char **envp) {
 
   read_initial_file();
 
-  afl_fsrv_start(fsrv, use_argv);
+  afl_fsrv_start(fsrv, use_argv, &stop_soon,
+                 get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0);
 
   ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
        fsrv->mem_limit, fsrv->exec_tmout, edges_only ? ", edges only" : "");
 
-  run_target(fsrv, use_argv, in_data, in_len, 1);
+  tmin_run_target(fsrv, use_argv, in_data, in_len, 1);
 
-  if (hang_mode && !fsrv->child_timed_out)
+  if (hang_mode && !fsrv->last_run_timed_out)
     FATAL(
         "Target binary did not time out but hang minimization mode "
         "(-H) was set (-t %u).",
         fsrv->exec_tmout);
 
-  if (fsrv->child_timed_out && !hang_mode)
+  if (fsrv->last_run_timed_out && !hang_mode)
     FATAL(
         "Target binary times out (adjusting -t may help). Use -H to minimize a "
         "hang.");
@@ -1174,9 +1011,9 @@ int main(int argc, char **argv_orig, char **envp) {
 
   ACTF("Writing output to '%s'...", output_file);
 
-  unlink(fsrv->out_file);
-  if (fsrv->out_file) ck_free(fsrv->out_file);
-  fsrv->out_file = NULL;
+  unlink(out_file);
+  if (out_file) ck_free(out_file);
+  out_file = NULL;
 
   close(write_to_file(output_file, in_data, in_len));
 
diff --git a/src/third_party/libradamsa/libradamsa.c b/src/third_party/libradamsa/libradamsa.c
index fe91594e..4f5515e5 100644
--- a/src/third_party/libradamsa/libradamsa.c
+++ b/src/third_party/libradamsa/libradamsa.c
@@ -1841,6 +1841,8 @@ static const unsigned char heap[] = {2,3,4,105,111,116,97,2,3,7,112,97,116,116,1
 #include <stdio.h>
 #include <netdb.h>
 
+#include "./radamsa.h"
+
 #ifndef EMULTIHOP
 #define EMULTIHOP -1
 #endif
@@ -2155,17 +2157,17 @@ static word *gc(int size, word *regs) {
 
 /*** OS Interaction and Helpers ***/
 
-static void signal_handler(int signal) {
-   switch (signal) {
-      case SIGINT:
-         breaked |= 2;
-         break;
-      case SIGPIPE:
-         break; /* can cause loop when reporting errors */
-      default:
-         breaked |= 4;
-   }
-}
+//static void signal_handler(int signal) {
+//   switch (signal) {
+//      case SIGINT:
+//         breaked |= 2;
+//         break;
+//      case SIGPIPE:
+//         break; /* can cause loop when reporting errors */
+//      default:
+//         breaked |= 4;
+//   }
+//}
 
 /* list length, no overflow or valid termination checks */
 static uint llen(word *ptr) {
@@ -2176,8 +2178,8 @@ static uint llen(word *ptr) {
    }
    return len;
 }
-
-static void set_signal_handler() {
+/*
+static void set_signal_handler(void) {
    struct sigaction sa;
    sa.sa_handler = signal_handler;
    sigemptyset(&sa.sa_mask);
@@ -2185,7 +2187,7 @@ static void set_signal_handler() {
    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGPIPE, &sa, NULL);
 }
-
+*/
 static word mkpair(word h, word a, word d) {
    word *pair;
    allocate(3, pair);
@@ -2312,7 +2314,7 @@ static word prim_set(word wptr, hval pos, word val) {
    return (word) new;
 }
 
-static void setdown() {
+static void setdown(void) {
    tcsetattr(0, TCSANOW, &tsettings); /* return stdio settings */
 }
 
@@ -30683,7 +30685,7 @@ static void heap_metrics(int *rwords, int *rnobjs) {
       get_obj_metrics(rwords, rnobjs);
    hp = hp_start;
 }
-
+/*
 static void read_heap(const char *path) {
    struct stat st;
    off_t pos = 0;
@@ -30703,25 +30705,26 @@ static void read_heap(const char *path) {
    } while (n && (pos += n) < st.st_size);
    close(fd);
 }
+*/
 
 /* find a fasl image source to *hp or exit */
-static void find_heap(int *nargs, char ***argv, int *nobjs, int *nwords) {
-   file_heap = NULL;
-   if ((word)heap == 0) {
+//static void find_heap(int *nargs, char ***argv, int *nobjs, int *nwords) {
+//   file_heap = NULL;
+//   if ((word)heap == 0) {
       /* if no preloaded heap, try to load it from first vm arg */
-      if (*nargs < 2)
-         exit(1);
-      read_heap(argv[0][1]);
-      ++*argv;
-      --*nargs;
-      hp = file_heap;
-      if (*hp == '#')
-         while (*hp++ != '\n');
-   } else {
-      hp = heap; /* builtin heap */
-   }
-   heap_metrics(nwords, nobjs);
-}
+//      if (*nargs < 2)
+//         exit(1);
+//      read_heap(argv[0][1]);
+//      ++*argv;
+//      --*nargs;
+//      hp = file_heap;
+//      if (*hp == '#')
+//         while (*hp++ != '\n');
+//   } else {
+//      hp = heap; /* builtin heap */
+//   }
+//   heap_metrics(nwords, nobjs);
+//}
 
 static word *decode_fasl(uint nobjs) {
    word *ptrs;
@@ -30744,7 +30747,7 @@ static word *load_heap(uint nobjs) {
       free(file_heap);
    return entry;
 }
-
+/*
 static void setup(int nwords, int nobjs) {
    tcgetattr(0, &tsettings);
    state = IFALSE;
@@ -30757,7 +30760,7 @@ static void setup(int nwords, int nobjs) {
    memend = memstart + nwords - MEMPAD;
 }
 
-int secondary(int nargs, char **argv) {
+static int secondary(int nargs, char **argv) {
    word *prog;
    int rval, nobjs=0, nwords=0;
    find_heap(&nargs, &argv, &nobjs, &nwords);
@@ -30772,8 +30775,9 @@ int secondary(int nargs, char **argv) {
    }
    return 127;
 }
+*/
 
-void radamsa_init() {
+void radamsa_init(void) {
    int nobjs=0, nwords=0;
    hp = (byte *) &heap; /* builtin heap */
    state = IFALSE;
@@ -30787,7 +30791,7 @@ void radamsa_init() {
 }
 
 /* bvec → value library call test with preserved state */
-word library_call(word val) {
+static word library_call(word val) {
    word program_state = state;
    word res;
    state = IFALSE; 
@@ -30798,7 +30802,8 @@ word library_call(word val) {
    return res;
 }
 
-size_t list_length(word lispval) {
+/*
+static size_t list_length(word lispval) {
    size_t l = 0;
    while(lispval != INULL) {
       lispval = G(lispval, 2);
@@ -30806,8 +30811,9 @@ size_t list_length(word lispval) {
    }
    return l;
 }
+*/
 
-size_t copy_list(uint8_t *ptr, word lispval, size_t max) {
+static size_t copy_list(uint8_t *ptr, word lispval, size_t max) {
    size_t n = 0;
    while(pairp((word)lispval) && max-- && lispval != INULL) {
       *ptr++ = 255 & immval(G(lispval, 1)); // *ptr++ = car(list)
diff --git a/src/third_party/libradamsa/radamsa.h b/src/third_party/libradamsa/radamsa.h
index d54fa2ec..073599da 100644
--- a/src/third_party/libradamsa/radamsa.h
+++ b/src/third_party/libradamsa/radamsa.h
@@ -1,15 +1,13 @@
 #include <inttypes.h>
 #include <stddef.h>
 
-extern void radamsa_init();
+void radamsa_init(void);
 
-extern size_t radamsa(uint8_t *ptr, size_t len, 
-                      uint8_t *target, size_t max, 
+size_t radamsa(uint8_t *ptr, size_t len,
+                      uint8_t *target, size_t max,
                       unsigned int seed);
 
-extern size_t radamsa_inplace(uint8_t *ptr, 
-                              size_t len, 
-                              size_t max, 
+size_t radamsa_inplace(uint8_t *ptr,
+                              size_t len,
+                              size_t max,
                               unsigned int seed);
-
-
diff --git a/test/test-compcov.c b/test/test-compcov.c
index 89611bfb..f1743265 100644
--- a/test/test-compcov.c
+++ b/test/test-compcov.c
@@ -3,30 +3,47 @@
 #include <unistd.h>
 #include <string.h>
 
+char global_cmpval[] = "GLOBALVARIABLE";
+
 int main(int argc, char **argv) {
+
   char *input = argv[1], *buf, buffer[20];
+  char  cmpval[] = "LOCALVARIABLE";
+  char  shortval[4] = "abc";
 
   if (argc < 2) {
+
     ssize_t ret = read(0, buffer, sizeof(buffer) - 1);
     buffer[ret] = 0;
     input = buffer;
+
   }
-  
+
   if (strcmp(input, "LIBTOKENCAP") == 0)
     printf("your string was libtokencap\n");
   else if (strcmp(input, "BUGMENOT") == 0)
     printf("your string was bugmenot\n");
   else if (strcmp(input, "BUFFEROVERFLOW") == 0) {
+
     buf = malloc(16);
     strcpy(buf, "TEST");
     strcat(buf, input);
     printf("This will only crash with libdislocator: %s\n", buf);
     return 0;
-  } else if (*(unsigned int*)input == 0xabadcafe)
+
+  } else if (*(unsigned int *)input == 0xabadcafe)
+
     printf("GG you eat cmp tokens for breakfast!\n");
+  else if (memcmp(cmpval, input, 8) == 0)
+    printf("local var memcmp works!\n");
+  else if (memcmp(shortval, input, 4) == 0)
+    printf("short local var memcmp works!\n");
+  else if (memcmp(global_cmpval, input, sizeof(global_cmpval)) == 0)
+    printf("global var memcmp works!\n");
   else
     printf("I do not know your string\n");
 
   return 0;
 
 }
+
diff --git a/test/test-custom-mutator.c b/test/test-custom-mutator.c
index 83baafab..f868550c 100644
--- a/test/test-custom-mutator.c
+++ b/test/test-custom-mutator.c
@@ -1,5 +1,6 @@
 /**
- * Reference: https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/blob/master/4_libprotobuf_aflpp_custom_mutator/vuln.c
+ * Reference:
+ * https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/blob/master/4_libprotobuf_aflpp_custom_mutator/vuln.c
  */
 
 #include <stdio.h>
@@ -8,12 +9,12 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-int main(int argc, char *argv[])
-{
-    char str[100];
-    read(0, str, 100);
-    if( str[6] == 'A') {
-        abort();
-    }
-    return 0;
+int main(int argc, char *argv[]) {
+
+  char str[100];
+  read(0, str, 100);
+  if (str[6] == 'A') { abort(); }
+  return 0;
+
 }
+
diff --git a/test/test-unsigaction.c b/test/test-unsigaction.c
index 1a5e4b26..8c6c7f41 100644
--- a/test/test-unsigaction.c
+++ b/test/test-unsigaction.c
@@ -1,25 +1,31 @@
-#include <signal.h> /* sigemptyset(), sigaction(), kill(), SIGUSR1 */
-#include <stdlib.h> /* exit() */
-#include <unistd.h> /* getpid() */
-#include <errno.h> /* errno */
-#include <stdio.h> /* fprintf() */
-
-static void mysig_handler(int sig)
-{
-	exit(2);
+#include <signal.h>          /* sigemptyset(), sigaction(), kill(), SIGUSR1 */
+#include <stdlib.h>                                               /* exit() */
+#include <unistd.h>                                             /* getpid() */
+#include <errno.h>                                                 /* errno */
+#include <stdio.h>                                             /* fprintf() */
+
+static void mysig_handler(int sig) {
+
+  exit(2);
+
 }
 
-int main()
-{
-	/* setup sig handler */
-	struct sigaction sa;
-       	sa.sa_handler = mysig_handler;
-	sigemptyset(&sa.sa_mask);
-        sa.sa_flags = 0;	
-	if (sigaction(SIGCHLD, &sa, NULL)) {
-		fprintf(stderr, "could not set signal handler %d, aborted\n", errno);
-		exit(1);
-	}
-	kill(getpid(), SIGCHLD);
-	return 0;
+int main() {
+
+  /* setup sig handler */
+  struct sigaction sa;
+  sa.sa_handler = mysig_handler;
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = 0;
+  if (sigaction(SIGCHLD, &sa, NULL)) {
+
+    fprintf(stderr, "could not set signal handler %d, aborted\n", errno);
+    exit(1);
+
+  }
+
+  kill(getpid(), SIGCHLD);
+  return 0;
+
 }
+
diff --git a/test/test.sh b/test/test.sh
index 0666ca36..9a53825b 100755
--- a/test/test.sh
+++ b/test/test.sh
@@ -185,7 +185,7 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc
     esac
     rm -f in2/in*
     export AFL_QUIET=1
-    if type bash >/dev/null ; then {
+    if command -v bash >/dev/null ; then {
       AFL_PATH=`pwd`/.. ../afl-cmin.bash -m ${MEM_LIMIT} -i in -o in2 -- ./test-instr.plain >/dev/null
       CNT=`ls in2/* 2>/dev/null | wc -l`
       case "$CNT" in
@@ -353,7 +353,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
   }
   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 && {
-    grep -Eq " [3-9][0-9] location" test.out && {
+    grep -Eq " [ 12][0-9][0-9] location| [3-9][0-9] location" test.out && {
       $ECHO "$GREEN[+] llvm_mode laf-intel/compcov feature works correctly"
     } || {
       $ECHO "$RED[!] llvm_mode laf-intel/compcov feature failed"
@@ -581,6 +581,8 @@ test -e ../afl-gcc-fast -a -e ../afl-gcc-rt.o && {
   INCOMPLETE=1
 }
 
+test -z "$AFL_CC" && unset AFL_CC
+
 $ECHO "$BLUE[*] Testing: shared library extensions"
 cc $CFLAGS -o test-compcov test-compcov.c > /dev/null 2>&1
 test -e ../libtokencap.so && {
@@ -669,7 +671,7 @@ test -e ../afl-qemu-trace && {
   test -e test-instr -a -e test-compcov && {
     {
       mkdir -p in
-      echo 0 > in/in
+      echo 00000 > in/in
       $ECHO "$GREY[*] running afl-fuzz for qemu_mode, this will take approx 10 seconds"
       {
         ../afl-fuzz -m ${MEM_LIMIT} -V10 -Q -i in -o out -- ./test-instr >>errors 2>&1
@@ -734,6 +736,25 @@ test -e ../afl-qemu-trace && {
       } || {
        $ECHO "$YELLOW[-] not an intel or arm platform, cannot test qemu_mode compcov"
       }
+      
+      test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && {
+        $ECHO "$GREY[*] running afl-fuzz for qemu_mode cmplog, this will take approx 10 seconds"
+        {
+          ../afl-fuzz -m none -V10 -Q -c 0 -i in -o out -- ./test-compcov >>errors 2>&1
+        } >>errors 2>&1
+        test -n "$( ls out/queue/id:000001* 2>/dev/null )" && {
+          $ECHO "$GREEN[+] afl-fuzz is working correctly with qemu_mode cmplog"
+        } || {
+          echo CUT------------------------------------------------------------------CUT
+          cat errors
+          echo CUT------------------------------------------------------------------CUT
+          $ECHO "$RED[!] afl-fuzz is not working correctly with qemu_mode cmplog"
+          CODE=1
+        }
+        rm -f errors
+      } || {
+       $ECHO "$YELLOW[-] not an intel or arm platform, cannot test qemu_mode cmplog"
+      }
 
       test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc" -o "$SYS" = "aarch64" -o ! "${SYS%%arm*}" && {
         $ECHO "$GREY[*] running afl-fuzz for persistent qemu_mode, this will take approx 10 seconds"
diff --git a/test/unittests/unit_list.c b/test/unittests/unit_list.c
index 11d3227c..90700a11 100644
--- a/test/unittests/unit_list.c
+++ b/test/unittests/unit_list.c
@@ -27,6 +27,7 @@ extern void mock_assert(const int result, const char* const expression,
     (compile with `--wrap=exit`) */
 extern void exit(int status);
 extern void __real_exit(int status);
+void __wrap_exit(int status);
 void __wrap_exit(int status) {
     assert(0);
 }
@@ -34,6 +35,7 @@ void __wrap_exit(int status) {
 /* ignore all printfs */
 extern int printf(const char *format, ...);
 extern int __real_printf(const char *format, ...);
+int __wrap_printf(const char *format, ...);
 int __wrap_printf(const char *format, ...) {
     return 1;
 }
diff --git a/test/unittests/unit_maybe_alloc.c b/test/unittests/unit_maybe_alloc.c
index a856fa08..8cd8b11a 100644
--- a/test/unittests/unit_maybe_alloc.c
+++ b/test/unittests/unit_maybe_alloc.c
@@ -22,6 +22,7 @@ extern void mock_assert(const int result, const char* const expression,
     mock_assert((int)(expression), #expression, __FILE__, __LINE__);
 #include "alloc-inl.h"
 
+void __wrap_exit(int status);
 /* remap exit -> assert, then use cmocka's mock_assert
     (compile with `--wrap=exit`) */
 extern void exit(int status);
@@ -30,6 +31,7 @@ void __wrap_exit(int status) {
     assert(0);
 }
 
+int __wrap_printf(const char *format, ...);
 /* ignore all printfs */
 extern int printf(const char *format, ...);
 extern int __real_printf(const char *format, ...);
@@ -71,7 +73,7 @@ static void test_nonpow2_size(void **state) {
 
 }
 
-static void test_zero_size() {
+static void test_zero_size(void **state) {
 
     char *buf = NULL;
     size_t size = 0;
diff --git a/test/unittests/unit_preallocable.c b/test/unittests/unit_preallocable.c
index 8cd36165..8d619b78 100644
--- a/test/unittests/unit_preallocable.c
+++ b/test/unittests/unit_preallocable.c
@@ -27,6 +27,7 @@ extern void mock_assert(const int result, const char* const expression,
     (compile with `--wrap=exit`) */
 extern void exit(int status);
 extern void __real_exit(int status);
+void __wrap_exit(int status);
 void __wrap_exit(int status) {
     assert(0);
 }
@@ -34,6 +35,7 @@ void __wrap_exit(int status) {
 /* ignore all printfs */
 extern int printf(const char *format, ...);
 extern int __real_printf(const char *format, ...);
+int __wrap_printf(const char *format, ...);
 int __wrap_printf(const char *format, ...) {
     return 1;
 }
diff --git a/unicorn_mode/build_unicorn_support.sh b/unicorn_mode/build_unicorn_support.sh
index df2a7f6d..8297e13f 100644..100755
--- a/unicorn_mode/build_unicorn_support.sh
+++ b/unicorn_mode/build_unicorn_support.sh
@@ -33,6 +33,8 @@
 # You must make sure that Unicorn Engine is not already installed before
 # running this script. If it is, please uninstall it first.
 
+UNICORNAFL_VERSION='afl++2.64c'
+
 echo "================================================="
 echo "UnicornAFL build script"
 echo "================================================="
@@ -157,13 +159,15 @@ test -d unicornafl || {
 test -d unicornafl || { echo "[-] not checked out, please install git or check your internet connection." ; exit 1 ; }
 echo "[+] Got unicornafl."
 
+cd "unicornafl" || exit 1
+echo "[*] Checking out $UNICORNAFL_VERSION"
+git checkout "$UNICORNAFL_VERSION" || exit 1
+
 echo "[*] making sure config.h matches"
-cp "../config.h" "./unicornafl/" || exit 1
+cp "../../config.h" "." || exit 1
 
 echo "[*] Configuring Unicorn build..."
 
-cd "unicornafl" || exit 1
-
 echo "[+] Configuration complete."
 
 echo "[*] Attempting to build unicornafl (fingers crossed!)..."