about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules2
-rw-r--r--CONTRIBUTING.md4
-rw-r--r--README.md11
-rw-r--r--custom_mutators/honggfuzz/honggfuzz.c1
-rw-r--r--custom_mutators/libfuzzer/FuzzerIO.cpp7
-rw-r--r--custom_mutators/libfuzzer/FuzzerLoop.cpp13
-rw-r--r--custom_mutators/libfuzzer/FuzzerMutate.cpp24
-rw-r--r--custom_mutators/libfuzzer/FuzzerMutate.h1
-rw-r--r--custom_mutators/libfuzzer/Makefile5
-rw-r--r--custom_mutators/libfuzzer/libfuzzer.cpp13
-rw-r--r--custom_mutators/radamsa/radamsa-mutator.c1
-rw-r--r--custom_mutators/symcc/symcc.c124
-rw-r--r--custom_mutators/symcc/test_examples/file_test.c36
-rw-r--r--custom_mutators/symcc/test_examples/stdin_test.c28
-rw-r--r--docs/Changelog.md13
-rw-r--r--docs/custom_mutators.md13
-rw-r--r--docs/env_variables.md21
-rw-r--r--examples/afl_frida/afl-frida.c7
-rw-r--r--examples/afl_network_proxy/afl-network-server.c15
-rw-r--r--examples/custom_mutators/custom_mutator_helpers.h2
-rw-r--r--examples/custom_mutators/post_library_gif.so.c8
-rw-r--r--examples/custom_mutators/post_library_png.so.c8
-rw-r--r--examples/custom_mutators/simple_example.c2
-rw-r--r--examples/defork/forking_target.c1
-rw-r--r--include/afl-fuzz.h41
-rw-r--r--include/alloc-inl.h22
-rw-r--r--include/envs.h3
-rw-r--r--instrumentation/SanitizerCoveragePCGUARD.so.cc8
-rw-r--r--instrumentation/afl-compiler-rt.o.c6
-rw-r--r--qemu_mode/QEMUAFL_VERSION2
-rw-r--r--qemu_mode/libcompcov/pmparser.h8
-rw-r--r--src/afl-cc.c130
-rw-r--r--src/afl-common.c2
-rw-r--r--src/afl-forkserver.c17
-rw-r--r--src/afl-fuzz-bitmap.c91
-rw-r--r--src/afl-fuzz-init.c11
-rw-r--r--src/afl-fuzz-mutators.c7
-rw-r--r--src/afl-fuzz-one.c14
-rw-r--r--src/afl-fuzz-python.c78
-rw-r--r--src/afl-fuzz-queue.c7
-rw-r--r--src/afl-fuzz-run.c4
-rw-r--r--src/afl-fuzz-state.c6
-rw-r--r--src/afl-fuzz.c56
-rw-r--r--src/afl-gotcpu.c1
-rw-r--r--src/afl-showmap.c6
-rw-r--r--src/afl-tmin.c7
-rwxr-xr-xtest/test-unicorn-mode.sh6
-rw-r--r--unicorn_mode/samples/persistent/simple_target_noncrashing.c16
m---------unicorn_mode/unicornafl0
49 files changed, 712 insertions, 197 deletions
diff --git a/.gitmodules b/.gitmodules
index 3ad6e10c..7c7613ac 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -7,4 +7,4 @@
 	url = https://github.com/AFLplusplus/Grammar-Mutator
 [submodule "qemu_mode/qemuafl"]
 	path = qemu_mode/qemuafl
-	url = https://github.com/AFLplusplus/qemuafl.git
+	url = https://github.com/AFLplusplus/qemuafl
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ccacef5f..c36ed9d8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -16,9 +16,9 @@ project, or added a file in a directory we already format, otherwise run:
 ```
 
 Regarding the coding style, please follow the AFL style.
-No camel case at all and use the AFL's macros wherever possible 
+No camel case at all and use AFL's macros wherever possible
 (e.g. WARNF, FATAL, MAP_SIZE, ...).
 
 Remember that AFLplusplus has to build and run on many platforms, so
 generalize your Makefiles/GNUmakefile (or your patches to our pre-existing
-Makefiles) to be as much generic as possible.
+Makefiles) to be as generic as possible.
diff --git a/README.md b/README.md
index d7c5694e..494a6bb7 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@
   afl++ is a superior fork to Google's afl - more speed, more and better
   mutations, more and better instrumentation, custom module support, etc.
 
-  If you want to use afl++ for you academic work, check the [papers page](https://aflplus.plus/papers/)
-  in the website.
+  If you want to use afl++ for your academic work, check the [papers page](https://aflplus.plus/papers/)
+  on the website.
 
 ## Major changes in afl++ 3.0
 
@@ -585,7 +585,10 @@ For every secondary fuzzer there should be a variation, e.g.:
    activated (`export AFL_USE_ASAN=1 ; export AFL_USE_UBSAN=1 ;
    export AFL_USE_CFISAN=1 ; `
  * one should fuzz the target with CMPLOG/redqueen (see above)
- * one to three should fuzz a target compiled with laf-intel/COMPCOV (see above).
+ * one to three fuzzers should fuzz a target compiled with laf-intel/COMPCOV
+   (see above). Important note: If you run more than one laf-intel/COMPCOV
+   fuzzer and you want them to share their intermediate results, the main
+   fuzzer (`-M`) must be one of the them!
 
 All other secondaries should be used like this:
  * A third to a half with the MOpt mutator enabled: `-L 0`
@@ -597,11 +600,11 @@ You can also use different fuzzers.
 If you are using afl spinoffs or afl conforming fuzzers, then just use the
 same -o directory and give it a unique `-S` name.
 Examples are:
- * [Angora](https://github.com/AngoraFuzzer/Angora)
  * [Untracer](https://github.com/FoRTE-Research/UnTracer-AFL)
  * [AFLsmart](https://github.com/aflsmart/aflsmart)
  * [FairFuzz](https://github.com/carolemieux/afl-rb)
  * [Neuzz](https://github.com/Dongdongshe/neuzz)
+ * [Angora](https://github.com/AngoraFuzzer/Angora)
 
 A long list can be found at [https://github.com/Microsvuln/Awesome-AFL](https://github.com/Microsvuln/Awesome-AFL)
 
diff --git a/custom_mutators/honggfuzz/honggfuzz.c b/custom_mutators/honggfuzz/honggfuzz.c
index bde922c6..b4f07258 100644
--- a/custom_mutators/honggfuzz/honggfuzz.c
+++ b/custom_mutators/honggfuzz/honggfuzz.c
@@ -37,6 +37,7 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
 
   if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) {
 
+    free(data);
     perror("mutator_buf alloc");
     return NULL;
 
diff --git a/custom_mutators/libfuzzer/FuzzerIO.cpp b/custom_mutators/libfuzzer/FuzzerIO.cpp
index e0c15db4..d8d52b63 100644
--- a/custom_mutators/libfuzzer/FuzzerIO.cpp
+++ b/custom_mutators/libfuzzer/FuzzerIO.cpp
@@ -83,6 +83,8 @@ void WriteToFile(const std::string &Data, const std::string &Path) {
 
 void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path) {
 
+  return;
+ 
   // Use raw C interface because this function may be called from a sig handler.
   FILE *Out = fopen(Path.c_str(), "wb");
   if (!Out) return;
@@ -93,6 +95,8 @@ void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path) {
 
 void AppendToFile(const std::string &Data, const std::string &Path) {
 
+  return;
+
   AppendToFile(reinterpret_cast<const uint8_t *>(Data.data()), Data.size(),
                Path);
 
@@ -100,6 +104,8 @@ void AppendToFile(const std::string &Data, const std::string &Path) {
 
 void AppendToFile(const uint8_t *Data, size_t Size, const std::string &Path) {
 
+  return;
+
   FILE *Out = fopen(Path.c_str(), "a");
   if (!Out) return;
   fwrite(Data, sizeof(Data[0]), Size, Out);
@@ -182,6 +188,7 @@ void Printf(const char *Fmt, ...) {
 
 void VPrintf(bool Verbose, const char *Fmt, ...) {
 
+  return;
   if (!Verbose) return;
   va_list ap;
   va_start(ap, Fmt);
diff --git a/custom_mutators/libfuzzer/FuzzerLoop.cpp b/custom_mutators/libfuzzer/FuzzerLoop.cpp
index 201883f0..08fda520 100644
--- a/custom_mutators/libfuzzer/FuzzerLoop.cpp
+++ b/custom_mutators/libfuzzer/FuzzerLoop.cpp
@@ -206,6 +206,8 @@ void Fuzzer::StaticDeathCallback() {
 
 void Fuzzer::DumpCurrentUnit(const char *Prefix) {
 
+  return;
+
   if (!CurrentUnitData) return;  // Happens when running individual inputs.
   ScopedDisableMsanInterceptorChecks S;
   MD.PrintMutationSequence();
@@ -733,6 +735,7 @@ std::string Fuzzer::WriteToOutputCorpus(const Unit &U) {
 
 void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) {
 
+  return;
   if (!Options.SaveArtifacts) return;
   std::string Path = Options.ArtifactPrefix + Prefix + Hash(U);
   if (!Options.ExactArtifactPath.empty())
@@ -1073,13 +1076,21 @@ void Fuzzer::MinimizeCrashLoop(const Unit &U) {
 
 }  // namespace fuzzer
 
+#ifdef  INTROSPECTION
+  extern const char *introspection_ptr;
+#endif
+
 extern "C" {
 
 ATTRIBUTE_INTERFACE size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size,
                                             size_t MaxSize) {
 
   assert(fuzzer::F);
-  return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize);
+  size_t r = fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize);
+#ifdef  INTROSPECTION
+  introspection_ptr = fuzzer::F->GetMD().WriteMutationSequence();
+#endif
+  return r;
 
 }
 
diff --git a/custom_mutators/libfuzzer/FuzzerMutate.cpp b/custom_mutators/libfuzzer/FuzzerMutate.cpp
index eebae39b..edfe0455 100644
--- a/custom_mutators/libfuzzer/FuzzerMutate.cpp
+++ b/custom_mutators/libfuzzer/FuzzerMutate.cpp
@@ -14,6 +14,8 @@
 #include "FuzzerMutate.h"
 #include "FuzzerOptions.h"
 #include "FuzzerTracePC.h"
+#include <random>
+#include <chrono>
 
 namespace fuzzer {
 
@@ -100,15 +102,17 @@ size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size,
 
 }
 
+
 size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
                                                size_t MaxSize) {
-
   if (Size > MaxSize || Size == 0) return 0;
   size_t ShuffleAmount =
       Rand(std::min(Size, (size_t)8)) + 1;  // [1,8] and <= Size.
   size_t ShuffleStart = Rand(Size - ShuffleAmount);
   assert(ShuffleStart + ShuffleAmount <= Size);
-  std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand);
+  unsigned num = std::chrono::system_clock::now().time_since_epoch().count();
+  std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, std::default_random_engine(num));
+  //std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand);
   return Size;
 
 }
@@ -609,8 +613,24 @@ void MutationDispatcher::PrintRecommendedDictionary() {
 
 }
 
+const char *MutationDispatcher::WriteMutationSequence() {
+
+  static std::string buf;
+  buf = "";
+
+  for (size_t i = 0; i < CurrentMutatorSequence.size(); i++) {
+  
+    buf = buf + " " + CurrentMutatorSequence[i].Name;
+  
+  }
+  
+  return buf.c_str();
+
+}
+
 void MutationDispatcher::PrintMutationSequence(bool Verbose) {
 
+  return;
   Printf("MS: %zd ", CurrentMutatorSequence.size());
   size_t EntriesToPrint =
       Verbose ? CurrentMutatorSequence.size()
diff --git a/custom_mutators/libfuzzer/FuzzerMutate.h b/custom_mutators/libfuzzer/FuzzerMutate.h
index 37fd6100..6252f265 100644
--- a/custom_mutators/libfuzzer/FuzzerMutate.h
+++ b/custom_mutators/libfuzzer/FuzzerMutate.h
@@ -26,6 +26,7 @@ public:
   void StartMutationSequence();
   /// Print the current sequence of mutations. Only prints the full sequence
   /// when Verbose is true.
+  const char *WriteMutationSequence();
   void PrintMutationSequence(bool Verbose = true);
   /// Return the current sequence of mutations.
   std::string MutationSequence();
diff --git a/custom_mutators/libfuzzer/Makefile b/custom_mutators/libfuzzer/Makefile
index 95402f6c..51263b89 100644
--- a/custom_mutators/libfuzzer/Makefile
+++ b/custom_mutators/libfuzzer/Makefile
@@ -3,6 +3,11 @@ CFLAGS = -g -O3 -funroll-loops -fPIC -fpermissive -std=c++11
 #CFLAGS = -g -O0 -fPIC -fpermissive -std=c++11
 CXX ?= clang++
 
+ifdef INTROSPECTION
+  $(info Compiling with introspection documentation)
+  CFLAGS += -DINTROSPECTION=1
+endif
+
 all: libfuzzer-mutator.so
 
 FuzzerCrossOver.o:	FuzzerCrossOver.cpp
diff --git a/custom_mutators/libfuzzer/libfuzzer.cpp b/custom_mutators/libfuzzer/libfuzzer.cpp
index 5e37df66..dc1fbeb2 100644
--- a/custom_mutators/libfuzzer/libfuzzer.cpp
+++ b/custom_mutators/libfuzzer/libfuzzer.cpp
@@ -6,6 +6,10 @@
 //#include "debug.h"
 #include "afl-fuzz.h"
 
+#ifdef  INTROSPECTION
+  const char *introspection_ptr;
+#endif
+
 afl_state_t *afl_struct;
 
 extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
@@ -46,6 +50,7 @@ extern "C" my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
 
   if ((data->mutator_buf = (u8 *)malloc(MAX_FILE)) == NULL) {
 
+    free(data);
     perror("mutator_buf alloc");
     return NULL;
 
@@ -133,6 +138,14 @@ extern "C" size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf,
 
 }
 
+#ifdef  INTROSPECTION
+extern "C" const char* afl_custom_introspection(my_mutator_t *data) {
+
+  return introspection_ptr;
+
+}
+#endif
+
 /**
  * Deinitialize everything
  *
diff --git a/custom_mutators/radamsa/radamsa-mutator.c b/custom_mutators/radamsa/radamsa-mutator.c
index 82d28001..624ace3d 100644
--- a/custom_mutators/radamsa/radamsa-mutator.c
+++ b/custom_mutators/radamsa/radamsa-mutator.c
@@ -33,6 +33,7 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
 
   if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) {
 
+    free(data);
     perror("mutator_buf alloc");
     return NULL;
 
diff --git a/custom_mutators/symcc/symcc.c b/custom_mutators/symcc/symcc.c
index 18b475b8..a609dafb 100644
--- a/custom_mutators/symcc/symcc.c
+++ b/custom_mutators/symcc/symcc.c
@@ -1,7 +1,10 @@
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
 #include "config.h"
 #include "debug.h"
 #include "afl-fuzz.h"
@@ -21,6 +24,7 @@ typedef struct my_mutator {
   afl_state_t *afl;
   u8 *         mutator_buf;
   u8 *         out_dir;
+  u8 *         tmp_dir;
   u8 *         target;
   uint32_t     seed;
 
@@ -41,6 +45,7 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
 
   if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) {
 
+    free(data);
     perror("mutator_buf alloc");
     return NULL;
 
@@ -54,10 +59,11 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
   if (!(data->out_dir = getenv("SYMCC_OUTPUT_DIR"))) {
 
     data->out_dir = alloc_printf("%s/symcc", afl->out_dir);
-    setenv("SYMCC_OUTPUT_DIR", data->out_dir, 1);
 
   }
 
+  data->tmp_dir = alloc_printf("%s/tmp", data->out_dir);
+  setenv("SYMCC_OUTPUT_DIR", data->tmp_dir, 1);
   int pid = fork();
 
   if (pid == -1) return NULL;
@@ -83,6 +89,10 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
 
   if (mkdir(data->out_dir, 0755))
     PFATAL("Could not create directory %s", data->out_dir);
+
+  if (mkdir(data->tmp_dir, 0755))
+    PFATAL("Could not create directory %s", data->tmp_dir);
+
   DBG("out_dir=%s, target=%s\n", data->out_dir, data->target);
 
   return data;
@@ -95,33 +105,119 @@ void afl_custom_queue_new_entry(my_mutator_t * data,
                                 const uint8_t *filename_new_queue,
                                 const uint8_t *filename_orig_queue) {
 
-  int pid = fork();
+  int         pipefd[2];
+  struct stat st;
+  ACTF("Queueing to symcc: %s", filename_new_queue);
+  u8 *fn = alloc_printf("%s", filename_new_queue);
+  if (!(stat(fn, &st) == 0 && S_ISREG(st.st_mode) && st.st_size)) {
 
-  if (pid == -1) return;
+    ck_free(fn);
+    PFATAL("Couldn't find enqueued file: %s", fn);
 
-  if (pid) pid = waitpid(pid, NULL, 0);
+  }
 
-  if (pid == 0) {
+  if (afl_struct->fsrv.use_stdin) {
+
+    if (pipe(pipefd) == -1) {
+
+      ck_free(fn);
+      PFATAL("Couldn't create a pipe for interacting with symcc child process");
+
+    }
+
+  }
+
+  int pid = fork();
 
-    setenv("SYMCC_INPUT_FILE", afl_struct->fsrv.out_file, 1);
+  if (pid == -1) return;
+
+  if (pid) {
 
     if (afl_struct->fsrv.use_stdin) {
 
-      u8 *fn = alloc_printf("%s/%s", afl_struct->out_dir, filename_new_queue);
+      close(pipefd[0]);
       int fd = open(fn, O_RDONLY);
 
       if (fd >= 0) {
 
         ssize_t r = read(fd, data->mutator_buf, MAX_FILE);
-        close(fd);
         DBG("fn=%s, fd=%d, size=%ld\n", fn, fd, r);
-        if (r <= 0) return;
-        close(0);
-        ck_write(0, data->mutator_buf, r, fn);
         ck_free(fn);
+        close(fd);
+        if (r <= 0) {
+
+          close(pipefd[1]);
+          return;
+
+        }
+
+        if (r > fcntl(pipefd[1], F_GETPIPE_SZ))
+          fcntl(pipefd[1], F_SETPIPE_SZ, MAX_FILE);
+        ck_write(pipefd[1], data->mutator_buf, r, filename_new_queue);
+
+      } else {
+
+        ck_free(fn);
+        close(pipefd[1]);
+        PFATAL(
+            "Something happened to the enqueued file before sending its "
+            "contents to symcc binary");
 
       }
 
+      close(pipefd[1]);
+
+    }
+
+    pid = waitpid(pid, NULL, 0);
+
+    // At this point we need to transfer files to output dir, since their names
+    // collide and symcc will just overwrite them
+
+    struct dirent **nl;
+    int32_t         items = scandir(data->tmp_dir, &nl, NULL, NULL);
+    u8 *            origin_name = basename(filename_new_queue);
+    int32_t         i;
+    if (items > 0) {
+
+      for (i = 0; i < (u32)items; ++i) {
+
+        struct stat st;
+        u8 *source_name = alloc_printf("%s/%s", data->tmp_dir, nl[i]->d_name);
+        DBG("test=%s\n", fn);
+        if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) {
+
+          u8 *destination_name =
+              alloc_printf("%s/%s.%s", data->out_dir, origin_name, nl[i]->d_name);
+          rename(source_name, destination_name);
+          ck_free(destination_name);
+          DBG("found=%s\n", source_name);
+
+        }
+
+        ck_free(source_name);
+        free(nl[i]);
+
+      }
+
+      free(nl);
+
+    }
+
+  }
+
+  if (pid == 0) {
+
+    if (afl_struct->fsrv.use_stdin) {
+
+      unsetenv("SYMCC_INPUT_FILE");
+      close(pipefd[1]);
+      dup2(pipefd[0], 0);
+
+    } else {
+
+      setenv("SYMCC_INPUT_FILE", afl_struct->fsrv.out_file, 1);
+
     }
 
     DBG("exec=%s\n", data->target);
@@ -129,6 +225,7 @@ void afl_custom_queue_new_entry(my_mutator_t * data,
     close(2);
     dup2(afl_struct->fsrv.dev_null_fd, 1);
     dup2(afl_struct->fsrv.dev_null_fd, 2);
+
     execvp(data->target, afl_struct->argv);
     DBG("exec=FAIL\n");
     exit(-1);
@@ -179,7 +276,7 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
 
   struct dirent **nl;
   int32_t         i, done = 0, items = scandir(data->out_dir, &nl, NULL, NULL);
-  size_t          size = 0;
+  ssize_t         size = 0;
 
   if (items <= 0) return 0;
 
@@ -198,6 +295,7 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
 
           size = read(fd, data->mutator_buf, max_size);
           *out_buf = data->mutator_buf;
+
           close(fd);
           done = 1;
 
@@ -216,7 +314,7 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
 
   free(nl);
   DBG("FUZZ size=%lu\n", size);
-  return size;
+  return (uint32_t)size;
 
 }
 
diff --git a/custom_mutators/symcc/test_examples/file_test.c b/custom_mutators/symcc/test_examples/file_test.c
new file mode 100644
index 00000000..f2b92986
--- /dev/null
+++ b/custom_mutators/symcc/test_examples/file_test.c
@@ -0,0 +1,36 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int main(int argc, char **argv) {
+
+  if (argc < 2) {
+
+    printf("Need a file argument\n");
+    return 1;
+
+  }
+
+  int fd = open(argv[1], O_RDONLY);
+  if (fd < 0) {
+
+    printf("Couldn't open file\n");
+    return 1;
+
+  }
+
+  uint32_t value = 0;
+
+  read(fd, &value, sizeof(value));
+  close(fd);
+
+  value = value ^ 0xffffffff;
+  if (value == 0x11223344) printf("Value one\n");
+  if (value == 0x44332211) printf("Value two\n");
+  if (value != 0x0) printf("Not zero\n");
+  return 0;
+
+}
+
diff --git a/custom_mutators/symcc/test_examples/stdin_test.c b/custom_mutators/symcc/test_examples/stdin_test.c
new file mode 100644
index 00000000..3acfc523
--- /dev/null
+++ b/custom_mutators/symcc/test_examples/stdin_test.c
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+
+  char     input_buffer[16];
+  uint32_t comparisonValue;
+  size_t   bytesRead;
+  bytesRead = read(STDIN_FILENO, input_buffer, sizeof(input_buffer));
+  if (bytesRead < 0) exit(-1);
+  comparisonValue = *(uint32_t *)input_buffer;
+  comparisonValue = comparisonValue ^ 0xff112233;
+  if (comparisonValue == 0x66554493) {
+
+    printf("First value\n");
+
+  } else {
+
+    if (comparisonValue == 0x84444415) printf("Second value\n");
+
+  }
+
+  return 0;
+
+}
+
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 50c1d48a..9426ed54 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -38,22 +38,27 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
     - added INTROSPECTION make target that writes all mutations to
       out/NAME/introspection.txt
     - print special compile time options used in help output
+    - somewhere we broke -n dumb fuzzing, fixed
   - instrumentation
     - We received an enhanced gcc_plugin module from AdaCore, thank you
       very much!!
     - not overriding -Ox or -fno-unroll-loops anymore
     - we now have our own trace-pc-guard implementation. It is the same as
       -fsanitize-coverage=trace-pc-guard from llvm 12, but: it is a) inline
-      and b) works from llvm 10+ on :)
+      and b) works from llvm 10.0.1 + onwards :)
     - new llvm pass: dict2file via AFL_LLVM_DICT2FILE, create afl-fuzz
       -x dictionary of string comparisons found during compilation
     - LTO autodict now also collects interesting cmp comparisons,
       std::string compare + find + ==, bcmp
     - fix crash in dict2file for integers > 64 bit
+  - custom mutators
+    - added a new custom mutator: symcc -> https://github.com/eurecom-s3/symcc/
+    - added a new custom mutator: libfuzzer that integrates libfuzzer mutations
+    - Our afl++ Grammar-Mutator is now better integrated into custom_mutators/
+    - added INTROSPECTION support for custom modules
+    - python fuzz function was not optional, fixed
   - unicornafl synced with upstream (arm64 fix, better rust bindings)
-  - added a new custom mutator: symcc -> https://github.com/eurecom-s3/symcc/
-  - added a new custom mutator: libfuzzer that integrates libfuzzer mutations
-  - Our afl++ Grammar-Mutator is now better integrated into custom_mutators/
+  - renamed AFL_DEBUG_CHILD_OUTPUT to AFL_DEBUG_CHILD
 
 
 ### Version ++2.68c (release)
diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md
index 81ee9de4..53f783fe 100644
--- a/docs/custom_mutators.md
+++ b/docs/custom_mutators.md
@@ -42,6 +42,7 @@ size_t afl_custom_havoc_mutation(void *data, unsigned char *buf, size_t buf_size
 unsigned char afl_custom_havoc_mutation_probability(void *data);
 unsigned char afl_custom_queue_get(void *data, const unsigned char *filename);
 void afl_custom_queue_new_entry(void *data, const unsigned char *filename_new_queue, const unsigned int *filename_orig_queue);
+const char* afl_custom_introspection(my_mutator_t *data);
 void afl_custom_deinit(void *data);
 ```
 
@@ -81,6 +82,9 @@ def queue_new_entry(filename_new_queue, filename_orig_queue):
     pass
 ```
 
+def introspection():
+    return string
+
 ### Custom Mutation
 
 - `init`:
@@ -126,10 +130,19 @@ def queue_new_entry(filename_new_queue, filename_orig_queue):
     `post_process` function. This function is then transforming the data into the
     format expected by the API before executing the target.
 
+    This can return any python object that implements the buffer protocol and
+    supports PyBUF_SIMPLE. These include bytes, bytearray, etc.
+
 - `queue_new_entry` (optional):
 
     This methods is called after adding a new test case to the queue.
 
+- `introspection` (optional):
+
+    This method is called after a new queue entry, crash or timeout is
+    discovered if compiled with INTROSPECTION. The custom mutator can then
+    return a string (const char *) that reports the exact mutations used.
+
 - `deinit`:
 
     The last method to be called, deinitializing the state.
diff --git a/docs/env_variables.md b/docs/env_variables.md
index a36f2b4e..04ba032a 100644
--- a/docs/env_variables.md
+++ b/docs/env_variables.md
@@ -306,6 +306,14 @@ checks or alter some of the more exotic semantics of the tool:
     don't want AFL++ to spend too much time classifying that stuff and just
     rapidly put all timeouts in that bin.
 
+  - Setting `AFL_FORKSRV_INIT_TMOUT` allows you to specify a different timeout
+    to wait for the forkserver to spin up. The default is the `-t` value times
+    `FORK_WAIT_MULT` from `config.h` (usually 10), so for a `-t 100`, the
+    default would wait for `1000` milliseconds. Setting a different time here is useful
+    if the target has a very slow startup time, for example when doing
+    full-system fuzzing or emulation, but you don't want the actual runs
+    to wait too long for timeouts.
+
   - `AFL_NO_ARITH` causes AFL++ to skip most of the deterministic arithmetics.
     This can be useful to speed up the fuzzing of text-based file formats.
 
@@ -380,8 +388,12 @@ checks or alter some of the more exotic semantics of the tool:
     processing the first queue entry; and `AFL_BENCH_UNTIL_CRASH` causes it to
     exit soon after the first crash is found.
 
-  - Setting `AFL_DEBUG_CHILD_OUTPUT` will not suppress the child output.
+  - Setting `AFL_DEBUG_CHILD` will not suppress the child output.
+    This lets you see all output of the child, making setup issues obvious.
+    For example, in an unicornafl harness, you might see python stacktraces.
+    You may also see other logs that way, indicating why the forkserver won't start.
     Not pretty but good for debugging purposes.
+    Note that `AFL_DEBUG_CHILD_OUTPUT` is deprecated.
 
   - Setting `AFL_NO_CPU_RED` will not display very high cpu usages in red color.
 
@@ -389,6 +401,13 @@ checks or alter some of the more exotic semantics of the tool:
     for an existing out folder, even if a different `-i` was provided.
     Without this setting, afl-fuzz will refuse execution for a long-fuzzed out dir.
 
+  - Setting `AFL_MAX_DET_EXRAS` will change the threshold at what number of elements
+    in the `-x` dictionary and LTO autodict (combined) the probabilistic mode will
+    kick off. In probabilistic mode not all dictionary entires will be used all
+    of the times for fuzzing mutations to not slow down fuzzing.
+    The default count is `200` elements. So for the 200 + 1st element, there is a
+    1 in 201 chance, that one of the dictionary entries will not be used directly.
+
   - Setting `AFL_NO_FORKSRV` disables the forkserver optimization, reverting to
     fork + execve() call for every tested input. This is useful mostly when
     working with unruly libraries that create threads or do other crazy
diff --git a/examples/afl_frida/afl-frida.c b/examples/afl_frida/afl-frida.c
index 2ad5a72a..31bf8f25 100644
--- a/examples/afl_frida/afl-frida.c
+++ b/examples/afl_frida/afl-frida.c
@@ -6,7 +6,7 @@
 
    Written mostly by meme -> https://github.com/meme/hotwax
 
-   Modificationy by Marc Heuse <mh@mh-sec.de>
+   Modifications by Marc Heuse <mh@mh-sec.de>
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -504,11 +504,12 @@ int main() {
     previous_pc = 0;  // Required!
 
 #ifdef _DEBUG
-    fprintf(stderr, "CLIENT crc: %016llx len: %u\n", hash64(__afl_fuzz_ptr, *__a
+    fprintf(stderr, "CLIENT crc: %016llx len: %u\n",
+            hash64(__afl_fuzz_ptr, *__afl_fuzz_len), *__afl_fuzz_len);
     fprintf(stderr, "RECV:");
     for (int i = 0; i < *__afl_fuzz_len; i++)
       fprintf(stderr, "%02x", __afl_fuzz_ptr[i]);
-    fprintf(stderr,"\n");
+    fprintf(stderr, "\n");
 #endif
 
     // STEP 3: ensure the minimum length is present and setup the target
diff --git a/examples/afl_network_proxy/afl-network-server.c b/examples/afl_network_proxy/afl-network-server.c
index 75eb3d20..513dc8f2 100644
--- a/examples/afl_network_proxy/afl-network-server.c
+++ b/examples/afl_network_proxy/afl-network-server.c
@@ -358,8 +358,8 @@ int recv_testcase(int s, void **buf) {
 
   if ((size & 0xff000000) != 0xff000000) {
 
-    *buf = afl_realloc((void **)&buf, size);
-    if (unlikely(!buf)) { PFATAL("Alloc"); }
+    *buf = afl_realloc(buf, size);
+    if (unlikely(!*buf)) { PFATAL("Alloc"); }
     received = 0;
     // fprintf(stderr, "unCOMPRESS (%u)\n", size);
     while (received < size &&
@@ -371,8 +371,8 @@ int recv_testcase(int s, void **buf) {
 #ifdef USE_DEFLATE
     u32 clen;
     size -= 0xff000000;
-    *buf = afl_realloc((void **)&buf, size);
-    if (unlikely(!buf)) { PFATAL("Alloc"); }
+    *buf = afl_realloc(buf, size);
+    if (unlikely(!*buf)) { PFATAL("Alloc"); }
     received = 0;
     while (received < 4 &&
            (ret = recv(s, &clen + received, 4 - received, 0)) > 0)
@@ -636,8 +636,11 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (listen(sock, 1) < 0) { PFATAL("listen() failed"); }
 
-  afl_fsrv_start(fsrv, use_argv, &stop_soon,
-                 get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0);
+  afl_fsrv_start(
+      fsrv, use_argv, &stop_soon,
+      (get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
+          ? 1
+          : 0);
 
 #ifdef USE_DEFLATE
   compressor = libdeflate_alloc_compressor(1);
diff --git a/examples/custom_mutators/custom_mutator_helpers.h b/examples/custom_mutators/custom_mutator_helpers.h
index ad5acb08..62e6efba 100644
--- a/examples/custom_mutators/custom_mutator_helpers.h
+++ b/examples/custom_mutators/custom_mutator_helpers.h
@@ -13,7 +13,7 @@
 #define BUF_VAR(type, name) \
   type * name##_buf;        \
   size_t name##_size;
-/* this filles in `&structptr->something_buf, &structptr->something_size`. */
+/* this fills in `&structptr->something_buf, &structptr->something_size`. */
 #define BUF_PARAMS(struct, name) \
   (void **)&struct->name##_buf, &struct->name##_size
 
diff --git a/examples/custom_mutators/post_library_gif.so.c b/examples/custom_mutators/post_library_gif.so.c
index 2d72400c..ac10f409 100644
--- a/examples/custom_mutators/post_library_gif.so.c
+++ b/examples/custom_mutators/post_library_gif.so.c
@@ -94,7 +94,13 @@ void *afl_custom_init(void *afl) {
   }
 
   state->buf = calloc(sizeof(unsigned char), 4096);
-  if (!state->buf) { return NULL; }
+  if (!state->buf) {
+
+    free(state);
+    perror("calloc");
+    return NULL;
+
+  }
 
   return state;
 
diff --git a/examples/custom_mutators/post_library_png.so.c b/examples/custom_mutators/post_library_png.so.c
index 7c1ea93e..941f7e55 100644
--- a/examples/custom_mutators/post_library_png.so.c
+++ b/examples/custom_mutators/post_library_png.so.c
@@ -54,7 +54,13 @@ void *afl_custom_init(void *afl) {
   }
 
   state->buf = calloc(sizeof(unsigned char), 4096);
-  if (!state->buf) { return NULL; }
+  if (!state->buf) {
+
+    free(state);
+    perror("calloc");
+    return NULL;
+
+  }
 
   return state;
 
diff --git a/examples/custom_mutators/simple_example.c b/examples/custom_mutators/simple_example.c
index a351d787..d888ec1f 100644
--- a/examples/custom_mutators/simple_example.c
+++ b/examples/custom_mutators/simple_example.c
@@ -8,7 +8,7 @@
 #include <stdio.h>
 
 #ifndef _FIXED_CHAR
-  #define 0x41
+  #define _FIXED_CHAR 0x41
 #endif
 
 typedef struct my_mutator {
diff --git a/examples/defork/forking_target.c b/examples/defork/forking_target.c
index 98f6365a..628d23c9 100644
--- a/examples/defork/forking_target.c
+++ b/examples/defork/forking_target.c
@@ -26,6 +26,7 @@ int main(int argc, char **argv) {
     FILE *f = fopen(argv[1], "r");
     char  buf[4096];
     fread(buf, 1, 4096, f);
+    fclose(f);
     uint32_t offset = buf[100] + (buf[101] << 8);
     char     test_val = buf[offset];
     return test_val < 100;
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index e59d5f90..933af65d 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -113,6 +113,7 @@
     #include <kstat.h>
     #include <sys/sysinfo.h>
     #include <sys/pset.h>
+    #include <strings.h>
   #endif
 #endif                                                         /* __linux__ */
 
@@ -310,6 +311,7 @@ enum {
   /* 09 */ PY_FUNC_HAVOC_MUTATION_PROBABILITY,
   /* 10 */ PY_FUNC_QUEUE_GET,
   /* 11 */ PY_FUNC_QUEUE_NEW_ENTRY,
+  /* 12 */ PY_FUNC_INTROSPECTION,
   PY_FUNC_COUNT
 
 };
@@ -324,8 +326,7 @@ typedef struct py_mutator {
   u8 *   fuzz_buf;
   size_t fuzz_size;
 
-  u8 *   post_process_buf;
-  size_t post_process_size;
+  Py_buffer post_process_buf;
 
   u8 *   trim_buf;
   size_t trim_size;
@@ -361,8 +362,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_cal_fast, afl_cycle_schedules, afl_expand_havoc, afl_statsd;
+      afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast,
+      afl_cycle_schedules, afl_expand_havoc, afl_statsd;
 
   u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
       *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload,
@@ -684,6 +685,8 @@ typedef struct afl_state {
 
   u32 custom_mutators_count;
 
+  struct custom_mutator *current_custom_fuzz;
+
   list_t custom_mutator_list;
 
   /* this is a fixed buffer of size map_size that can be used by any function if
@@ -748,6 +751,15 @@ struct custom_mutator {
   void *(*afl_custom_init)(afl_state_t *afl, unsigned int seed);
 
   /**
+   * When afl-fuzz was compiled with INTROSPECTION=1 then custom mutators can
+   * also give introspection information back with this function.
+   *
+   * @param data pointer returned in afl_custom_init for this fuzz case
+   * @return pointer to a text string (const char*)
+   */
+  const char *(*afl_custom_introspection)(void *data);
+
+  /**
    * This method is called just before fuzzing a queue entry with the custom
    * mutator, and receives the initial buffer. It should return the number of
    * fuzzes to perform.
@@ -953,16 +965,17 @@ u8   trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf,
 struct custom_mutator *load_custom_mutator_py(afl_state_t *, char *);
 void                   finalize_py_module(void *);
 
-u32    fuzz_count_py(void *, const u8 *, size_t);
-size_t post_process_py(void *, u8 *, size_t, u8 **);
-s32    init_trim_py(void *, u8 *, size_t);
-s32    post_trim_py(void *, u8);
-size_t trim_py(void *, u8 **);
-size_t havoc_mutation_py(void *, u8 *, size_t, u8 **, size_t);
-u8     havoc_mutation_probability_py(void *);
-u8     queue_get_py(void *, const u8 *);
-void   queue_new_entry_py(void *, const u8 *, const u8 *);
-void   deinit_py(void *);
+u32         fuzz_count_py(void *, const u8 *, size_t);
+size_t      post_process_py(void *, u8 *, size_t, u8 **);
+s32         init_trim_py(void *, u8 *, size_t);
+s32         post_trim_py(void *, u8);
+size_t      trim_py(void *, u8 **);
+size_t      havoc_mutation_py(void *, u8 *, size_t, u8 **, size_t);
+u8          havoc_mutation_probability_py(void *);
+u8          queue_get_py(void *, const u8 *);
+const char *introspection_py(void *);
+void        queue_new_entry_py(void *, const u8 *, const u8 *);
+void        deinit_py(void *);
 
 #endif
 
diff --git a/include/alloc-inl.h b/include/alloc-inl.h
index d7aa51a7..68255fb6 100644
--- a/include/alloc-inl.h
+++ b/include/alloc-inl.h
@@ -636,7 +636,7 @@ struct afl_alloc_buf {
 
 #define AFL_ALLOC_SIZE_OFFSET (offsetof(struct afl_alloc_buf, buf))
 
-/* Returs the container element to this ptr */
+/* Returns the container element to this ptr */
 static inline struct afl_alloc_buf *afl_alloc_bufptr(void *buf) {
 
   return (struct afl_alloc_buf *)((u8 *)buf - AFL_ALLOC_SIZE_OFFSET);
@@ -694,12 +694,18 @@ static inline void *afl_realloc(void **buf, size_t size_needed) {
   }
 
   /* alloc */
-  new_buf = (struct afl_alloc_buf *)realloc(new_buf, next_size);
-  if (unlikely(!new_buf)) {
+  struct afl_alloc_buf *newer_buf =
+      (struct afl_alloc_buf *)realloc(new_buf, next_size);
+  if (unlikely(!newer_buf)) {
 
+    free(new_buf);  // avoid a leak
     *buf = NULL;
     return NULL;
 
+  } else {
+
+    new_buf = newer_buf;
+
   }
 
   new_buf->complete_size = next_size;
@@ -730,12 +736,18 @@ static inline void *afl_realloc_exact(void **buf, size_t size_needed) {
   if (unlikely(current_size == size_needed)) { return *buf; }
 
   /* alloc */
-  new_buf = (struct afl_alloc_buf *)realloc(new_buf, size_needed);
-  if (unlikely(!new_buf)) {
+  struct afl_alloc_buf *newer_buf =
+      (struct afl_alloc_buf *)realloc(new_buf, size_needed);
+  if (unlikely(!newer_buf)) {
 
+    free(new_buf);  // avoid a leak
     *buf = NULL;
     return NULL;
 
+  } else {
+
+    new_buf = newer_buf;
+
   }
 
   new_buf->complete_size = size_needed;
diff --git a/include/envs.h b/include/envs.h
index b753d5f8..8255cf4f 100644
--- a/include/envs.h
+++ b/include/envs.h
@@ -6,6 +6,7 @@ static char *afl_environment_deprecated[] = {
 
     "AFL_LLVM_WHITELIST",
     "AFL_GCC_WHITELIST",
+    "AFL_DEBUG_CHILD_OUTPUT",
     "AFL_DEFER_FORKSRV",
     "AFL_POST_LIBRARY",
     "AFL_PERSISTENT",
@@ -36,7 +37,7 @@ static char *afl_environment_variables[] = {
     "AFL_CXX",
     "AFL_CYCLE_SCHEDULES",
     "AFL_DEBUG",
-    "AFL_DEBUG_CHILD_OUTPUT",
+    "AFL_DEBUG_CHILD",
     "AFL_DEBUG_GDB",
     "AFL_DISABLE_TRIM",
     "AFL_DONT_OPTIMIZE",
diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc
index b3c55108..e85f9cd3 100644
--- a/instrumentation/SanitizerCoveragePCGUARD.so.cc
+++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc
@@ -544,7 +544,9 @@ bool ModuleSanitizerCoverage::instrumentModule(
     be_quiet = 1;
 
   skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
-  // scanForDangerousFunctions(&M);
+
+  initInstrumentList();
+  scanForDangerousFunctions(&M);
 
   if (debug) {
 
@@ -819,6 +821,8 @@ void ModuleSanitizerCoverage::instrumentFunction(
     Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
 
   if (F.empty()) return;
+  if (!isInInstrumentList(&F)) return;
+
   if (F.getName().find(".module_ctor") != std::string::npos)
     return;  // Should not instrument sanitizer init functions.
   if (F.getName().startswith("__sanitizer_"))
@@ -1315,6 +1319,7 @@ std::string ModuleSanitizerCoverage::getSectionEnd(
 }
 
 char ModuleSanitizerCoverageLegacyPass::ID = 0;
+
 INITIALIZE_PASS_BEGIN(ModuleSanitizerCoverageLegacyPass, "sancov",
                       "Pass for instrumenting coverage on functions", false,
                       false)
@@ -1323,6 +1328,7 @@ INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
 INITIALIZE_PASS_END(ModuleSanitizerCoverageLegacyPass, "sancov",
                     "Pass for instrumenting coverage on functions", false,
                     false)
+
 ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass(
     const SanitizerCoverageOptions &Options,
     const std::vector<std::string> &AllowlistFiles,
diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c
index f38af668..485f500c 100644
--- a/instrumentation/afl-compiler-rt.o.c
+++ b/instrumentation/afl-compiler-rt.o.c
@@ -123,7 +123,7 @@ void __afl_trace(const u32 x) {
   u8 c = __builtin_add_overflow(*p, 1, p);
   *p += c;
   #else
-  *p += 1 + ((u8)(1 + *p == 0);
+  *p += 1 + ((u8)(1 + *p) == 0);
   #endif
 #else
   ++*p;
@@ -182,7 +182,7 @@ static void __afl_map_shm_fuzz() {
 
     if (!map || map == (void *)-1) {
 
-      perror("Could not access fuzzign shared memory");
+      perror("Could not access fuzzing shared memory");
       exit(1);
 
     }
@@ -992,7 +992,7 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
   // For stability analysis, if you want to know to which function unstable
   // edge IDs belong - uncomment, recompile+install llvm_mode, recompile
   // the target. libunwind and libbacktrace are better solutions.
-  // Set AFL_DEBUG_CHILD_OUTPUT=1 and run afl-fuzz with 2>file to capture
+  // Set AFL_DEBUG_CHILD=1 and run afl-fuzz with 2>file to capture
   // the backtrace output
   /*
   uint32_t unstable[] = { ... unstable edge IDs };
diff --git a/qemu_mode/QEMUAFL_VERSION b/qemu_mode/QEMUAFL_VERSION
index 75883247..43403430 100644
--- a/qemu_mode/QEMUAFL_VERSION
+++ b/qemu_mode/QEMUAFL_VERSION
@@ -1 +1 @@
-21ff343837
+d66c9e2654
diff --git a/qemu_mode/libcompcov/pmparser.h b/qemu_mode/libcompcov/pmparser.h
index 9421d47e..0eb4fb1d 100644
--- a/qemu_mode/libcompcov/pmparser.h
+++ b/qemu_mode/libcompcov/pmparser.h
@@ -108,8 +108,7 @@ void pmparser_print(procmaps_struct *map, int order);
 
 procmaps_iterator *pmparser_parse(int pid) {
 
-  procmaps_iterator *maps_it = malloc(sizeof(procmaps_iterator));
-  char               maps_path[500];
+  char maps_path[500];
   if (pid >= 0) {
 
     sprintf(maps_path, "/proc/%d/maps", pid);
@@ -129,8 +128,9 @@ procmaps_iterator *pmparser_parse(int pid) {
 
   }
 
-  int  ind = 0;
-  char buf[PROCMAPS_LINE_MAX_LENGTH];
+  procmaps_iterator *maps_it = malloc(sizeof(procmaps_iterator));
+  int                ind = 0;
+  char               buf[PROCMAPS_LINE_MAX_LENGTH];
   // int c;
   procmaps_struct *list_maps = NULL;
   procmaps_struct *tmp;
diff --git a/src/afl-cc.c b/src/afl-cc.c
index 771a58f5..19dc9a6a 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -49,14 +49,14 @@ static u8 * obj_path;                  /* Path to runtime libraries         */
 static u8 **cc_params;                 /* Parameters passed to the real CC  */
 static u32  cc_par_cnt = 1;            /* Param count, including argv0      */
 static u8   llvm_fullpath[PATH_MAX];
-static u8   instrument_mode, instrument_opt_mode, ngram_size, lto_mode,
-    compiler_mode, plusplus_mode;
-static u8  have_gcc, have_llvm, have_gcc_plugin, have_lto;
-static u8 *lto_flag = AFL_CLANG_FLTO, *argvnull;
-static u8  debug;
-static u8  cwd[4096];
-static u8  cmplog_mode;
-u8         use_stdin;                                              /* dummy */
+static u8   instrument_mode, instrument_opt_mode, ngram_size, lto_mode;
+static u8   compiler_mode, plusplus_mode, have_instr_env = 0;
+static u8   have_gcc, have_llvm, have_gcc_plugin, have_lto, have_instr_list = 0;
+static u8 * lto_flag = AFL_CLANG_FLTO, *argvnull;
+static u8   debug;
+static u8   cwd[4096];
+static u8   cmplog_mode;
+u8          use_stdin;                                             /* dummy */
 // static u8 *march_opt = CFLAGS_OPT;
 
 enum {
@@ -354,19 +354,13 @@ static void edit_params(u32 argc, char **argv, char **envp) {
     if (lto_mode && plusplus_mode)
       cc_params[cc_par_cnt++] = "-lc++";  // needed by fuzzbench, early
 
-    if (lto_mode) {
-
-      if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
-          getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
-          getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) {
-
-        cc_params[cc_par_cnt++] = "-Xclang";
-        cc_params[cc_par_cnt++] = "-load";
-        cc_params[cc_par_cnt++] = "-Xclang";
-        cc_params[cc_par_cnt++] =
-            alloc_printf("%s/afl-llvm-lto-instrumentlist.so", obj_path);
+    if (lto_mode && have_instr_env) {
 
-      }
+      cc_params[cc_par_cnt++] = "-Xclang";
+      cc_params[cc_par_cnt++] = "-load";
+      cc_params[cc_par_cnt++] = "-Xclang";
+      cc_params[cc_par_cnt++] =
+          alloc_printf("%s/afl-llvm-lto-instrumentlist.so", obj_path);
 
     }
 
@@ -508,11 +502,25 @@ static void edit_params(u32 argc, char **argv, char **envp) {
       if (instrument_mode == INSTRUMENT_PCGUARD) {
 
 #if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
-        cc_params[cc_par_cnt++] = "-Xclang";
-        cc_params[cc_par_cnt++] = "-load";
-        cc_params[cc_par_cnt++] = "-Xclang";
-        cc_params[cc_par_cnt++] =
-            alloc_printf("%s/SanitizerCoveragePCGUARD.so", obj_path);
+        if (have_instr_list) {
+
+          if (!be_quiet)
+            SAYF(
+                "Using unoptimized trace-pc-guard, due usage of "
+                "-fsanitize-coverage-allow/denylist, you can use "
+                "AFL_LLVM_ALLOWLIST/AFL_LLMV_DENYLIST instead.\n");
+          cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
+
+        } else {
+
+          cc_params[cc_par_cnt++] = "-Xclang";
+          cc_params[cc_par_cnt++] = "-load";
+          cc_params[cc_par_cnt++] = "-Xclang";
+          cc_params[cc_par_cnt++] =
+              alloc_printf("%s/SanitizerCoveragePCGUARD.so", obj_path);
+
+        }
+
 #else
   #if LLVM_MAJOR >= 4
         if (!be_quiet)
@@ -590,6 +598,9 @@ static void edit_params(u32 argc, char **argv, char **envp) {
     if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32;
     if (!strcmp(cur, "-m64")) bit_mode = 64;
 
+    if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list="))
+      have_instr_list = 1;
+
     if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
       asan_set = 1;
 
@@ -826,7 +837,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
     }
 
-  #ifndef __APPLE__
+  #if !defined(__APPLE__) && !defined(__sun)
     if (!shared_linking)
       cc_params[cc_par_cnt++] =
           alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path);
@@ -856,6 +867,14 @@ int main(int argc, char **argv, char **envp) {
 
     be_quiet = 1;
 
+  if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST") ||
+      getenv("AFL_LLVM_ALLOWLIST") || getenv("AFL_LLVM_DENYLIST") ||
+      getenv("AFL_LLVM_BLOCKLIST")) {
+
+    have_instr_env = 1;
+
+  }
+
   if ((ptr = strrchr(callname, '/')) != NULL) callname = ptr + 1;
   argvnull = (u8 *)argv[0];
   check_environment_vars(envp);
@@ -1015,14 +1034,14 @@ int main(int argc, char **argv, char **envp) {
 
   }
 
-  if ((getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
-       getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
-       getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) &&
-      getenv("AFL_DONT_OPTIMIZE"))
+  if (have_instr_env && getenv("AFL_DONT_OPTIMIZE")) {
+
     WARNF(
         "AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined "
         "for file matching, only function matching!");
 
+  }
+
   if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") ||
       getenv("INSTRIM_LIB")) {
 
@@ -1307,15 +1326,20 @@ int main(int argc, char **argv, char **envp) {
             "  AFL_GCC_INSTRUMENT_FILE: enable selective instrumentation by "
             "filename\n");
 
+#if LLVM_MAJOR < 9
+  #define COUNTER_BEHAVIOUR \
+    "  AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n"
+#else
+  #define COUNTER_BEHAVIOUR \
+    "  AFL_LLVM_SKIP_NEVERZERO: do not skip zero on trace counters\n"
+#endif
       if (have_llvm)
         SAYF(
             "\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment "
             "variables:\n"
-#if LLVM_MAJOR < 9
-            "  AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n"
-#else
-            "  AFL_LLVM_SKIP_NEVERZERO: do not skip zero on trace counters\n"
-#endif
+
+            COUNTER_BEHAVIOUR
+
             "  AFL_LLVM_DICT2FILE: generate an afl dictionary based on found "
             "comparisons\n"
             "  AFL_LLVM_LAF_ALL: enables all LAF splits/transforms\n"
@@ -1426,22 +1450,20 @@ int main(int argc, char **argv, char **envp) {
 #if LLVM_MAJOR <= 6
     instrument_mode = INSTRUMENT_AFL;
 #else
-    if (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
-        getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
-        getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")) {
+  #if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
+    if (have_instr_env) {
 
       instrument_mode = INSTRUMENT_AFL;
-      WARNF(
-          "switching to classic instrumentation because "
-          "AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD. Use "
-          "-fsanitize-coverage-allowlist=allowlist.txt or "
-          "-fsanitize-coverage-blocklist=denylist.txt if you want to use "
-          "PCGUARD. Requires llvm 12+. See https://clang.llvm.org/docs/ "
-          "SanitizerCoverage.html#partially-disabling-instrumentation");
+      if (!be_quiet)
+        WARNF(
+            "Switching to classic instrumentation because "
+            "AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD < 10.0.1.");
 
     } else
 
+  #endif
       instrument_mode = INSTRUMENT_PCGUARD;
+
 #endif
 
   }
@@ -1487,18 +1509,16 @@ int main(int argc, char **argv, char **envp) {
         "AFL_LLVM_NOT_ZERO and AFL_LLVM_SKIP_NEVERZERO can not be set "
         "together");
 
-  if (instrument_mode == INSTRUMENT_PCGUARD &&
-      (getenv("AFL_LLVM_INSTRUMENT_FILE") != NULL ||
-       getenv("AFL_LLVM_WHITELIST") || getenv("AFL_LLVM_ALLOWLIST") ||
-       getenv("AFL_LLVM_DENYLIST") || getenv("AFL_LLVM_BLOCKLIST")))
+#if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
+  if (instrument_mode == INSTRUMENT_PCGUARD && have_instr_env) {
+
     FATAL(
         "Instrumentation type PCGUARD does not support "
-        "AFL_LLVM_ALLOWLIST/DENYLIST! Use "
-        "-fsanitize-coverage-allowlist=allowlist.txt or "
-        "-fsanitize-coverage-blocklist=denylist.txt instead (requires llvm "
-        "12+), see "
-        "https://clang.llvm.org/docs/"
-        "SanitizerCoverage.html#partially-disabling-instrumentation");
+        "AFL_LLVM_ALLOWLIST/DENYLIST! Use LLVM 10.0.1+ instead.");
+
+  }
+
+#endif
 
   u8 *ptr2;
 
diff --git a/src/afl-common.c b/src/afl-common.c
index 19c9419b..8cf1a444 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -342,7 +342,7 @@ u8 *find_binary(u8 *fname) {
     if (stat(target_path, &st) || !S_ISREG(st.st_mode) ||
         !(st.st_mode & 0111) || st.st_size < 4) {
 
-      free(target_path);
+      ck_free(target_path);
       FATAL("Program '%s' not found or not executable", fname);
 
     }
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 45be2abd..3814a77e 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -116,7 +116,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
   fsrv_to->use_fauxsrv = 0;
   fsrv_to->last_run_timed_out = 0;
 
-  fsrv_to->init_child_func = fsrv_exec_child;
+  fsrv_to->init_child_func = from->init_child_func;
   // Note: do not copy ->add_extra_func
 
   list_append(&fsrv_list, fsrv_to);
@@ -272,7 +272,8 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
 
       *(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG;
 
-      PFATAL("Execv failed in fauxserver.");
+      WARNF("Execv failed in fauxserver.");
+      break;
 
     }
 
@@ -286,13 +287,13 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
     if (waitpid(child_pid, &status, 0) < 0) {
 
       // Zombie Child could not be collected. Scary!
-      PFATAL("Fauxserver could not determin child's exit code. ");
+      WARNF("Fauxserver could not determine child's exit code. ");
 
     }
 
     /* Relay wait status to AFL pipe, then loop back. */
 
-    if (write(FORKSRV_FD + 1, &status, 4) != 4) { exit(0); }
+    if (write(FORKSRV_FD + 1, &status, 4) != 4) { exit(1); }
 
   }
 
@@ -330,7 +331,7 @@ static void report_error_and_exit(int error) {
           "memory failed.");
       break;
     default:
-      FATAL("unknown error code %u from fuzzing target!", error);
+      FATAL("unknown error code %d from fuzzing target!", error);
 
   }
 
@@ -355,7 +356,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
   if (fsrv->use_fauxsrv) {
 
-    /* TODO: Come up with sone nice way to initialize this all */
+    /* TODO: Come up with some nice way to initialize this all */
 
     if (fsrv->init_child_func != fsrv_exec_child) {
 
@@ -520,7 +521,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
     *(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG;
     fprintf(stderr, "Error: execv to target failed\n");
-    exit(0);
+    exit(1);
 
   }
 
@@ -1137,7 +1138,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
   }
 
   // Fauxserver should handle this now.
-  // if (tb4 == EXEC_FAIL_SIG) return FSRV_RUN_ERROR;
+  if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG) return FSRV_RUN_ERROR;
 
   return FSRV_RUN_OK;
 
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index 735420c3..2d14b04e 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -584,12 +584,39 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
         alloc_printf("%s/queue/id_%06u", afl->out_dir, afl->queued_paths);
 
 #endif                                                    /* ^!SIMPLE_FILES */
-
+    fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
+    if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", queue_fn); }
+    ck_write(fd, mem, len, queue_fn);
+    close(fd);
     add_to_queue(afl, queue_fn, len, 0);
 
 #ifdef INTROSPECTION
-    fprintf(afl->introspection_file, "QUEUE %s = %s\n", afl->mutation,
-            afl->queue_top->fname);
+    if (afl->custom_mutators_count && afl->current_custom_fuzz) {
+
+      LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+        if (afl->current_custom_fuzz == el && el->afl_custom_introspection) {
+
+          const char *ptr = el->afl_custom_introspection(el->data);
+
+          if (ptr != NULL && *ptr != 0) {
+
+            fprintf(afl->introspection_file, "QUEUE CUSTOM %s = %s\n", ptr,
+                    afl->queue_top->fname);
+
+          }
+
+        }
+
+      });
+
+    } else if (afl->mutation[0] != 0) {
+
+      fprintf(afl->introspection_file, "QUEUE %s = %s\n", afl->mutation,
+              afl->queue_top->fname);
+
+    }
+
 #endif
 
     if (hnb == 2) {
@@ -623,11 +650,6 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 
     }
 
-    fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
-    if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", queue_fn); }
-    ck_write(fd, mem, len, queue_fn);
-    close(fd);
-
     if (likely(afl->q_testcase_max_cache_size)) {
 
       queue_testcase_store_mem(afl, afl->queue_top, mem);
@@ -665,7 +687,32 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 
       ++afl->unique_tmouts;
 #ifdef INTROSPECTION
-      fprintf(afl->introspection_file, "UNIQUE_TIMEOUT %s\n", afl->mutation);
+      if (afl->custom_mutators_count && afl->current_custom_fuzz) {
+
+        LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+          if (afl->current_custom_fuzz == el && el->afl_custom_introspection) {
+
+            const char *ptr = el->afl_custom_introspection(el->data);
+
+            if (ptr != NULL && *ptr != 0) {
+
+              fprintf(afl->introspection_file,
+                      "UNIQUE_TIMEOUT CUSTOM %s = %s\n", ptr,
+                      afl->queue_top->fname);
+
+            }
+
+          }
+
+        });
+
+      } else if (afl->mutation[0] != 0) {
+
+        fprintf(afl->introspection_file, "UNIQUE_TIMEOUT %s\n", afl->mutation);
+
+      }
+
 #endif
 
       /* Before saving, we make sure that it's a genuine hang by re-running
@@ -751,7 +798,31 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 
       ++afl->unique_crashes;
 #ifdef INTROSPECTION
-      fprintf(afl->introspection_file, "UNIQUE_CRASH %s\n", afl->mutation);
+      if (afl->custom_mutators_count && afl->current_custom_fuzz) {
+
+        LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+          if (afl->current_custom_fuzz == el && el->afl_custom_introspection) {
+
+            const char *ptr = el->afl_custom_introspection(el->data);
+
+            if (ptr != NULL && *ptr != 0) {
+
+              fprintf(afl->introspection_file, "UNIQUE_CRASH CUSTOM %s = %s\n",
+                      ptr, afl->queue_top->fname);
+
+            }
+
+          }
+
+        });
+
+      } else if (afl->mutation[0] != 0) {
+
+        fprintf(afl->introspection_file, "UNIQUE_CRASH %s\n", afl->mutation);
+
+      }
+
 #endif
       if (unlikely(afl->infoexec)) {
 
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 19a8d77b..0360cdb0 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -355,7 +355,7 @@ void bind_to_free_cpu(afl_state_t *afl) {
 
   if (ncpus > sizeof(cpu_used)) ncpus = sizeof(cpu_used);
 
-  for (i = 0; i < ncpus; i++) {
+  for (i = 0; i < (s32)ncpus; i++) {
 
     k = kstat_lookup(m, "cpu_stat", i, NULL);
     if (kstat_read(m, k, &cs)) {
@@ -2300,12 +2300,6 @@ void fix_up_sync(afl_state_t *afl) {
 
   u8 *x = afl->sync_id;
 
-  if (afl->non_instrumented_mode) {
-
-    FATAL("-S / -M and -n are mutually exclusive");
-
-  }
-
   while (*x) {
 
     if (!isalnum(*x) && *x != '_' && *x != '-') {
@@ -2503,7 +2497,8 @@ void check_binary(afl_state_t *afl, u8 *fname) {
 
   }
 
-  if (afl->afl_env.afl_skip_bin_check || afl->use_wine || afl->unicorn_mode) {
+  if (afl->afl_env.afl_skip_bin_check || afl->use_wine || afl->unicorn_mode ||
+      afl->non_instrumented_mode) {
 
     return;
 
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index c4d7233c..1d14f657 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -166,6 +166,13 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
 
   }
 
+  /* "afl_custom_introspection", optional */
+#ifdef INTROSPECTION
+  mutator->afl_custom_introspection = dlsym(dh, "afl_custom_introspection");
+  if (!mutator->afl_custom_introspection)
+    ACTF("optional symbol 'afl_custom_introspection' not found.");
+#endif
+
   /* "afl_custom_fuzz_count", optional */
   mutator->afl_custom_fuzz_count = dlsym(dh, "afl_custom_fuzz_count");
   if (!mutator->afl_custom_fuzz_count)
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index 91bbced6..0adc3719 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -1780,10 +1780,16 @@ custom_mutator_stage:
 
   orig_hit_cnt = afl->queued_paths + afl->unique_crashes;
 
+#ifdef INTROSPECTION
+  afl->mutation[0] = 0;
+#endif
+
   LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
 
     if (el->afl_custom_fuzz) {
 
+      afl->current_custom_fuzz = el;
+
       if (el->afl_custom_fuzz_count)
         afl->stage_max = el->afl_custom_fuzz_count(el->data, out_buf, len);
       else
@@ -1840,12 +1846,6 @@ custom_mutator_stage:
 
           if (mutated_size > 0) {
 
-#ifdef INTROSPECTION
-            snprintf(afl->mutation, sizeof(afl->mutation), "%s CUSTOM-%s",
-                     afl->queue_cur->fname,
-                     target != NULL ? (char *)target->fname : "none");
-#endif
-
             if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) {
 
               goto abandon_entry;
@@ -1889,6 +1889,8 @@ custom_mutator_stage:
 
   });
 
+  afl->current_custom_fuzz = NULL;
+
   if (!has_custom_fuzz) goto havoc_stage;
 
   new_hit_cnt = afl->queued_paths + afl->unique_crashes;
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
index adb92649..9ac4403b 100644
--- a/src/afl-fuzz-python.c
+++ b/src/afl-fuzz-python.c
@@ -96,7 +96,7 @@ static size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf,
     mutated_size = PyByteArray_Size(py_value);
 
     *out_buf = afl_realloc(BUF_PARAMS(fuzz), mutated_size);
-    if (unlikely(!out_buf)) { PFATAL("alloc"); }
+    if (unlikely(!*out_buf)) { PFATAL("alloc"); }
 
     memcpy(*out_buf, PyByteArray_AsString(py_value), mutated_size);
     Py_DECREF(py_value);
@@ -134,6 +134,18 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
   PyObject * py_module = py->py_module;
   PyObject **py_functions = py->py_functions;
 
+  // initialize the post process buffer; ensures it's always valid
+  PyObject *unused_bytes = PyByteArray_FromStringAndSize("OHAI", 4);
+  if (!unused_bytes) { FATAL("allocation failed!"); }
+  if (PyObject_GetBuffer(unused_bytes, &py->post_process_buf, PyBUF_SIMPLE) ==
+      -1) {
+
+    FATAL("buffer initialization failed");
+
+  }
+
+  Py_DECREF(unused_bytes);
+
   if (py_module != NULL) {
 
     u8 py_notrim = 0, py_idx;
@@ -163,6 +175,8 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
         PyObject_GetAttrString(py_module, "queue_get");
     py_functions[PY_FUNC_QUEUE_NEW_ENTRY] =
         PyObject_GetAttrString(py_module, "queue_new_entry");
+    py_functions[PY_FUNC_INTROSPECTION] =
+        PyObject_GetAttrString(py_module, "introspection");
     py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit");
     if (!py_functions[PY_FUNC_DEINIT])
       FATAL("deinit function not found in python module");
@@ -212,6 +226,7 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
 
     PyErr_Print();
     fprintf(stderr, "Failed to load \"%s\"\n", module_name);
+    free(py);
     return NULL;
 
   }
@@ -310,7 +325,6 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
   struct custom_mutator *mutator;
 
   mutator = ck_alloc(sizeof(struct custom_mutator));
-  mutator->post_process_buf = NULL;
 
   mutator->name = module_name;
   ACTF("Loading Python mutator library from '%s'...", module_name);
@@ -326,9 +340,7 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
 
   if (py_functions[PY_FUNC_DEINIT]) { mutator->afl_custom_deinit = deinit_py; }
 
-  /* "afl_custom_fuzz" should not be NULL, but the interface of Python mutator
-     is quite different from the custom mutator. */
-  mutator->afl_custom_fuzz = fuzz_py;
+  if (py_functions[PY_FUNC_FUZZ]) { mutator->afl_custom_fuzz = fuzz_py; }
 
   if (py_functions[PY_FUNC_POST_PROCESS]) {
 
@@ -381,6 +393,15 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
 
   }
 
+  #ifdef INTROSPECTION
+  if (py_functions[PY_FUNC_INTROSPECTION]) {
+
+    mutator->afl_custom_introspection = introspection_py;
+
+  }
+
+  #endif
+
   OKF("Python mutator '%s' installed successfully.", module_name);
 
   /* Initialize the custom mutator */
@@ -393,10 +414,13 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
 size_t post_process_py(void *py_mutator, u8 *buf, size_t buf_size,
                        u8 **out_buf) {
 
-  size_t        py_out_buf_size;
   PyObject *    py_args, *py_value;
   py_mutator_t *py = (py_mutator_t *)py_mutator;
 
+  // buffer returned previously must be released; initialized during init
+  // so we don't need to do comparisons
+  PyBuffer_Release(&py->post_process_buf);
+
   py_args = PyTuple_New(1);
   py_value = PyByteArray_FromStringAndSize(buf, buf_size);
   if (!py_value) {
@@ -416,20 +440,20 @@ size_t post_process_py(void *py_mutator, u8 *buf, size_t buf_size,
 
   if (py_value != NULL) {
 
-    py_out_buf_size = PyByteArray_Size(py_value);
-
-    if (unlikely(!afl_realloc(BUF_PARAMS(post_process), py_out_buf_size))) {
+    if (PyObject_GetBuffer(py_value, &py->post_process_buf, PyBUF_SIMPLE) ==
+        -1) {
 
-      PFATAL("alloc");
+      PyErr_Print();
+      FATAL(
+          "Python custom mutator: post_process call return value not a "
+          "bytes-like object");
 
     }
 
-    memcpy(py->post_process_buf, PyByteArray_AsString(py_value),
-           py_out_buf_size);
     Py_DECREF(py_value);
 
-    *out_buf = py->post_process_buf;
-    return py_out_buf_size;
+    *out_buf = (u8 *)py->post_process_buf.buf;
+    return py->post_process_buf.len;
 
   } else {
 
@@ -569,7 +593,7 @@ size_t trim_py(void *py_mutator, u8 **out_buf) {
 
     ret = PyByteArray_Size(py_value);
     *out_buf = afl_realloc(BUF_PARAMS(trim), ret);
-    if (unlikely(!out_buf)) { PFATAL("alloc"); }
+    if (unlikely(!*out_buf)) { PFATAL("alloc"); }
     memcpy(*out_buf, PyByteArray_AsString(py_value), ret);
     Py_DECREF(py_value);
 
@@ -635,7 +659,7 @@ size_t havoc_mutation_py(void *py_mutator, u8 *buf, size_t buf_size,
 
       /* A new buf is needed... */
       *out_buf = afl_realloc(BUF_PARAMS(havoc), mutated_size);
-      if (unlikely(!out_buf)) { PFATAL("alloc"); }
+      if (unlikely(!*out_buf)) { PFATAL("alloc"); }
 
     }
 
@@ -679,6 +703,28 @@ u8 havoc_mutation_probability_py(void *py_mutator) {
 
 }
 
+const char *introspection_py(void *py_mutator) {
+
+  PyObject *py_args, *py_value;
+
+  py_args = PyTuple_New(0);
+  py_value = PyObject_CallObject(
+      ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_INTROSPECTION],
+      py_args);
+  Py_DECREF(py_args);
+
+  if (py_value == NULL) {
+
+    return NULL;
+
+  } else {
+
+    return PyByteArray_AsString(py_value);
+
+  }
+
+}
+
 u8 queue_get_py(void *py_mutator, const u8 *filename) {
 
   PyObject *py_args, *py_value;
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index c78df8be..f35b4f57 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -56,7 +56,12 @@ void create_alias_table(afl_state_t *afl) {
   int *   S = (u32 *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32));
   int *   L = (u32 *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32));
 
-  if (!P || !S || !L) { FATAL("could not aquire memory for alias table"); }
+  if (!P || !S || !L || !afl->alias_table || !afl->alias_probability) {
+
+    FATAL("could not acquire memory for alias table");
+
+  }
+
   memset((void *)afl->alias_table, 0, n * sizeof(u32));
   memset((void *)afl->alias_probability, 0, n * sizeof(double));
 
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index e969994d..95b3ee8a 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -332,7 +332,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
     }
 
     afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
-                   afl->afl_env.afl_debug_child_output);
+                   afl->afl_env.afl_debug_child);
 
     if (afl->fsrv.support_shmem_fuzz && !afl->fsrv.use_shmem_fuzz) {
 
@@ -590,7 +590,7 @@ void sync_fuzzers(afl_state_t *afl) {
 
     while (m < n) {
 
-      if (strcmp(namelist[m]->d_name, entry)) {
+      if (strncmp(namelist[m]->d_name, entry, 9)) {
 
         m++;
 
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index 61bd06b7..489d4e53 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -268,11 +268,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
             afl->afl_env.afl_bench_until_crash =
                 get_afl_env(afl_environment_variables[i]) ? 1 : 0;
 
-          } else if (!strncmp(env, "AFL_DEBUG_CHILD_OUTPUT",
+          } else if (!strncmp(env, "AFL_DEBUG_CHILD",
 
+                              afl_environment_variable_len) ||
+                     !strncmp(env, "AFL_DEBUG_CHILD_OUTPUT",
                               afl_environment_variable_len)) {
 
-            afl->afl_env.afl_debug_child_output =
+            afl->afl_env.afl_debug_child =
                 get_afl_env(afl_environment_variables[i]) ? 1 : 0;
 
           } else if (!strncmp(env, "AFL_AUTORESUME",
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 269ce1bf..1008f28c 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -166,7 +166,7 @@ static void usage(u8 *argv0, int more_help) {
       "AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n"
       "AFL_CYCLE_SCHEDULES: after completing a cycle, switch to a different -p schedule\n"
       "AFL_DEBUG: extra debugging output for Python mode trimming\n"
-      "AFL_DEBUG_CHILD_OUTPUT: do not suppress stdout/stderr from target\n"
+      "AFL_DEBUG_CHILD: do not suppress stdout/stderr from target\n"
       "AFL_DISABLE_TRIM: disable the trimming of test cases\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"
@@ -350,6 +350,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
       case 's': {
 
+        if (optarg == NULL) { FATAL("No valid seed provided. Got NULL."); }
         rand_set_seed(afl, strtoul(optarg, 0L, 10));
         afl->fixed_seed = 1;
         break;
@@ -419,6 +420,7 @@ int main(int argc, char **argv_orig, char **envp) {
       case 'i':                                                /* input dir */
 
         if (afl->in_dir) { FATAL("Multiple -i options not supported"); }
+        if (optarg == NULL) { FATAL("Invalid -i option (got NULL)."); }
         afl->in_dir = optarg;
 
         if (!strcmp(afl->in_dir, "-")) { afl->in_place_resume = 1; }
@@ -435,9 +437,26 @@ int main(int argc, char **argv_orig, char **envp) {
 
         u8 *c;
 
+        if (afl->non_instrumented_mode) {
+
+          FATAL("-M is not supported in non-instrumented mode");
+
+        }
+
         if (afl->sync_id) { FATAL("Multiple -S or -M options not supported"); }
+
+        /* sanity check for argument: should not begin with '-' (possible
+         * option) */
+        if (optarg && *optarg == '-') {
+
+          FATAL(
+              "argument for -M started with a dash '-', which is used for "
+              "options");
+
+        }
+
         afl->sync_id = ck_strdup(optarg);
-        afl->skip_deterministic = 0;  // force determinsitic fuzzing
+        afl->skip_deterministic = 0;  // force deterministic fuzzing
         afl->old_seed_selection = 1;  // force old queue walking seed selection
 
         if ((c = strchr(afl->sync_id, ':'))) {
@@ -464,7 +483,24 @@ int main(int argc, char **argv_orig, char **envp) {
 
       case 'S':                                        /* secondary sync id */
 
+        if (afl->non_instrumented_mode) {
+
+          FATAL("-S is not supported in non-instrumented mode");
+
+        }
+
         if (afl->sync_id) { FATAL("Multiple -S or -M options not supported"); }
+
+        /* sanity check for argument: should not begin with '-' (possible
+         * option) */
+        if (optarg && *optarg == '-') {
+
+          FATAL(
+              "argument for -M started with a dash '-', which is used for "
+              "options");
+
+        }
+
         afl->sync_id = ck_strdup(optarg);
         afl->is_secondary_node = 1;
         break;
@@ -620,6 +656,12 @@ int main(int argc, char **argv_orig, char **envp) {
 
       case 'n':                                                /* dumb mode */
 
+        if (afl->is_main_node || afl->is_secondary_node) {
+
+          FATAL("Non instrumented mode is not supported with -M / -S");
+
+        }
+
         if (afl->non_instrumented_mode) {
 
           FATAL("Multiple -n options not supported");
@@ -906,7 +948,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   afl->power_name = power_names[afl->schedule];
 
-  if (!afl->sync_id) {
+  if (!afl->non_instrumented_mode && !afl->sync_id) {
 
     auto_sync = 1;
     afl->sync_id = ck_strdup("default");
@@ -1338,7 +1380,11 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
-    if (!afl->fsrv.qemu_mode) { check_binary(afl, afl->cmplog_binary); }
+    if (!afl->fsrv.qemu_mode && !afl->non_instrumented_mode) {
+
+      check_binary(afl, afl->cmplog_binary);
+
+    }
 
   }
 
@@ -1380,7 +1426,7 @@ int main(int argc, char **argv_orig, char **envp) {
     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);
+                   afl->afl_env.afl_debug_child);
     OKF("Cmplog forkserver successfully started");
 
   }
diff --git a/src/afl-gotcpu.c b/src/afl-gotcpu.c
index bd0f7de6..1aea3e40 100644
--- a/src/afl-gotcpu.c
+++ b/src/afl-gotcpu.c
@@ -65,7 +65,6 @@
     #define cpu_set_t cpuset_t
   #elif defined(__NetBSD__)
     #include <pthread.h>
-    #include <sched.h>
   #elif defined(__APPLE__)
     #include <pthread.h>
     #include <mach/thread_act.h>
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index 4b357254..69527007 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -1091,7 +1091,11 @@ int main(int argc, char **argv_orig, char **envp) {
     }
 
     afl_fsrv_start(fsrv, use_argv, &stop_soon,
-                   get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0);
+                   (get_afl_env("AFL_DEBUG_CHILD") ||
+                    get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
+                       ? 1
+                       : 0);
+
     map_size = fsrv->map_size;
 
     if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index 06037d61..e4fb068d 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -1141,8 +1141,11 @@ int main(int argc, char **argv_orig, char **envp) {
 
   read_initial_file();
 
-  afl_fsrv_start(fsrv, use_argv, &stop_soon,
-                 get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0);
+  afl_fsrv_start(
+      fsrv, use_argv, &stop_soon,
+      (get_afl_env("AFL_DEBUG_CHILD") || get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
+          ? 1
+          : 0);
 
   if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
     shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
diff --git a/test/test-unicorn-mode.sh b/test/test-unicorn-mode.sh
index 7ac4cdd2..b4c6eb3e 100755
--- a/test/test-unicorn-mode.sh
+++ b/test/test-unicorn-mode.sh
@@ -7,7 +7,7 @@ test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/samples/shel
   test -e ../unicorn_mode/samples/simple/simple_target.bin -a -e ../unicorn_mode/samples/compcov_x64/compcov_target.bin && {
     {
       # We want to see python errors etc. in logs, in case something doesn't work
-      export AFL_DEBUG_CHILD_OUTPUT=1
+      export AFL_DEBUG_CHILD=1
 
       # some python version should be available now
       PYTHONS="`command -v python3` `command -v python` `command -v python2`"
@@ -34,7 +34,7 @@ test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/samples/shel
       cd ../unicorn_mode/samples/persistent
       make >>errors 2>&1
       $ECHO "$GREY[*] running afl-fuzz for unicorn_mode (persistent), this will take approx 25 seconds"
-      AFL_DEBUG_CHILD_OUTPUT=1 ../../../afl-fuzz -m none -V25 -U -i sample_inputs -o out -d -- ./harness @@ >>errors 2>&1
+      AFL_DEBUG_CHILD=1 ../../../afl-fuzz -m none -V25 -U -i sample_inputs -o out -d -- ./harness @@ >>errors 2>&1
       test -n "$( ls out/default/queue/id:000002* 2>/dev/null )" && {
         $ECHO "$GREEN[+] afl-fuzz is working correctly with unicorn_mode (persistent)"
       } || {
@@ -96,7 +96,7 @@ test -d ../unicorn_mode/unicornafl -a -e ../unicorn_mode/unicornafl/samples/shel
       }
       fi
 
-      unset AFL_DEBUG_CHILD_OUTPUT
+      unset AFL_DEBUG_CHILD
 
     }
   } || {
diff --git a/unicorn_mode/samples/persistent/simple_target_noncrashing.c b/unicorn_mode/samples/persistent/simple_target_noncrashing.c
index 00764473..9257643b 100644
--- a/unicorn_mode/samples/persistent/simple_target_noncrashing.c
+++ b/unicorn_mode/samples/persistent/simple_target_noncrashing.c
@@ -10,7 +10,7 @@
  * Written by Nathan Voss <njvoss99@gmail.com>
  * Adapted by Lukas Seidel <seidel.1@campus.tu-berlin.de>
  */
-
+#include <string.h>
 
 int main(int argc, char** argv) {
   if(argc < 2){
@@ -19,15 +19,19 @@ int main(int argc, char** argv) {
 
   char *data_buf = argv[1];
 
-  if len(data_buf < 20) {
-  if (data_buf[20] != 0) {
+  if (strlen(data_buf) >= 21 && data_buf[20] != 0) {
     printf("Not crashing");
-  } else if (data_buf[0] > 0x10 && data_buf[0] < 0x20 && data_buf[1] > data_buf[2]) {
+  } else if (strlen(data_buf) > 1
+             && data_buf[0] > 0x10 && data_buf[0] < 0x20 && data_buf[1] > data_buf[2]) {
     printf("Also not crashing with databuf[0] == %c", data_buf[0])
-  } else if (data_buf[9] == 0x00 && data_buf[10] != 0x00 && data_buf[11] == 0x00) {
+  }
+#if 0
+  // not possible with argv (zero terminated strings) (hexcoder-)
+  // do not try to access data_buf[10] and beyond
+  else if (data_buf[9] == 0x00 && data_buf[10] != 0x00 && data_buf[11] == 0x00) {
     // Cause a crash if data[10] is not zero, but [9] and [11] are zero
     unsigned char invalid_read = *(unsigned char *) 0x00000000;
   }
-
+#endif
   return 0;
 }
diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl
-Subproject 0bf26f6c2601e1c1c84998551ed7d50b4108fbd
+Subproject f44ec48f8d5929f243522c1152b5b3c0985a554