about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Dockerfile33
-rw-r--r--GNUmakefile.llvm2
-rw-r--r--docs/Changelog.md6
-rw-r--r--frida_mode/GNUmakefile2
-rw-r--r--frida_mode/src/instrument/instrument_arm64.c2
-rw-r--r--frida_mode/src/instrument/instrument_x64.c3
-rw-r--r--frida_mode/src/instrument/instrument_x86.c2
-rw-r--r--frida_mode/src/module.c4
-rw-r--r--frida_mode/src/prefetch.c106
-rw-r--r--frida_mode/src/stalker.c2
-rw-r--r--frida_mode/test/dynamic/GNUmakefile76
-rw-r--r--frida_mode/test/dynamic/Makefile19
-rw-r--r--frida_mode/test/dynamic/testinstr.c98
-rw-r--r--frida_mode/test/dynamic/testinstrlib.c14
-rw-r--r--include/afl-fuzz.h15
-rw-r--r--include/debug.h2
-rw-r--r--instrumentation/SanitizerCoveragePCGUARD.so.cc24
-rw-r--r--nyx_mode/LIBNYX_VERSION2
-rw-r--r--nyx_mode/PACKER_VERSION2
m---------nyx_mode/QEMU-Nyx0
-rw-r--r--nyx_mode/QEMU_NYX_VERSION2
m---------nyx_mode/libnyx0
m---------nyx_mode/packer0
-rw-r--r--src/afl-fuzz-bitmap.c2
-rw-r--r--src/afl-fuzz-cmplog.c2
-rw-r--r--src/afl-fuzz-init.c2
-rw-r--r--src/afl-fuzz-mutators.c4
-rw-r--r--src/afl-fuzz-one.c397
-rw-r--r--src/afl-fuzz-run.c24
-rw-r--r--src/afl-fuzz-stats.c12
-rw-r--r--src/afl-sharedmem.c38
-rw-r--r--unicorn_mode/UNICORNAFL_VERSION2
32 files changed, 705 insertions, 194 deletions
diff --git a/Dockerfile b/Dockerfile
index 522e801a..bdfa1c56 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,9 +1,9 @@
 #
-# This Dockerfile for AFLplusplus uses Ubuntu 20.04 focal and
-# installs LLVM 11 from llvm.org for afl-clang-lto support :-)
+# This Dockerfile for AFLplusplus uses Ubuntu 22.04 jammy and
+# installs LLVM 14 for afl-clang-lto support :-)
 #
 
-FROM ubuntu:20.04 AS aflplusplus
+FROM ubuntu:22.04 AS aflplusplus
 LABEL "maintainer"="afl++ team <afl@aflplus.plus>"
 LABEL "about"="AFLplusplus docker image"
 
@@ -29,20 +29,21 @@ RUN apt-get update && \
     gnuplot-nox \
     && rm -rf /var/lib/apt/lists/*
 
-RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main" >> /etc/apt/sources.list && \
-    wget -qO - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
+# TODO: reactivate in timely manner
+#RUN echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" >> /etc/apt/sources.list && \
+#    wget -qO - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
 
-RUN echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu focal main" >> /etc/apt/sources.list && \
+RUN echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu jammy main" >> /etc/apt/sources.list && \
     apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 1E9377A2BA9EF27F
 
 RUN apt-get update && apt-get full-upgrade -y && \
     apt-get -y install --no-install-suggests --no-install-recommends \
-    gcc-10 g++-10 gcc-10-plugin-dev gdb lcov \
-    clang-12 clang-tools-12 libc++1-12 libc++-12-dev \
-    libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \
-    libclang-common-12-dev libclang-cpp12 libclang-cpp12-dev liblld-12 \
-    liblld-12-dev liblldb-12 liblldb-12-dev libllvm12 libomp-12-dev \
-    libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools
+    gcc-12 g++-12 gcc-12-plugin-dev gdb lcov \
+    clang-14 clang-tools-14 libc++1-14 libc++-14-dev \
+    libc++abi1-14 libc++abi-14-dev libclang1-14 libclang-14-dev \
+    libclang-common-14-dev libclang-cpp14 libclang-cpp14-dev liblld-14 \
+    liblld-14-dev liblldb-14 liblldb-14-dev libllvm14 libomp-14-dev \
+    libomp5-14 lld-14 lldb-14 llvm-14 llvm-14-dev llvm-14-runtime llvm-14-tools
 
 # arm64 doesn't have gcc-multilib, and it's only used for -m32 support on x86
 ARG TARGETPLATFORM
@@ -52,10 +53,10 @@ RUN [ "$TARGETPLATFORM" = "linux/amd64" ] && \
 
 RUN rm -rf /var/lib/apt/lists/*
 
-RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 0
-RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0
+RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 0
+RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 0
 
-ENV LLVM_CONFIG=llvm-config-12
+ENV LLVM_CONFIG=llvm-config-14
 ENV AFL_SKIP_CPUFREQ=1
 ENV AFL_TRY_AFFINITY=1
 ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1
@@ -66,7 +67,7 @@ RUN cd /afl-cov && make install && cd ..
 COPY . /AFLplusplus
 WORKDIR /AFLplusplus
 
-RUN export CC=gcc-10 && export CXX=g++-10 && make clean && \
+RUN export CC=gcc-12 && export CXX=g++-12 && make clean && \
     make distrib && make install && make clean
 
 RUN sh -c 'echo set encoding=utf-8 > /root/.vimrc'
diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm
index 685964b7..538ca4a2 100644
--- a/GNUmakefile.llvm
+++ b/GNUmakefile.llvm
@@ -407,7 +407,7 @@ ifeq "$(LLVM_LTO)" "1"
 	$(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@
 endif
 
-./SanitizerCoverageLTO.so: instrumentation/SanitizerCoverageLTO.so.cc
+./SanitizerCoverageLTO.so: instrumentation/SanitizerCoverageLTO.so.cc instrumentation/afl-llvm-common.o
 ifeq "$(LLVM_LTO)" "1"
 	$(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
 	$(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto.o
diff --git a/docs/Changelog.md b/docs/Changelog.md
index a841cca3..b6271a22 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -26,10 +26,16 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
     - "saved timeouts" was wrong information, timeouts are still thrown
       away by default even if they have new coverage (hangs are always
       kept), unless AFL_KEEP_TIMEOUTS are set
+    - AFL never implemented auto token inserts (but user token inserts,
+      user token overwrite and auto token overwrite), added now!
+    - Mopt fix to always select the correct algorithm
+    - fix effector map calculation (deterministic mode)
+    - fix custom mutator post_process functionality
     - document and auto-activate pizza mode on condition
   - afl-cc:
     - converted all passed to use the new llvm pass manager for llvm 11+
     - AFL++ PCGUARD mode is not available for 10.0.1 anymore (11+ only)
+    - trying to stay on top on all these #$&ยง!! changes in llvm 15 ...
   - frida_mode:
     - update to new frida release, handles now c++ throw/catch
   - unicorn_mode:
diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile
index 0b5f52cb..014dcca5 100644
--- a/frida_mode/GNUmakefile
+++ b/frida_mode/GNUmakefile
@@ -116,7 +116,7 @@ ifndef OS
  $(error "Operating system unsupported")
 endif
 
-GUM_DEVKIT_VERSION=15.1.15
+GUM_DEVKIT_VERSION=15.1.22
 GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz
 GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)"
 
diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c
index 2bc8f8aa..fab9eee2 100644
--- a/frida_mode/src/instrument/instrument_arm64.c
+++ b/frida_mode/src/instrument/instrument_arm64.c
@@ -157,11 +157,13 @@ static gboolean instrument_is_deterministic(const cs_insn *from_insn) {
 }
 
 static void instrument_coverage_switch(GumStalkerObserver *self,
+                                       gpointer            from_address,
                                        gpointer            start_address,
                                        const cs_insn *     from_insn,
                                        gpointer *          target) {
 
   UNUSED_PARAMETER(self);
+  UNUSED_PARAMETER(from_address);
   UNUSED_PARAMETER(start_address);
 
   gsize fixup_offset;
diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c
index f02c971e..a764b054 100644
--- a/frida_mode/src/instrument/instrument_x64.c
+++ b/frida_mode/src/instrument/instrument_x64.c
@@ -172,12 +172,13 @@ void instrument_coverage_optimize_init(void) {
 }
 
 static void instrument_coverage_switch(GumStalkerObserver *self,
+                                       gpointer            from_address,
                                        gpointer            start_address,
                                        const cs_insn *     from_insn,
                                        gpointer *          target) {
 
   UNUSED_PARAMETER(self);
-  UNUSED_PARAMETER(start_address);
+  UNUSED_PARAMETER(from_address);
 
   cs_x86 *   x86;
   cs_x86_op *op;
diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c
index 6a899248..1baa98ca 100644
--- a/frida_mode/src/instrument/instrument_x86.c
+++ b/frida_mode/src/instrument/instrument_x86.c
@@ -84,11 +84,13 @@ gboolean instrument_is_coverage_optimize_supported(void) {
 }
 
 static void instrument_coverage_switch(GumStalkerObserver *self,
+                                       gpointer            from_address,
                                        gpointer            start_address,
                                        const cs_insn *     from_insn,
                                        gpointer *          target) {
 
   UNUSED_PARAMETER(self);
+  UNUSED_PARAMETER(from_address);
   UNUSED_PARAMETER(start_address);
 
   cs_x86 *   x86;
diff --git a/frida_mode/src/module.c b/frida_mode/src/module.c
index 65b394cd..60e69fec 100644
--- a/frida_mode/src/module.c
+++ b/frida_mode/src/module.c
@@ -42,7 +42,7 @@ gboolean found_range(const GumRangeDetails *details, gpointer user_data) {
 
 }
 
-#if defined(__linux__)
+#if defined(__linux__) && !defined(__ANDROID__)
 static int on_dlclose(void *handle) {
 
   GArray *         ranges = NULL;
@@ -95,7 +95,7 @@ void module_init(void) {
 
   FOKF(cBLU "Module" cRST " - " cYEL " [%c]", handle_dlclose ? 'X' : ' ');
 
-#if defined(__linux__)
+#if defined(__linux__) && !defined(__ANDROID__)
   if (!handle_dlclose) { return; }
 
   page_size = gum_query_page_size();
diff --git a/frida_mode/src/prefetch.c b/frida_mode/src/prefetch.c
index fa0288cc..59bfecc2 100644
--- a/frida_mode/src/prefetch.c
+++ b/frida_mode/src/prefetch.c
@@ -32,6 +32,8 @@ gboolean prefetch_backpatch = TRUE;
 static prefetch_data_t *prefetch_data = NULL;
 static int              prefetch_shm_id = -1;
 
+static GHashTable *cant_prefetch = NULL;
+
 static void gum_afl_stalker_backpatcher_notify(GumStalkerObserver *self,
                                                const GumBackpatch *backpatch,
                                                gsize               size) {
@@ -40,6 +42,18 @@ static void gum_afl_stalker_backpatcher_notify(GumStalkerObserver *self,
   if (!entry_run) { return; }
   gsize remaining =
       sizeof(prefetch_data->backpatch_data) - prefetch_data->backpatch_size;
+
+  gpointer from = gum_stalker_backpatch_get_from(backpatch);
+  gpointer to = gum_stalker_backpatch_get_to(backpatch);
+
+  /* Stop reporting patches which can't be prefetched */
+  if (g_hash_table_contains(cant_prefetch, GSIZE_TO_POINTER(from)) ||
+      g_hash_table_contains(cant_prefetch, GSIZE_TO_POINTER(to))) {
+
+    return;
+
+  }
+
   if (sizeof(gsize) + size > remaining) { return; }
 
   gsize *dst_backpatch_size =
@@ -68,6 +82,9 @@ void prefetch_write(void *addr) {
   /* Bail if we aren't initialized */
   if (prefetch_data == NULL) return;
 
+  /* Stop reporting blocks which can't be prefetched */
+  if (g_hash_table_contains(cant_prefetch, GSIZE_TO_POINTER(addr))) { return; }
+
   /*
    * Our shared memory IPC is large enough for about 1000 entries, we can fine
    * tune this if we need to. But if we have more new blocks that this in a
@@ -84,6 +101,38 @@ void prefetch_write(void *addr) {
 
 }
 
+typedef struct {
+
+  GumAddress address;
+  gboolean   executable;
+
+} check_executable_t;
+
+static gboolean prefetch_find_executable(const GumRangeDetails *details,
+                                         gpointer               user_data) {
+
+  check_executable_t *ctx = (check_executable_t *)user_data;
+  if (GUM_MEMORY_RANGE_INCLUDES(details->range, ctx->address)) {
+
+    ctx->executable = TRUE;
+    return FALSE;
+
+  }
+
+  return TRUE;
+
+}
+
+static gboolean prefetch_is_executable(void *address) {
+
+  check_executable_t ctx = {.address = GUM_ADDRESS(address),
+                            .executable = FALSE};
+  gum_process_enumerate_ranges(GUM_PAGE_EXECUTE, prefetch_find_executable,
+                               &ctx);
+  return ctx.executable;
+
+}
+
 static void prefetch_read_blocks(void) {
 
   GumStalker *stalker = stalker_get();
@@ -92,7 +141,24 @@ static void prefetch_read_blocks(void) {
   for (size_t i = 0; i < prefetch_data->count; i++) {
 
     void *addr = prefetch_data->entry[i];
-    gum_stalker_prefetch(stalker, addr, 1);
+
+    if (prefetch_is_executable(addr)) {
+
+      gum_stalker_prefetch(stalker, addr, 1);
+
+    } else {
+
+      /*
+       * If our child process creates a new executable mapping, e.g. by
+       * dynamically loading a new DSO, then this won't appear in our parent
+       * process' memory map and hence we can't prefetch it. Add it to a
+       * hashtable which the child will inherit on the next fork to prevent the
+       * child from keep reporting it and exhausting the shared memory buffers
+       * used to pass new blocks from the child back to the parent.
+       */
+      g_hash_table_add(cant_prefetch, GSIZE_TO_POINTER(addr));
+
+    }
 
   }
 
@@ -125,7 +191,36 @@ static void prefetch_read_patches(void) {
     }
 
     backpatch = (GumBackpatch *)&prefetch_data->backpatch_data[offset];
-    gum_stalker_prefetch_backpatch(stalker, backpatch);
+
+    gpointer from = gum_stalker_backpatch_get_from(backpatch);
+    gpointer to = gum_stalker_backpatch_get_to(backpatch);
+
+    /*
+     * If our child process creates a new executable mapping, e.g. by
+     * dynamically loading a new DSO, then this won't appear in our parent
+     * process' memory map and hence we can't prefetch it. Add it to a
+     * hashtable which the child will inherit on the next fork to prevent the
+     * child from keep reporting it and exhausting the shared memory buffers
+     * used to pass new blocks from the child back to the parent.
+     */
+    if (!prefetch_is_executable(from)) {
+
+      g_hash_table_add(cant_prefetch, GSIZE_TO_POINTER(from));
+
+    }
+
+    if (!prefetch_is_executable(to)) {
+
+      g_hash_table_add(cant_prefetch, GSIZE_TO_POINTER(to));
+
+    }
+
+    if (prefetch_is_executable(from) && prefetch_is_executable(to)) {
+
+      gum_stalker_prefetch_backpatch(stalker, backpatch);
+
+    }
+
     offset += size;
 
   }
@@ -215,6 +310,13 @@ void prefetch_init(void) {
 
   prefetch_hook_fork();
 
+  cant_prefetch = g_hash_table_new(g_direct_hash, g_direct_equal);
+  if (cant_prefetch == NULL) {
+
+    FFATAL("Failed to g_hash_table_new, errno: %d", errno);
+
+  }
+
   if (!prefetch_backpatch) { return; }
 
   GumStalkerObserver *         observer = stalker_get_observer();
diff --git a/frida_mode/src/stalker.c b/frida_mode/src/stalker.c
index 80e4e707..ddc17b81 100644
--- a/frida_mode/src/stalker.c
+++ b/frida_mode/src/stalker.c
@@ -131,6 +131,8 @@ void stalker_init(void) {
 
   }
 
+  gum_stalker_activate_experimental_unwind_support();
+
 #if defined(__x86_64__) || defined(__i386__)
   stalker = g_object_new(GUM_TYPE_STALKER, "ic-entries", stalker_ic_entries,
                          "adjacent-blocks", stalker_adjacent_blocks, NULL);
diff --git a/frida_mode/test/dynamic/GNUmakefile b/frida_mode/test/dynamic/GNUmakefile
new file mode 100644
index 00000000..f43416f7
--- /dev/null
+++ b/frida_mode/test/dynamic/GNUmakefile
@@ -0,0 +1,76 @@
+PWD:=$(shell pwd)/
+ROOT:=$(PWD)../../../
+BUILD_DIR:=$(PWD)build/
+TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/
+TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in
+AFLPP_DRIVER_DUMMY_INPUT:=$(BUILD_DIR)dummy.dat
+
+TESTINSTBIN:=$(BUILD_DIR)testinstr
+TESTINSTSRC:=$(PWD)testinstr.c
+
+TESTINSTLIB:=$(BUILD_DIR)testinstrlib.so
+TESTINSTLIBSRC:=$(PWD)testinstrlib.c
+
+QEMU_OUT:=$(BUILD_DIR)qemu-out
+FRIDA_OUT:=$(BUILD_DIR)frida-out
+
+AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so
+
+ADDR_BIN:=$(ROOT)frida_mode/build/addr
+GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh
+
+AFL_FRIDA_BASE_ADDR:=$(shell $(ADDR_BIN))
+AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TESTINSTBIN) testinstr $(AFL_FRIDA_BASE_ADDR))
+
+CFLAGS+=-D_GNU_SOURCE=1
+LDFLAGS+=-ldl
+
+.PHONY: all clean qemu frida
+
+all: $(TESTINSTBIN) $(TESTINSTLIB)
+	make -C $(ROOT)frida_mode/
+
+$(BUILD_DIR):
+	mkdir -p $@
+
+$(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR)
+	dd if=/dev/zero bs=1048576 count=1 of=$@
+
+$(TESTINSTR_DATA_DIR): | $(BUILD_DIR)
+	mkdir -p $@
+
+$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR)
+	echo -n "000" > $@
+
+$(TESTINSTLIB): $(TESTINSTLIBSRC) | $(BUILD_DIR)
+	$(CC) \
+		$(CFLAGS) \
+		-shared \
+		-o $@ \
+		$(LDFLAGS) \
+		$<
+
+$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR)
+	$(CC) \
+		$(CFLAGS) \
+		-o $@ \
+		$< \
+		$(LDFLAGS) \
+		-Wl,-rpath,'$$ORIGIN'
+
+clean:
+	rm -rf $(BUILD_DIR)
+
+
+frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) $(AFLPP_DRIVER_DUMMY_INPUT)
+	AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_FRIDA_DRIVER_HOOK_OBJ) \
+	AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \
+	$(ROOT)afl-fuzz \
+		-D \
+		-O \
+		-i $(TESTINSTR_DATA_DIR) \
+		-o $(FRIDA_OUT) \
+		-- \
+			$(TESTINSTBIN) $(AFLPP_DRIVER_DUMMY_INPUT)
+
diff --git a/frida_mode/test/dynamic/Makefile b/frida_mode/test/dynamic/Makefile
new file mode 100644
index 00000000..f843af19
--- /dev/null
+++ b/frida_mode/test/dynamic/Makefile
@@ -0,0 +1,19 @@
+all:
+	@echo trying to use GNU make...
+	@gmake all || echo please install GNUmake
+
+32:
+	@echo trying to use GNU make...
+	@gmake 32 || echo please install GNUmake
+
+clean:
+	@gmake clean
+
+qemu:
+	@gmake qemu
+
+frida:
+	@gmake frida
+
+debug:
+	@gmake debug
diff --git a/frida_mode/test/dynamic/testinstr.c b/frida_mode/test/dynamic/testinstr.c
new file mode 100644
index 00000000..ad26d060
--- /dev/null
+++ b/frida_mode/test/dynamic/testinstr.c
@@ -0,0 +1,98 @@
+/*
+   american fuzzy lop++ - a trivial program to test the build
+   --------------------------------------------------------
+   Originally written by Michal Zalewski
+   Copyright 2014 Google Inc. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at:
+     http://www.apache.org/licenses/LICENSE-2.0
+ */
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+typedef void (*fntestinstrlib)(char *buf, int len);
+
+void testinstr(char *buf, int len) {
+  void *lib = dlopen("testinstrlib.so", RTLD_NOW);
+  if (lib == NULL) {
+    puts("Library not found");
+    abort();
+  }
+
+  fntestinstrlib fn = (fntestinstrlib)(dlsym(lib, "testinstrlib"));
+  if (fn == NULL) {
+    puts("Function not found");
+    abort();
+  }
+
+  fn(buf, len);
+}
+
+int main(int argc, char **argv) {
+  char * file;
+  int    fd = -1;
+  off_t  len;
+  char * buf = NULL;
+  size_t n_read;
+  int    result = -1;
+
+  if (argc != 2) { return 1; }
+
+  do {
+    file = argv[1];
+    printf("file: %s\n", file);
+
+    dprintf(STDERR_FILENO, "Running: %s\n", file);
+
+    fd = open(file, O_RDONLY);
+    if (fd < 0) {
+      perror("open");
+      break;
+    }
+
+    len = lseek(fd, 0, SEEK_END);
+    if (len < 0) {
+      perror("lseek (SEEK_END)");
+      break;
+    }
+
+    if (lseek(fd, 0, SEEK_SET) != 0) {
+      perror("lseek (SEEK_SET)");
+      break;
+    }
+
+    printf("len: %ld\n", len);
+
+    buf = malloc(len);
+    if (buf == NULL) {
+      perror("malloc");
+      break;
+    }
+
+    n_read = read(fd, buf, len);
+    if (n_read != len) {
+      perror("read");
+      break;
+    }
+
+    dprintf(STDERR_FILENO, "Running:    %s: (%zd bytes)\n", file, n_read);
+
+    testinstr(buf, len);
+    dprintf(STDERR_FILENO, "Done:    %s: (%zd bytes)\n", file, n_read);
+
+    result = 0;
+
+  } while (false);
+
+  if (buf != NULL) { free(buf); }
+
+  if (fd != -1) { close(fd); }
+
+  return result;
+}
diff --git a/frida_mode/test/dynamic/testinstrlib.c b/frida_mode/test/dynamic/testinstrlib.c
new file mode 100644
index 00000000..987cbf91
--- /dev/null
+++ b/frida_mode/test/dynamic/testinstrlib.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+void testinstrlib(char *buf, int len) {
+  if (len < 1) return;
+  buf[len] = 0;
+
+  // we support three input cases
+  if (buf[0] == '0')
+    printf("Looks like a zero to me!\n");
+  else if (buf[0] == '1')
+    printf("Pretty sure that is a one!\n");
+  else
+    printf("Neither one or zero? How quaint!\n");
+}
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 8bb61e22..9992e841 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -230,12 +230,13 @@ enum {
   /* 12 */ STAGE_EXTRAS_UO,
   /* 13 */ STAGE_EXTRAS_UI,
   /* 14 */ STAGE_EXTRAS_AO,
-  /* 15 */ STAGE_HAVOC,
-  /* 16 */ STAGE_SPLICE,
-  /* 17 */ STAGE_PYTHON,
-  /* 18 */ STAGE_CUSTOM_MUTATOR,
-  /* 19 */ STAGE_COLORIZATION,
-  /* 20 */ STAGE_ITS,
+  /* 15 */ STAGE_EXTRAS_AI,
+  /* 16 */ STAGE_HAVOC,
+  /* 17 */ STAGE_SPLICE,
+  /* 18 */ STAGE_PYTHON,
+  /* 19 */ STAGE_CUSTOM_MUTATOR,
+  /* 20 */ STAGE_COLORIZATION,
+  /* 21 */ STAGE_ITS,
 
   STAGE_NUM_MAX
 
@@ -1098,7 +1099,7 @@ int  statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen);
 /* Run */
 
 void sync_fuzzers(afl_state_t *);
-u32  write_to_testcase(afl_state_t *, void *, u32, u32);
+u32  write_to_testcase(afl_state_t *, void **, u32, u32);
 u8   calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8);
 u8   trim_case(afl_state_t *, struct queue_entry *, u8 *);
 u8   common_fuzz_stuff(afl_state_t *, u8 *, u32);
diff --git a/include/debug.h b/include/debug.h
index e2ee16a8..c2f20f0f 100644
--- a/include/debug.h
+++ b/include/debug.h
@@ -388,6 +388,8 @@ static inline const char *colorfilter(const char *x) {
                                                                               \
     } while (1);                                                              \
                                                                               \
+                                                                              \
+                                                                              \
   } while (0)
 
 #define ck_read(fd, buf, len, fn)                              \
diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc
index f80b1a1e..408353b3 100644
--- a/instrumentation/SanitizerCoveragePCGUARD.so.cc
+++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc
@@ -313,13 +313,25 @@ PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &               M,
 std::pair<Value *, Value *> ModuleSanitizerCoverageAFL::CreateSecStartEnd(
     Module &M, const char *Section, Type *Ty) {
 
-  GlobalVariable *SecStart = new GlobalVariable(
-      M, Ty->getPointerElementType(), false,
-      GlobalVariable::ExternalWeakLinkage, nullptr, getSectionStart(Section));
+  GlobalVariable *SecStart =
+      new GlobalVariable(M,
+#if LLVM_VERSION_MAJOR >= 15
+                         Ty,
+#else
+                         Ty->getPointerElementType(),
+#endif
+                         false, GlobalVariable::ExternalWeakLinkage, nullptr,
+                         getSectionStart(Section));
   SecStart->setVisibility(GlobalValue::HiddenVisibility);
-  GlobalVariable *SecEnd = new GlobalVariable(
-      M, Ty->getPointerElementType(), false,
-      GlobalVariable::ExternalWeakLinkage, nullptr, getSectionEnd(Section));
+  GlobalVariable *SecEnd =
+      new GlobalVariable(M,
+#if LLVM_VERSION_MAJOR >= 15
+                         Ty,
+#else
+                         Ty->getPointerElementType(),
+#endif
+                         false, GlobalVariable::ExternalWeakLinkage, nullptr,
+                         getSectionEnd(Section));
   SecEnd->setVisibility(GlobalValue::HiddenVisibility);
   IRBuilder<> IRB(M.getContext());
   if (!TargetTriple.isOSBinFormatCOFF())
diff --git a/nyx_mode/LIBNYX_VERSION b/nyx_mode/LIBNYX_VERSION
index 65e119c9..00165a63 100644
--- a/nyx_mode/LIBNYX_VERSION
+++ b/nyx_mode/LIBNYX_VERSION
@@ -1 +1 @@
-8a77c71
+acaf7f6
diff --git a/nyx_mode/PACKER_VERSION b/nyx_mode/PACKER_VERSION
index d67dee20..a8ebe13a 100644
--- a/nyx_mode/PACKER_VERSION
+++ b/nyx_mode/PACKER_VERSION
@@ -1 +1 @@
-5d143ee
+86b159b
diff --git a/nyx_mode/QEMU-Nyx b/nyx_mode/QEMU-Nyx
-Subproject c08e4ac94244a9739b4484b3010abc06b372923
+Subproject 5c8cf793ec615b0df5fa722878c8f6906ad7936
diff --git a/nyx_mode/QEMU_NYX_VERSION b/nyx_mode/QEMU_NYX_VERSION
index 2d9ee5e3..f5888136 100644
--- a/nyx_mode/QEMU_NYX_VERSION
+++ b/nyx_mode/QEMU_NYX_VERSION
@@ -1 +1 @@
-c08e4ac942
+5c8cf793ec
diff --git a/nyx_mode/libnyx b/nyx_mode/libnyx
-Subproject 8a77c71dc8a8c0b73abd8fb9c22e30d565184ef
+Subproject acaf7f6346eeb5f1e2cf043543316909fca4365
diff --git a/nyx_mode/packer b/nyx_mode/packer
-Subproject 5d143eee4e4dcd12a1fc5d6786dd8da25cbb995
+Subproject 86b159bafc0b2ba8feeaa8761a45b6201d34084
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index 7c2b35d6..26e70d81 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -648,7 +648,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
       if (afl->fsrv.exec_tmout < afl->hang_tmout) {
 
         u8 new_fault;
-        len = write_to_testcase(afl, mem, len, 0);
+        len = write_to_testcase(afl, &mem, len, 0);
         new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout);
         classify_counts(&afl->fsrv);
 
diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c
index 7d94085d..258d9ea7 100644
--- a/src/afl-fuzz-cmplog.c
+++ b/src/afl-fuzz-cmplog.c
@@ -49,7 +49,7 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
 
   u8 fault;
 
-  write_to_testcase(afl, out_buf, len, 0);
+  write_to_testcase(afl, (void **)&out_buf, len, 0);
 
   fault = fuzz_run_target(afl, &afl->cmplog_fsrv, afl->fsrv.exec_tmout);
 
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 05a654c8..6a653a00 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -617,7 +617,7 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
 
         }
 
-        u32 len = write_to_testcase(afl, mem, st.st_size, 1);
+        u32 len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
         fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
         afl->syncing_party = foreign_name;
         afl->queued_imported += save_if_interesting(afl, mem, len, fault);
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index e78e2dc4..9407adfb 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -428,7 +428,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
 
     if (likely(retlen)) {
 
-      retlen = write_to_testcase(afl, retbuf, retlen, 0);
+      retlen = write_to_testcase(afl, (void **)&retbuf, retlen, 0);
 
       fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
       ++afl->trim_execs;
@@ -460,6 +460,8 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
       }
 
       out_len = retlen;
+      // TODO are we sure that retbuf fits into out_buf if retbuf can actually
+      // increase in size?
       memcpy(out_buf, retbuf, retlen);
 
       /* Tell the custom mutator that the trimming was successful */
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index b28ee80a..19f41ebe 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -373,7 +373,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
   u32 j;
   u32 i;
   u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0;
-  u64 havoc_queued = 0, orig_hit_cnt, new_hit_cnt = 0, prev_cksum;
+  u64 havoc_queued = 0, orig_hit_cnt, new_hit_cnt = 0, prev_cksum, _prev_cksum;
   u32 splice_cycle = 0, perf_score = 100, orig_perf, eff_cnt = 1;
 
   u8 ret_val = 1, doing_det = 0;
@@ -630,7 +630,14 @@ u8 fuzz_one_original(afl_state_t *afl) {
 
   orig_hit_cnt = afl->queued_items + afl->saved_crashes;
 
-  prev_cksum = afl->queue_cur->exec_cksum;
+  /* Get a clean cksum. */
+
+  if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+  prev_cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+  _prev_cksum = prev_cksum;
+
+  /* Now flip bits. */
 
   for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
 
@@ -716,7 +723,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
       /* Continue collecting string, but only if the bit flip actually made
          any difference - we don't want no-op tokens. */
 
-      if (cksum != afl->queue_cur->exec_cksum) {
+      if (cksum != _prev_cksum) {
 
         if (a_len < MAX_AUTO_EXTRA) {
 
@@ -839,6 +846,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
   afl->stage_max = len;
 
   orig_hit_cnt = new_hit_cnt;
+  prev_cksum = _prev_cksum;
 
   for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
 
@@ -871,11 +879,11 @@ u8 fuzz_one_original(afl_state_t *afl) {
 
       } else {
 
-        cksum = ~afl->queue_cur->exec_cksum;
+        cksum = ~prev_cksum;
 
       }
 
-      if (cksum != afl->queue_cur->exec_cksum) {
+      if (cksum != prev_cksum) {
 
         eff_map[EFF_APOS(afl->stage_cur)] = 1;
         ++eff_cnt;
@@ -1779,6 +1787,62 @@ skip_user_extras:
   afl->stage_finds[STAGE_EXTRAS_AO] += new_hit_cnt - orig_hit_cnt;
   afl->stage_cycles[STAGE_EXTRAS_AO] += afl->stage_max;
 
+  /* Insertion of auto extras. */
+
+  afl->stage_name = "auto extras (insert)";
+  afl->stage_short = "ext_AI";
+  afl->stage_cur = 0;
+  afl->stage_max = afl->a_extras_cnt * (len + 1);
+
+  orig_hit_cnt = new_hit_cnt;
+
+  ex_tmp = afl_realloc(AFL_BUF_PARAM(ex), len + MAX_DICT_FILE);
+  if (unlikely(!ex_tmp)) { PFATAL("alloc"); }
+
+  for (i = 0; i <= (u32)len; ++i) {
+
+    afl->stage_cur_byte = i;
+
+    for (j = 0; j < afl->a_extras_cnt; ++j) {
+
+      if (len + afl->a_extras[j].len > MAX_FILE) {
+
+        --afl->stage_max;
+        continue;
+
+      }
+
+      /* Insert token */
+      memcpy(ex_tmp + i, afl->a_extras[j].data, afl->a_extras[j].len);
+
+      /* Copy tail */
+      memcpy(ex_tmp + i + afl->a_extras[j].len, out_buf + i, len - i);
+
+#ifdef INTROSPECTION
+      snprintf(afl->mutation, sizeof(afl->mutation),
+               "%s AUTO_EXTRAS_insert-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+
+      if (common_fuzz_stuff(afl, ex_tmp, len + afl->a_extras[j].len)) {
+
+        goto abandon_entry;
+
+      }
+
+      ++afl->stage_cur;
+
+    }
+
+    /* Copy head */
+    ex_tmp[i] = out_buf[i];
+
+  }
+
+  new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+  afl->stage_finds[STAGE_EXTRAS_AI] += new_hit_cnt - orig_hit_cnt;
+  afl->stage_cycles[STAGE_EXTRAS_AI] += afl->stage_max;
+
 skip_extras:
 
   /* If we made this to here without jumping to havoc_stage or abandon_entry,
@@ -1905,11 +1969,7 @@ custom_mutator_stage:
 
           }
 
-          /* `(afl->)out_buf` may have been changed by the call to custom_fuzz
-           */
-          /* TODO: Only do this when `mutated_buf` == `out_buf`? Branch vs
-           * Memcpy.
-           */
+          /* out_buf may have been changed by the call to custom_fuzz */
           memcpy(out_buf, in_buf, len);
 
         }
@@ -2994,7 +3054,8 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
   u32 i;
   u32 j;
   u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0;
-  u64 havoc_queued = 0, orig_hit_cnt, new_hit_cnt = 0, cur_ms_lv, prev_cksum;
+  u64 havoc_queued = 0, orig_hit_cnt, new_hit_cnt = 0, cur_ms_lv, prev_cksum,
+      _prev_cksum;
   u32 splice_cycle = 0, perf_score = 100, orig_perf, eff_cnt = 1;
 
   u8 ret_val = 1, doing_det = 0;
@@ -3238,7 +3299,14 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
 
   orig_hit_cnt = afl->queued_items + afl->saved_crashes;
 
-  prev_cksum = afl->queue_cur->exec_cksum;
+  /* Get a clean cksum. */
+
+  if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
+
+  prev_cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+  _prev_cksum = prev_cksum;
+
+  /* Now flip bits. */
 
   for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
 
@@ -3323,7 +3391,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
       /* Continue collecting string, but only if the bit flip actually made
          any difference - we don't want no-op tokens. */
 
-      if (cksum != afl->queue_cur->exec_cksum) {
+      if (cksum != _prev_cksum) {
 
         if (a_len < MAX_AUTO_EXTRA) {
 
@@ -3444,6 +3512,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
   afl->stage_max = len;
 
   orig_hit_cnt = new_hit_cnt;
+  prev_cksum = _prev_cksum;
 
   for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
 
@@ -3475,11 +3544,11 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
 
       } else {
 
-        cksum = ~afl->queue_cur->exec_cksum;
+        cksum = ~prev_cksum;
 
       }
 
-      if (cksum != afl->queue_cur->exec_cksum) {
+      if (cksum != prev_cksum) {
 
         eff_map[EFF_APOS(afl->stage_cur)] = 1;
         ++eff_cnt;
@@ -4367,6 +4436,62 @@ skip_user_extras:
   afl->stage_finds[STAGE_EXTRAS_AO] += new_hit_cnt - orig_hit_cnt;
   afl->stage_cycles[STAGE_EXTRAS_AO] += afl->stage_max;
 
+  /* Insertion of auto extras. */
+
+  afl->stage_name = "auto extras (insert)";
+  afl->stage_short = "ext_AI";
+  afl->stage_cur = 0;
+  afl->stage_max = afl->a_extras_cnt * (len + 1);
+
+  orig_hit_cnt = new_hit_cnt;
+
+  ex_tmp = afl_realloc(AFL_BUF_PARAM(ex), len + MAX_DICT_FILE);
+  if (unlikely(!ex_tmp)) { PFATAL("alloc"); }
+
+  for (i = 0; i <= (u32)len; ++i) {
+
+    afl->stage_cur_byte = i;
+
+    for (j = 0; j < afl->a_extras_cnt; ++j) {
+
+      if (len + afl->a_extras[j].len > MAX_FILE) {
+
+        --afl->stage_max;
+        continue;
+
+      }
+
+      /* Insert token */
+      memcpy(ex_tmp + i, afl->a_extras[j].data, afl->a_extras[j].len);
+
+      /* Copy tail */
+      memcpy(ex_tmp + i + afl->a_extras[j].len, out_buf + i, len - i);
+
+#ifdef INTROSPECTION
+      snprintf(afl->mutation, sizeof(afl->mutation),
+               "%s MOPT_AUTO_EXTRAS_insert-%u-%u", afl->queue_cur->fname, i, j);
+#endif
+
+      if (common_fuzz_stuff(afl, ex_tmp, len + afl->a_extras[j].len)) {
+
+        goto abandon_entry;
+
+      }
+
+      ++afl->stage_cur;
+
+    }
+
+    /* Copy head */
+    ex_tmp[i] = out_buf[i];
+
+  }                                                  /* for i = 0; i <= len */
+
+  new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+  afl->stage_finds[STAGE_EXTRAS_AI] += new_hit_cnt - orig_hit_cnt;
+  afl->stage_cycles[STAGE_EXTRAS_AI] += afl->stage_max;
+
 skip_extras:
 
   /* If we made this to here without jumping to havoc_stage or abandon_entry,
@@ -4464,14 +4589,14 @@ pacemaker_fuzzing:
 
       havoc_queued = afl->queued_items;
 
-      u32 r_max;
+      u32 r_max, r;
 
-      r_max = 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0);
+      r_max = 16 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0);
 
       if (unlikely(afl->expand_havoc && afl->ready_for_splicing_count > 1)) {
 
         /* add expensive havoc cases here, they are activated after a full
-           cycle without finds happened */
+           cycle without any finds happened */
 
         ++r_max;
 
@@ -4497,7 +4622,7 @@ pacemaker_fuzzing:
 
         for (i = 0; i < use_stacking; ++i) {
 
-          switch (select_algorithm(afl, r_max)) {
+          switch (r = (select_algorithm(afl, r_max))) {
 
             case 0:
               /* Flip a single bit somewhere. Spooky! */
@@ -4914,192 +5039,196 @@ pacemaker_fuzzing:
 
             }                                                    /* case 15 */
 
+            default: {
+
               /* Values 16 and 17 can be selected only if there are any extras
                  present in the dictionaries. */
 
-            case 16: {
+              r -= 16;
+
+              if (r == 0 && (afl->extras_cnt || afl->a_extras_cnt)) {
 
-              /* Overwrite bytes with an extra. */
+                /* Overwrite bytes with an extra. */
 
-              if (!afl->extras_cnt ||
-                  (afl->a_extras_cnt && rand_below(afl, 2))) {
+                if (!afl->extras_cnt ||
+                    (afl->a_extras_cnt && rand_below(afl, 2))) {
 
-                /* No user-specified extras or odds in our favor. Let's use an
-                  auto-detected one. */
+                  /* No user-specified extras or odds in our favor. Let's use an
+                    auto-detected one. */
 
-                u32 use_extra = rand_below(afl, afl->a_extras_cnt);
-                u32 extra_len = afl->a_extras[use_extra].len;
+                  u32 use_extra = rand_below(afl, afl->a_extras_cnt);
+                  u32 extra_len = afl->a_extras[use_extra].len;
 
-                if (extra_len > (u32)temp_len) break;
+                  if (extra_len > (u32)temp_len) break;
 
-                u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
+                  u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
 #ifdef INTROSPECTION
-                snprintf(afl->m_tmp, sizeof(afl->m_tmp),
-                         " AUTO_EXTRA_OVERWRITE-%u-%u", insert_at, extra_len);
-                strcat(afl->mutation, afl->m_tmp);
+                  snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+                           " AUTO_EXTRA_OVERWRITE-%u-%u", insert_at, extra_len);
+                  strcat(afl->mutation, afl->m_tmp);
 #endif
-                memcpy(out_buf + insert_at, afl->a_extras[use_extra].data,
-                       extra_len);
+                  memcpy(out_buf + insert_at, afl->a_extras[use_extra].data,
+                         extra_len);
 
-              } else {
+                } else {
 
-                /* No auto extras or odds in our favor. Use the dictionary. */
+                  /* No auto extras or odds in our favor. Use the dictionary. */
 
-                u32 use_extra = rand_below(afl, afl->extras_cnt);
-                u32 extra_len = afl->extras[use_extra].len;
+                  u32 use_extra = rand_below(afl, afl->extras_cnt);
+                  u32 extra_len = afl->extras[use_extra].len;
 
-                if (extra_len > (u32)temp_len) break;
+                  if (extra_len > (u32)temp_len) break;
 
-                u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
+                  u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
 #ifdef INTROSPECTION
-                snprintf(afl->m_tmp, sizeof(afl->m_tmp),
-                         " EXTRA_OVERWRITE-%u-%u", insert_at, extra_len);
-                strcat(afl->mutation, afl->m_tmp);
+                  snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+                           " EXTRA_OVERWRITE-%u-%u", insert_at, extra_len);
+                  strcat(afl->mutation, afl->m_tmp);
 #endif
-                memcpy(out_buf + insert_at, afl->extras[use_extra].data,
-                       extra_len);
+                  memcpy(out_buf + insert_at, afl->extras[use_extra].data,
+                         extra_len);
 
-              }
+                }
 
-              MOpt_globals.cycles_v2[STAGE_OverWriteExtra]++;
+                MOpt_globals.cycles_v2[STAGE_OverWriteExtra]++;
 
-              break;
+                break;
 
-            }
+              }
 
               /* Insert an extra. */
 
-            case 17: {
+              else if (r == 1 && (afl->extras_cnt || afl->a_extras_cnt)) {
 
-              u32 use_extra, extra_len,
-                  insert_at = rand_below(afl, temp_len + 1);
-              u8 *ptr;
+                u32 use_extra, extra_len,
+                    insert_at = rand_below(afl, temp_len + 1);
+                u8 *ptr;
 
-              /* Insert an extra. Do the same dice-rolling stuff as for the
-                previous case. */
+                /* Insert an extra. Do the same dice-rolling stuff as for the
+                  previous case. */
 
-              if (!afl->extras_cnt ||
-                  (afl->a_extras_cnt && rand_below(afl, 2))) {
+                if (!afl->extras_cnt ||
+                    (afl->a_extras_cnt && rand_below(afl, 2))) {
 
-                use_extra = rand_below(afl, afl->a_extras_cnt);
-                extra_len = afl->a_extras[use_extra].len;
-                ptr = afl->a_extras[use_extra].data;
+                  use_extra = rand_below(afl, afl->a_extras_cnt);
+                  extra_len = afl->a_extras[use_extra].len;
+                  ptr = afl->a_extras[use_extra].data;
 #ifdef INTROSPECTION
-                snprintf(afl->m_tmp, sizeof(afl->m_tmp),
-                         " AUTO_EXTRA_INSERT-%u-%u", insert_at, extra_len);
-                strcat(afl->mutation, afl->m_tmp);
+                  snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+                           " AUTO_EXTRA_INSERT-%u-%u", insert_at, extra_len);
+                  strcat(afl->mutation, afl->m_tmp);
 #endif
 
-              } else {
+                } else {
 
-                use_extra = rand_below(afl, afl->extras_cnt);
-                extra_len = afl->extras[use_extra].len;
-                ptr = afl->extras[use_extra].data;
+                  use_extra = rand_below(afl, afl->extras_cnt);
+                  extra_len = afl->extras[use_extra].len;
+                  ptr = afl->extras[use_extra].data;
 #ifdef INTROSPECTION
-                snprintf(afl->m_tmp, sizeof(afl->m_tmp), " EXTRA_INSERT-%u-%u",
-                         insert_at, extra_len);
-                strcat(afl->mutation, afl->m_tmp);
+                  snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+                           " EXTRA_INSERT-%u-%u", insert_at, extra_len);
+                  strcat(afl->mutation, afl->m_tmp);
 #endif
 
-              }
-
-              if (temp_len + extra_len >= MAX_FILE) break;
+                }
 
-              out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len);
-              if (unlikely(!out_buf)) { PFATAL("alloc"); }
+                if (temp_len + extra_len >= MAX_FILE) break;
 
-              /* Tail */
-              memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
-                      temp_len - insert_at);
+                out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len);
+                if (unlikely(!out_buf)) { PFATAL("alloc"); }
 
-              /* Inserted part */
-              memcpy(out_buf + insert_at, ptr, extra_len);
+                /* Tail */
+                memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
+                        temp_len - insert_at);
 
-              temp_len += extra_len;
-              MOpt_globals.cycles_v2[STAGE_InsertExtra]++;
-              break;
+                /* Inserted part */
+                memcpy(out_buf + insert_at, ptr, extra_len);
 
-            }
+                temp_len += extra_len;
+                MOpt_globals.cycles_v2[STAGE_InsertExtra]++;
+                break;
 
-            default: {
+              } else {
 
-              if (unlikely(afl->ready_for_splicing_count < 2)) break;
+                if (unlikely(afl->ready_for_splicing_count < 2)) break;
 
-              u32 tid;
-              do {
+                u32 tid;
+                do {
 
-                tid = rand_below(afl, afl->queued_items);
+                  tid = rand_below(afl, afl->queued_items);
 
-              } while (tid == afl->current_entry ||
+                } while (tid == afl->current_entry ||
 
-                       afl->queue_buf[tid]->len < 4);
+                         afl->queue_buf[tid]->len < 4);
 
-              /* Get the testcase for splicing. */
-              struct queue_entry *target = afl->queue_buf[tid];
-              u32                 new_len = target->len;
-              u8 *                new_buf = queue_testcase_get(afl, target);
+                /* Get the testcase for splicing. */
+                struct queue_entry *target = afl->queue_buf[tid];
+                u32                 new_len = target->len;
+                u8 *                new_buf = queue_testcase_get(afl, target);
 
-              if ((temp_len >= 2 && rand_below(afl, 2)) ||
-                  temp_len + HAVOC_BLK_XL >= MAX_FILE) {
+                if ((temp_len >= 2 && rand_below(afl, 2)) ||
+                    temp_len + HAVOC_BLK_XL >= MAX_FILE) {
 
-                /* overwrite mode */
+                  /* overwrite mode */
 
-                u32 copy_from, copy_to, copy_len;
+                  u32 copy_from, copy_to, copy_len;
 
-                copy_len = choose_block_len(afl, new_len - 1);
-                if (copy_len > temp_len) copy_len = temp_len;
+                  copy_len = choose_block_len(afl, new_len - 1);
+                  if (copy_len > temp_len) copy_len = temp_len;
 
-                copy_from = rand_below(afl, new_len - copy_len + 1);
-                copy_to = rand_below(afl, temp_len - copy_len + 1);
+                  copy_from = rand_below(afl, new_len - copy_len + 1);
+                  copy_to = rand_below(afl, temp_len - copy_len + 1);
 
 #ifdef INTROSPECTION
-                snprintf(afl->m_tmp, sizeof(afl->m_tmp),
-                         " SPLICE_OVERWRITE-%u-%u-%u-%s", copy_from, copy_to,
-                         copy_len, target->fname);
-                strcat(afl->mutation, afl->m_tmp);
+                  snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+                           " SPLICE_OVERWRITE-%u-%u-%u-%s", copy_from, copy_to,
+                           copy_len, target->fname);
+                  strcat(afl->mutation, afl->m_tmp);
 #endif
-                memmove(out_buf + copy_to, new_buf + copy_from, copy_len);
+                  memmove(out_buf + copy_to, new_buf + copy_from, copy_len);
 
-              } else {
+                } else {
 
-                /* insert mode */
+                  /* insert mode */
 
-                u32 clone_from, clone_to, clone_len;
+                  u32 clone_from, clone_to, clone_len;
 
-                clone_len = choose_block_len(afl, new_len);
-                clone_from = rand_below(afl, new_len - clone_len + 1);
-                clone_to = rand_below(afl, temp_len + 1);
+                  clone_len = choose_block_len(afl, new_len);
+                  clone_from = rand_below(afl, new_len - clone_len + 1);
+                  clone_to = rand_below(afl, temp_len + 1);
 
-                u8 *temp_buf = afl_realloc(AFL_BUF_PARAM(out_scratch),
-                                           temp_len + clone_len + 1);
-                if (unlikely(!temp_buf)) { PFATAL("alloc"); }
+                  u8 *temp_buf = afl_realloc(AFL_BUF_PARAM(out_scratch),
+                                             temp_len + clone_len + 1);
+                  if (unlikely(!temp_buf)) { PFATAL("alloc"); }
 
 #ifdef INTROSPECTION
-                snprintf(afl->m_tmp, sizeof(afl->m_tmp),
-                         " SPLICE_INSERT-%u-%u-%u-%s", clone_from, clone_to,
-                         clone_len, target->fname);
-                strcat(afl->mutation, afl->m_tmp);
+                  snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+                           " SPLICE_INSERT-%u-%u-%u-%s", clone_from, clone_to,
+                           clone_len, target->fname);
+                  strcat(afl->mutation, afl->m_tmp);
 #endif
-                /* Head */
+                  /* Head */
 
-                memcpy(temp_buf, out_buf, clone_to);
+                  memcpy(temp_buf, out_buf, clone_to);
 
-                /* Inserted part */
+                  /* Inserted part */
 
-                memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len);
+                  memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len);
 
-                /* Tail */
-                memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to,
-                       temp_len - clone_to);
+                  /* Tail */
+                  memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to,
+                         temp_len - clone_to);
 
-                out_buf = temp_buf;
-                afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
-                temp_len += clone_len;
+                  out_buf = temp_buf;
+                  afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+                  temp_len += clone_len;
 
-              }
+                }
 
-              MOpt_globals.cycles_v2[STAGE_Splice]++;
-              break;
+                MOpt_globals.cycles_v2[STAGE_Splice]++;
+                break;
+
+              }
 
             }  // end of default:
 
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index ffba3475..09e773f0 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -74,7 +74,7 @@ fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) {
    rewound and truncated. */
 
 u32 __attribute__((hot))
-write_to_testcase(afl_state_t *afl, void *mem, u32 len, u32 fix) {
+write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
 
 #ifdef _AFL_DOCUMENT_MUTATIONS
   s32  doc_fd;
@@ -86,7 +86,7 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len, u32 fix) {
   if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION)) >=
       0) {
 
-    if (write(doc_fd, mem, len) != len)
+    if (write(doc_fd, *mem, len) != len)
       PFATAL("write to mutation file failed: %s", fn);
     close(doc_fd);
 
@@ -97,7 +97,7 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len, u32 fix) {
   if (unlikely(afl->custom_mutators_count)) {
 
     ssize_t new_size = len;
-    u8 *    new_mem = mem;
+    u8 *    new_mem = *mem;
     u8 *    new_buf = NULL;
 
     LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
@@ -130,8 +130,14 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len, u32 fix) {
 
     }
 
+    if (new_mem != *mem) {
+
+      *mem = new_mem;
+
+    }
+
     /* everything as planned. use the potentially new data. */
-    afl_fsrv_write_to_testcase(&afl->fsrv, new_mem, new_size);
+    afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size);
     len = new_size;
 
   } else {
@@ -147,7 +153,7 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len, u32 fix) {
     }
 
     /* boring uncustom. */
-    afl_fsrv_write_to_testcase(&afl->fsrv, mem, len);
+    afl_fsrv_write_to_testcase(&afl->fsrv, *mem, len);
 
   }
 
@@ -370,7 +376,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
   /* we need a dummy run if this is LTO + cmplog */
   if (unlikely(afl->shm.cmplog_mode)) {
 
-    (void)write_to_testcase(afl, use_mem, q->len, 1);
+    (void)write_to_testcase(afl, (void **)&use_mem, q->len, 1);
 
     fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
 
@@ -413,7 +419,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
 
     u64 cksum;
 
-    (void)write_to_testcase(afl, use_mem, q->len, 1);
+    (void)write_to_testcase(afl, (void **)&use_mem, q->len, 1);
 
     fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
 
@@ -724,7 +730,7 @@ void sync_fuzzers(afl_state_t *afl) {
         /* See what happens. We rely on save_if_interesting() to catch major
            errors and save the test case. */
 
-        (void)write_to_testcase(afl, mem, st.st_size, 1);
+        (void)write_to_testcase(afl, (void **)&mem, st.st_size, 1);
 
         fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
 
@@ -967,7 +973,7 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
 
   u8 fault;
 
-  len = write_to_testcase(afl, out_buf, len, 0);
+  len = write_to_testcase(afl, (void **)&out_buf, len, 0);
 
   fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
 
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 9737c692..5b237748 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -1021,13 +1021,15 @@ void show_stats_normal(afl_state_t *afl) {
 
   if (unlikely(!afl->skip_deterministic)) {
 
-    sprintf(tmp, "%s/%s, %s/%s, %s/%s",
+    sprintf(tmp, "%s/%s, %s/%s, %s/%s, %s/%s",
             u_stringify_int(IB(0), afl->stage_finds[STAGE_EXTRAS_UO]),
             u_stringify_int(IB(1), afl->stage_cycles[STAGE_EXTRAS_UO]),
             u_stringify_int(IB(2), afl->stage_finds[STAGE_EXTRAS_UI]),
             u_stringify_int(IB(3), afl->stage_cycles[STAGE_EXTRAS_UI]),
             u_stringify_int(IB(4), afl->stage_finds[STAGE_EXTRAS_AO]),
-            u_stringify_int(IB(5), afl->stage_cycles[STAGE_EXTRAS_AO]));
+            u_stringify_int(IB(5), afl->stage_cycles[STAGE_EXTRAS_AO]),
+            u_stringify_int(IB(6), afl->stage_finds[STAGE_EXTRAS_AI]),
+            u_stringify_int(IB(7), afl->stage_cycles[STAGE_EXTRAS_AI]));
 
   } else if (unlikely(!afl->extras_cnt || afl->custom_only)) {
 
@@ -1839,13 +1841,15 @@ void show_stats_pizza(afl_state_t *afl) {
 
   if (unlikely(!afl->skip_deterministic)) {
 
-    sprintf(tmp, "%s/%s, %s/%s, %s/%s",
+    sprintf(tmp, "%s/%s, %s/%s, %s/%s, %s/%s",
             u_stringify_int(IB(0), afl->stage_finds[STAGE_EXTRAS_UO]),
             u_stringify_int(IB(1), afl->stage_cycles[STAGE_EXTRAS_UO]),
             u_stringify_int(IB(2), afl->stage_finds[STAGE_EXTRAS_UI]),
             u_stringify_int(IB(3), afl->stage_cycles[STAGE_EXTRAS_UI]),
             u_stringify_int(IB(4), afl->stage_finds[STAGE_EXTRAS_AO]),
-            u_stringify_int(IB(5), afl->stage_cycles[STAGE_EXTRAS_AO]));
+            u_stringify_int(IB(5), afl->stage_cycles[STAGE_EXTRAS_AO]),
+            u_stringify_int(IB(6), afl->stage_finds[STAGE_EXTRAS_AI]),
+            u_stringify_int(IB(7), afl->stage_cycles[STAGE_EXTRAS_AI]));
 
   } else if (unlikely(!afl->extras_cnt || afl->custom_only)) {
 
diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c
index 8d58bb3e..b48c6fb3 100644
--- a/src/afl-sharedmem.c
+++ b/src/afl-sharedmem.c
@@ -107,7 +107,7 @@ void afl_shm_deinit(sharedmem_t *shm) {
     if (shm->cmp_map != NULL) {
 
       munmap(shm->cmp_map, shm->map_size);
-      shm->map = NULL;
+      shm->cmp_map = NULL;
 
     }
 
@@ -153,6 +153,8 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
   shm->g_shm_fd = -1;
   shm->cmplog_g_shm_fd = -1;
 
+  const int shmflags = O_RDWR | O_EXCL;
+
   /* ======
   generate random file name for multi instance
 
@@ -161,9 +163,39 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
   so we do this worse workaround */
   snprintf(shm->g_shm_file_path, L_tmpnam, "/afl_%d_%ld", getpid(), random());
 
+  #ifdef SHM_LARGEPAGE_ALLOC_DEFAULT
+  /* trying to get large memory segment optimised and monitorable separately as
+   * such */
+  static size_t sizes[4] = {(size_t)-1};
+  static int    psizes = 0;
+  int           i;
+  if (sizes[0] == (size_t)-1) { psizes = getpagesizes(sizes, 4); }
+
+  /* very unlikely to fail even if the arch supports only two sizes */
+  if (likely(psizes > 0)) {
+
+    for (i = psizes - 1; shm->g_shm_fd == -1 && i >= 0; --i) {
+
+      if (sizes[i] == 0 || map_size % sizes[i]) { continue; }
+
+      shm->g_shm_fd =
+          shm_create_largepage(shm->g_shm_file_path, shmflags, i,
+                               SHM_LARGEPAGE_ALLOC_DEFAULT, DEFAULT_PERMISSION);
+
+    }
+
+  }
+
+  #endif
+
   /* create the shared memory segment as if it was a file */
-  shm->g_shm_fd = shm_open(shm->g_shm_file_path, O_CREAT | O_RDWR | O_EXCL,
-                           DEFAULT_PERMISSION);
+  if (shm->g_shm_fd == -1) {
+
+    shm->g_shm_fd =
+        shm_open(shm->g_shm_file_path, shmflags | O_CREAT, DEFAULT_PERMISSION);
+
+  }
+
   if (shm->g_shm_fd == -1) { PFATAL("shm_open() failed"); }
 
   /* configure the size of the shared memory segment */
diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION
index cda1d700..77fc69b5 100644
--- a/unicorn_mode/UNICORNAFL_VERSION
+++ b/unicorn_mode/UNICORNAFL_VERSION
@@ -1 +1 @@
-09ad7d4784e50ec4ddf590a2c29764e2a7f37442
+c3e15a7d