about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/afl-analyze.c4
-rw-r--r--src/afl-as.c2
-rw-r--r--src/afl-cc.c267
-rw-r--r--src/afl-common.c4
-rw-r--r--src/afl-forkserver.c163
-rw-r--r--src/afl-fuzz-bitmap.c75
-rw-r--r--src/afl-fuzz-init.c27
-rw-r--r--src/afl-fuzz-mutators.c80
-rw-r--r--src/afl-fuzz-one.c18
-rw-r--r--src/afl-fuzz-python.c39
-rw-r--r--src/afl-fuzz-queue.c86
-rw-r--r--src/afl-fuzz-run.c5
-rw-r--r--src/afl-fuzz-state.c9
-rw-r--r--src/afl-fuzz.c46
-rw-r--r--src/afl-ld-lto.c18
-rw-r--r--src/afl-sharedmem.c28
-rw-r--r--src/afl-showmap.c29
-rw-r--r--src/afl-tmin.c32
18 files changed, 676 insertions, 256 deletions
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index c8acebb3..2780deff 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -78,9 +78,9 @@ static u64 mem_limit = MEM_LIMIT;      /* Memory limit (MB)                 */
 
 static s32 dev_null_fd = -1;           /* FD to /dev/null                   */
 
-static u8 edges_only,                  /* Ignore hit counts?                */
+static bool edges_only,                  /* Ignore hit counts?              */
     use_hex_offsets,                   /* Show hex offsets?                 */
-    use_stdin = 1;                     /* Use stdin for program input?      */
+    use_stdin = true;                     /* Use stdin for program input?   */
 
 static volatile u8 stop_soon,          /* Ctrl-C pressed?                   */
     child_timed_out;                   /* Child timed out?                  */
diff --git a/src/afl-as.c b/src/afl-as.c
index 7d70bfcd..3d6f7d5e 100644
--- a/src/afl-as.c
+++ b/src/afl-as.c
@@ -27,7 +27,7 @@
    utility has right now is to be able to skip them gracefully and allow the
    compilation process to continue.
 
-   That said, see examples/clang_asm_normalize/ for a solution that may
+   That said, see utils/clang_asm_normalize/ for a solution that may
    allow clang users to make things work even with hand-crafted assembly. Just
    note that there is no equivalent for GCC.
 
diff --git a/src/afl-cc.c b/src/afl-cc.c
index 19dc9a6a..c43ac2c1 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -48,6 +48,7 @@
 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   clang_mode;                /* Invoked as afl-clang*?            */
 static u8   llvm_fullpath[PATH_MAX];
 static u8   instrument_mode, instrument_opt_mode, ngram_size, lto_mode;
 static u8   compiler_mode, plusplus_mode, have_instr_env = 0;
@@ -105,7 +106,24 @@ u8 *getthecwd() {
 
 }
 
-/* Try to find the runtime libraries. If that fails, abort. */
+/* Try to find a specific runtime we need, returns NULL on fail. */
+
+/*
+  in find_object() we look here:
+
+  1. if obj_path is already set we look there first
+  2. then we check the $AFL_PATH environment variable location if set
+  3. next we check argv[0] if it has path information and use it
+    a) we also check ../lib/afl
+  4. if 3. failed we check /proc (only Linux, Android, NetBSD, DragonFly, and
+     FreeBSD with procfs)
+    a) and check here in ../lib/afl too
+  5. we look into the AFL_PATH define (usually /usr/local/lib/afl)
+  6. we finally try the current directory
+
+  if all these attempts fail - we return NULL and the caller has to decide
+  what to do.
+*/
 
 static u8 *find_object(u8 *obj, u8 *argv0) {
 
@@ -114,11 +132,9 @@ static u8 *find_object(u8 *obj, u8 *argv0) {
 
   if (afl_path) {
 
-#ifdef __ANDROID__
     tmp = alloc_printf("%s/%s", afl_path, obj);
-#else
-    tmp = alloc_printf("%s/%s", afl_path, obj);
-#endif
+
+    if (debug) DEBUGF("Trying %s\n", tmp);
 
     if (!access(tmp, R_OK)) {
 
@@ -131,125 +147,139 @@ static u8 *find_object(u8 *obj, u8 *argv0) {
 
   }
 
-  if (argv0) slash = strrchr(argv0, '/');
+  if (argv0) {
 
-  if (slash) {
+    slash = strrchr(argv0, '/');
 
-    u8 *dir;
+    if (slash) {
 
-    *slash = 0;
-    dir = ck_strdup(argv0);
-    *slash = '/';
+      u8 *dir = ck_strdup(argv0);
 
-#ifdef __ANDROID__
-    tmp = alloc_printf("%s/%s", dir, obj);
-#else
-    tmp = alloc_printf("%s/%s", dir, obj);
-#endif
+      slash = strrchr(dir, '/');
+      *slash = 0;
 
-    if (!access(tmp, R_OK)) {
+      tmp = alloc_printf("%s/%s", dir, obj);
 
-      obj_path = dir;
-      return tmp;
-
-    }
+      if (debug) DEBUGF("Trying %s\n", tmp);
 
-    ck_free(tmp);
-    ck_free(dir);
+      if (!access(tmp, R_OK)) {
 
-  }
+        obj_path = dir;
+        return tmp;
 
-  tmp = alloc_printf("%s/%s", AFL_PATH, obj);
-#ifdef __ANDROID__
-  if (!access(tmp, R_OK)) {
+      }
 
-#else
-  if (!access(tmp, R_OK)) {
+      ck_free(tmp);
+      tmp = alloc_printf("%s/../lib/afl/%s", dir, obj);
 
-#endif
+      if (debug) DEBUGF("Trying %s\n", tmp);
 
-    obj_path = AFL_PATH;
-    return tmp;
+      if (!access(tmp, R_OK)) {
 
-  }
+        u8 *dir2 = alloc_printf("%s/../lib/afl", dir);
+        obj_path = dir2;
+        ck_free(dir);
+        return tmp;
 
-  ck_free(tmp);
-  return NULL;
+      }
 
-}
+      ck_free(tmp);
+      ck_free(dir);
 
-/* Try to find the runtime libraries. If that fails, abort. */
+    }
 
-static void find_obj(u8 *argv0) {
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__linux__) || \
+    defined(__ANDROID__) || defined(__NetBSD__)
+  #define HAS_PROC_FS 1
+#endif
+#ifdef HAS_PROC_FS
+    else {
+
+      char *procname = NULL;
+  #if defined(__FreeBSD__) || defined(__DragonFly__)
+      procname = "/proc/curproc/file";
+  #elif defined(__linux__) || defined(__ANDROID__)
+      procname = "/proc/self/exe";
+  #elif defined(__NetBSD__)
+      procname = "/proc/curproc/exe";
+  #endif
+      if (procname) {
 
-  u8 *afl_path = getenv("AFL_PATH");
-  u8 *slash, *tmp;
+        char    exepath[PATH_MAX];
+        ssize_t exepath_len = readlink(procname, exepath, sizeof(exepath));
+        if (exepath_len > 0 && exepath_len < PATH_MAX) {
 
-  if (afl_path) {
+          exepath[exepath_len] = 0;
+          slash = strrchr(exepath, '/');
 
-#ifdef __ANDROID__
-    tmp = alloc_printf("%s/afl-compiler-rt.so", afl_path);
-#else
-    tmp = alloc_printf("%s/afl-compiler-rt.o", afl_path);
-#endif
+          if (slash) {
 
-    if (!access(tmp, R_OK)) {
+            *slash = 0;
+            tmp = alloc_printf("%s/%s", exepath, obj);
 
-      obj_path = afl_path;
-      ck_free(tmp);
-      return;
+            if (!access(tmp, R_OK)) {
 
-    }
+              u8 *dir = alloc_printf("%s", exepath);
+              obj_path = dir;
+              return tmp;
 
-    ck_free(tmp);
+            }
 
-  }
+            ck_free(tmp);
+            tmp = alloc_printf("%s/../lib/afl/%s", exepath, obj);
 
-  slash = strrchr(argv0, '/');
+            if (debug) DEBUGF("Trying %s\n", tmp);
 
-  if (slash) {
+            if (!access(tmp, R_OK)) {
 
-    u8 *dir;
+              u8 *dir = alloc_printf("%s/../lib/afl/", exepath);
+              obj_path = dir;
+              return tmp;
 
-    *slash = 0;
-    dir = ck_strdup(argv0);
-    *slash = '/';
+            }
 
-#ifdef __ANDROID__
-    tmp = alloc_printf("%s/afl-compiler-rt.so", dir);
-#else
-    tmp = alloc_printf("%s/afl-compiler-rt.o", dir);
-#endif
+          }
 
-    if (!access(tmp, R_OK)) {
+        }
 
-      obj_path = dir;
-      ck_free(tmp);
-      return;
+      }
 
     }
 
-    ck_free(tmp);
-    ck_free(dir);
+#endif
+#undef HAS_PROC_FS
 
   }
 
-#ifdef __ANDROID__
-  if (!access(AFL_PATH "/afl-compiler-rt.so", R_OK)) {
+  tmp = alloc_printf("%s/%s", AFL_PATH, obj);
 
-#else
-  if (!access(AFL_PATH "/afl-compiler-rt.o", R_OK)) {
+  if (debug) DEBUGF("Trying %s\n", tmp);
 
-#endif
+  if (!access(tmp, R_OK)) {
 
     obj_path = AFL_PATH;
-    return;
+    return tmp;
+
+  }
+
+  ck_free(tmp);
+
+  tmp = alloc_printf("./%s", obj);
+
+  if (debug) DEBUGF("Trying %s\n", tmp);
+
+  if (!access(tmp, R_OK)) {
+
+    obj_path = ".";
+    return tmp;
 
   }
 
-  FATAL(
-      "Unable to find 'afl-compiler-rt.o' or 'afl-llvm-pass.so'. Please set "
-      "AFL_PATH");
+  ck_free(tmp);
+
+  if (debug) DEBUGF("Trying ... giving up\n");
+
+  return NULL;
 
 }
 
@@ -288,7 +318,15 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
       if (compiler_mode >= GCC_PLUGIN) {
 
-        alt_cxx = "g++";
+        if (compiler_mode == GCC) {
+
+          alt_cxx = clang_mode ? "clang++" : "g++";
+
+        } else {
+
+          alt_cxx = "g++";
+
+        }
 
       } else {
 
@@ -313,7 +351,15 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
       if (compiler_mode >= GCC_PLUGIN) {
 
-        alt_cc = "gcc";
+        if (compiler_mode == GCC) {
+
+          alt_cc = clang_mode ? "clang" : "gcc";
+
+        } else {
+
+          alt_cc = "gcc";
+
+        }
 
       } else {
 
@@ -337,12 +383,13 @@ static void edit_params(u32 argc, char **argv, char **envp) {
     cc_params[cc_par_cnt++] = "-B";
     cc_params[cc_par_cnt++] = obj_path;
 
+    if (clang_mode) { cc_params[cc_par_cnt++] = "-no-integrated-as"; }
+
   }
 
   if (compiler_mode == GCC_PLUGIN) {
 
-    char *fplugin_arg =
-        alloc_printf("-fplugin=%s", find_object("afl-gcc-pass.so", argvnull));
+    char *fplugin_arg = alloc_printf("-fplugin=%s/afl-gcc-pass.so", obj_path);
     cc_params[cc_par_cnt++] = fplugin_arg;
 
   }
@@ -686,7 +733,8 @@ static void edit_params(u32 argc, char **argv, char **envp) {
   }
 
   if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
-      getenv("LAF_TRANSFORM_COMPARES") || lto_mode) {
+      getenv("LAF_TRANSFORM_COMPARES") || getenv("AFL_LLVM_LAF_ALL") ||
+      lto_mode) {
 
     cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
     cc_params[cc_par_cnt++] = "-fno-builtin-strncmp";
@@ -843,6 +891,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
           alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path);
   #endif
 
+  #ifdef USEMMAP
+    cc_params[cc_par_cnt++] = "-lrt";
+  #endif
+
   }
 
 #endif
@@ -934,7 +986,9 @@ int main(int argc, char **argv, char **envp) {
 
   } else if (strncmp(callname, "afl-gcc", 7) == 0 ||
 
-             strncmp(callname, "afl-g++", 7) == 0) {
+             strncmp(callname, "afl-g++", 7) == 0 ||
+
+             strncmp(callname, "afl-clang", 9) == 0) {
 
     compiler_mode = GCC;
 
@@ -978,6 +1032,14 @@ int main(int argc, char **argv, char **envp) {
 
   }
 
+  if (strncmp(callname, "afl-clang", 9) == 0) {
+
+    clang_mode = 1;
+
+    if (strncmp(callname, "afl-clang++", 11) == 0) { plusplus_mode = 1; }
+
+  }
+
   for (i = 1; i < argc; i++) {
 
     if (strncmp(argv[i], "--afl", 5) == 0) {
@@ -1030,7 +1092,7 @@ int main(int argc, char **argv, char **envp) {
     if (instrument_mode == 0)
       instrument_mode = INSTRUMENT_PCGUARD;
     else if (instrument_mode != INSTRUMENT_PCGUARD)
-      FATAL("you can not set AFL_LLVM_INSTRUMENT and AFL_TRACE_PC together");
+      FATAL("you cannot set AFL_LLVM_INSTRUMENT and AFL_TRACE_PC together");
 
   }
 
@@ -1048,8 +1110,7 @@ int main(int argc, char **argv, char **envp) {
     if (instrument_mode == 0)
       instrument_mode = INSTRUMENT_CFG;
     else if (instrument_mode != INSTRUMENT_CFG)
-      FATAL(
-          "you can not set AFL_LLVM_INSTRUMENT and AFL_LLVM_INSTRIM together");
+      FATAL("you cannot set AFL_LLVM_INSTRUMENT and AFL_LLVM_INSTRIM together");
 
   }
 
@@ -1403,9 +1464,15 @@ int main(int argc, char **argv, char **envp) {
     if (have_llvm)
       SAYF("afl-cc LLVM version %d with the the binary path \"%s\".\n",
            LLVM_MAJOR, LLVM_BINDIR);
-    if (have_lto || have_llvm) SAYF("\n");
 #endif
 
+#ifdef USEMMAP
+    SAYF("Compiled with shm_open support (adds -lrt when linking).\n");
+#else
+    SAYF("Compiled with shmat support.\n");
+#endif
+    SAYF("\n");
+
     SAYF(
         "Do not be overwhelmed :) afl-cc uses good defaults if no options are "
         "selected.\n"
@@ -1545,7 +1612,7 @@ int main(int argc, char **argv, char **envp) {
 
   if (debug) {
 
-    SAYF(cMGN "[D]" cRST " cd '%s';", getthecwd());
+    DEBUGF("cd '%s';", getthecwd());
     for (i = 0; i < argc; i++)
       SAYF(" '%s'", argv[i]);
     SAYF("\n");
@@ -1565,15 +1632,29 @@ int main(int argc, char **argv, char **envp) {
   if (!be_quiet && cmplog_mode)
     printf("CmpLog mode by <andreafioraldi@gmail.com>\n");
 
-#ifndef __ANDROID__
-  find_obj(argv[0]);
+#ifdef __ANDROID__
+  ptr = find_object("afl-compiler-rt.so", argv[0]);
+#else
+  ptr = find_object("afl-compiler-rt.o", argv[0]);
 #endif
 
+  if (!ptr) {
+
+    FATAL(
+        "Unable to find 'afl-compiler-rt.o'. Please set the AFL_PATH "
+        "environment variable.");
+
+  }
+
+  if (debug) { DEBUGF("rt=%s obj_path=%s\n", ptr, obj_path); }
+
+  ck_free(ptr);
+
   edit_params(argc, argv, envp);
 
   if (debug) {
 
-    SAYF(cMGN "[D]" cRST " cd '%s';", getthecwd());
+    DEBUGF("cd '%s';", getthecwd());
     for (i = 0; i < (s32)cc_par_cnt; i++)
       SAYF(" '%s'", cc_params[i]);
     SAYF("\n");
diff --git a/src/afl-common.c b/src/afl-common.c
index 8cf1a444..ed0b0e53 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -46,7 +46,7 @@ u8  be_quiet = 0;
 u8 *doc_path = "";
 u8  last_intr = 0;
 
-void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) {
+void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin) {
 
   u32 i = 0;
   u8  cwd[PATH_MAX];
@@ -63,7 +63,7 @@ void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) {
 
       if (!prog_in) { FATAL("@@ syntax is not supported by this tool."); }
 
-      *use_stdin = 0;
+      *use_stdin = false;
 
       if (prog_in[0] != 0) {  // not afl-showmap special case
 
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 3814a77e..3afb94be 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -62,6 +62,8 @@ static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) {
 
   execv(fsrv->target_path, argv);
 
+  WARNF("Execv failed in forkserver.");
+
 }
 
 /* Initializes the struct */
@@ -76,8 +78,8 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
   fsrv->dev_urandom_fd = -1;
 
   /* Settings */
-  fsrv->use_stdin = 1;
-  fsrv->no_unlink = 0;
+  fsrv->use_stdin = true;
+  fsrv->no_unlink = false;
   fsrv->exec_tmout = EXEC_TIMEOUT;
   fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT;
   fsrv->mem_limit = MEM_LIMIT;
@@ -86,8 +88,11 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
   /* exec related stuff */
   fsrv->child_pid = -1;
   fsrv->map_size = get_map_size();
-  fsrv->use_fauxsrv = 0;
-  fsrv->last_run_timed_out = 0;
+  fsrv->use_fauxsrv = false;
+  fsrv->last_run_timed_out = false;
+
+  fsrv->uses_crash_exitcode = false;
+  fsrv->uses_asan = false;
 
   fsrv->init_child_func = fsrv_exec_child;
 
@@ -109,6 +114,8 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
   fsrv_to->dev_urandom_fd = from->dev_urandom_fd;
   fsrv_to->out_fd = from->out_fd;  // not sure this is a good idea
   fsrv_to->no_unlink = from->no_unlink;
+  fsrv_to->uses_crash_exitcode = from->uses_crash_exitcode;
+  fsrv_to->crash_exitcode = from->crash_exitcode;
 
   // These are forkserver specific.
   fsrv_to->out_dir_fd = -1;
@@ -348,9 +355,10 @@ static void report_error_and_exit(int error) {
 void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
                     volatile u8 *stop_soon_p, u8 debug_child_output) {
 
-  int st_pipe[2], ctl_pipe[2];
-  s32 status;
-  s32 rlen;
+  int   st_pipe[2], ctl_pipe[2];
+  s32   status;
+  s32   rlen;
+  char *ignore_autodict = getenv("AFL_NO_AUTODICT");
 
   if (!be_quiet) { ACTF("Spinning up the fork server..."); }
 
@@ -520,8 +528,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
        falling through. */
 
     *(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG;
-    fprintf(stderr, "Error: execv to target failed\n");
-    exit(1);
+    FATAL("Error: execv to target failed\n");
 
   }
 
@@ -607,7 +614,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
           fsrv->use_shmem_fuzz = 1;
           if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); }
 
-          if ((status & FS_OPT_AUTODICT) == 0) {
+          if ((status & FS_OPT_AUTODICT) == 0 || ignore_autodict) {
 
             u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
             if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) {
@@ -660,100 +667,108 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
       if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) {
 
-        if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) {
+        if (ignore_autodict) {
 
-          // this is not afl-fuzz - or it is cmplog - we deny and return
-          if (fsrv->use_shmem_fuzz) {
+          if (!be_quiet) { WARNF("Ignoring offered AUTODICT feature."); }
 
-            status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
+        } else {
 
-          } else {
+          if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) {
 
-            status = (FS_OPT_ENABLED);
+            // this is not afl-fuzz - or it is cmplog - we deny and return
+            if (fsrv->use_shmem_fuzz) {
 
-          }
+              status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
 
-          if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
+            } else {
 
-            FATAL("Writing to forkserver failed.");
+              status = (FS_OPT_ENABLED);
 
-          }
+            }
 
-          return;
+            if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
 
-        }
+              FATAL("Writing to forkserver failed.");
 
-        if (!be_quiet) { ACTF("Using AUTODICT feature."); }
+            }
 
-        if (fsrv->use_shmem_fuzz) {
+            return;
 
-          status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ);
+          }
 
-        } else {
+          if (!be_quiet) { ACTF("Using AUTODICT feature."); }
 
-          status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
+          if (fsrv->use_shmem_fuzz) {
 
-        }
+            status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ);
 
-        if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
+          } else {
 
-          FATAL("Writing to forkserver failed.");
+            status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
 
-        }
+          }
+
+          if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
 
-        if (read(fsrv->fsrv_st_fd, &status, 4) != 4) {
+            FATAL("Writing to forkserver failed.");
 
-          FATAL("Reading from forkserver failed.");
+          }
 
-        }
+          if (read(fsrv->fsrv_st_fd, &status, 4) != 4) {
 
-        if (status < 2 || (u32)status > 0xffffff) {
+            FATAL("Reading from forkserver failed.");
 
-          FATAL("Dictionary has an illegal size: %d", status);
+          }
 
-        }
+          if (status < 2 || (u32)status > 0xffffff) {
 
-        u32 offset = 0, count = 0;
-        u32 len = status;
-        u8 *dict = ck_alloc(len);
-        if (dict == NULL) {
+            FATAL("Dictionary has an illegal size: %d", status);
 
-          FATAL("Could not allocate %u bytes of autodictionary memory", len);
+          }
 
-        }
+          u32 offset = 0, count = 0;
+          u32 len = status;
+          u8 *dict = ck_alloc(len);
+          if (dict == NULL) {
 
-        while (len != 0) {
+            FATAL("Could not allocate %u bytes of autodictionary memory", len);
 
-          rlen = read(fsrv->fsrv_st_fd, dict + offset, len);
-          if (rlen > 0) {
+          }
 
-            len -= rlen;
-            offset += rlen;
+          while (len != 0) {
 
-          } else {
+            rlen = read(fsrv->fsrv_st_fd, dict + offset, len);
+            if (rlen > 0) {
+
+              len -= rlen;
+              offset += rlen;
 
-            FATAL(
-                "Reading autodictionary fail at position %u with %u bytes "
-                "left.",
-                offset, len);
+            } else {
+
+              FATAL(
+                  "Reading autodictionary fail at position %u with %u bytes "
+                  "left.",
+                  offset, len);
+
+            }
 
           }
 
-        }
+          offset = 0;
+          while (offset < (u32)status &&
+                 (u8)dict[offset] + offset < (u32)status) {
 
-        offset = 0;
-        while (offset < (u32)status &&
-               (u8)dict[offset] + offset < (u32)status) {
+            fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
+                                 (u8)dict[offset]);
+            offset += (1 + dict[offset]);
+            count++;
 
-          fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
-                               (u8)dict[offset]);
-          offset += (1 + dict[offset]);
-          count++;
+          }
 
-        }
+          if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
+          ck_free(dict);
 
-        if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
-        ck_free(dict);
+        }
 
       }
 
@@ -902,7 +917,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
         "      estimate the required amount of virtual memory for the "
         "binary.\n\n"
 
-        "    - the target was compiled with afl-clang-lto and a constructor "
+        "    - The target was compiled with afl-clang-lto and a constructor "
         "was\n"
         "      instrumented, recompiling without AFL_LLVM_MAP_ADDR might solve "
         "your \n"
@@ -945,6 +960,8 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
 
   if (fsrv->shmem_fuzz) {
 
+    if (unlikely(len > MAX_FILE)) len = MAX_FILE;
+
     *fsrv->shmem_fuzz_len = len;
     memcpy(fsrv->shmem_fuzz, buf, len);
 #ifdef _DEBUG
@@ -1055,6 +1072,13 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
   if (fsrv->child_pid <= 0) {
 
     if (*stop_soon_p) { return 0; }
+
+    if ((fsrv->child_pid & FS_OPT_ERROR) &&
+        FS_OPT_GET_ERROR(fsrv->child_pid) == FS_ERROR_SHM_OPEN)
+      FATAL(
+          "Target reported shared memory access failed (perhaps increase "
+          "shared memory available).");
+
     FATAL("Fork server is misbehaving (OOM?)");
 
   }
@@ -1127,10 +1151,13 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
 
   }
 
-  /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and
-     must use a special exit code. */
+  /* MSAN in uses_asan mode uses a special exit code as it doesn't support
+  abort_on_error.
+  On top, a user may specify a custom AFL_CRASH_EXITCODE. Handle both here. */
 
-  if (fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) {
+  if ((fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) ||
+      (fsrv->uses_crash_exitcode &&
+       WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode)) {
 
     fsrv->last_kill_signal = 0;
     return FSRV_RUN_CRASH;
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index 2d14b04e..f1ca7400 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -425,8 +425,10 @@ void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) {
 /* Construct a file name for a new test case, capturing the operation
    that led to its discovery. Returns a ptr to afl->describe_op_buf_256. */
 
-u8 *describe_op(afl_state_t *afl, u8 hnb) {
+u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) {
 
+  size_t real_max_len =
+      MIN(max_description_len, sizeof(afl->describe_op_buf_256));
   u8 *ret = afl->describe_op_buf_256;
 
   if (unlikely(afl->syncing_party)) {
@@ -445,29 +447,66 @@ u8 *describe_op(afl_state_t *afl, u8 hnb) {
 
     sprintf(ret + strlen(ret), ",time:%llu", get_cur_time() - afl->start_time);
 
-    sprintf(ret + strlen(ret), ",op:%s", afl->stage_short);
+    if (afl->current_custom_fuzz &&
+        afl->current_custom_fuzz->afl_custom_describe) {
 
-    if (afl->stage_cur_byte >= 0) {
+      /* We are currently in a custom mutator that supports afl_custom_describe,
+       * use it! */
 
-      sprintf(ret + strlen(ret), ",pos:%d", afl->stage_cur_byte);
+      size_t len_current = strlen(ret);
+      ret[len_current++] = ',';
+      ret[len_current] = '\0';
 
-      if (afl->stage_val_type != STAGE_VAL_NONE) {
+      ssize_t size_left = real_max_len - len_current - strlen(",+cov") - 2;
+      if (unlikely(size_left <= 0)) FATAL("filename got too long");
 
-        sprintf(ret + strlen(ret), ",val:%s%+d",
-                (afl->stage_val_type == STAGE_VAL_BE) ? "be:" : "",
-                afl->stage_cur_val);
+      const char *custom_description =
+          afl->current_custom_fuzz->afl_custom_describe(
+              afl->current_custom_fuzz->data, size_left);
+      if (!custom_description || !custom_description[0]) {
+
+        DEBUGF("Error getting a description from afl_custom_describe");
+        /* Take the stage name as description fallback */
+        sprintf(ret + len_current, "op:%s", afl->stage_short);
+
+      } else {
+
+        /* We got a proper custom description, use it */
+        strncat(ret + len_current, custom_description, size_left);
 
       }
 
     } else {
 
-      sprintf(ret + strlen(ret), ",rep:%d", afl->stage_cur_val);
+      /* Normal testcase descriptions start here */
+      sprintf(ret + strlen(ret), ",op:%s", afl->stage_short);
+
+      if (afl->stage_cur_byte >= 0) {
+
+        sprintf(ret + strlen(ret), ",pos:%d", afl->stage_cur_byte);
+
+        if (afl->stage_val_type != STAGE_VAL_NONE) {
+
+          sprintf(ret + strlen(ret), ",val:%s%+d",
+                  (afl->stage_val_type == STAGE_VAL_BE) ? "be:" : "",
+                  afl->stage_cur_val);
+
+        }
+
+      } else {
+
+        sprintf(ret + strlen(ret), ",rep:%d", afl->stage_cur_val);
+
+      }
 
     }
 
   }
 
-  if (hnb == 2) { strcat(ret, ",+cov"); }
+  if (new_bits == 2) { strcat(ret, ",+cov"); }
+
+  if (unlikely(strlen(ret) >= max_description_len))
+    FATAL("describe string is too long");
 
   return ret;
 
@@ -540,7 +579,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
   if (unlikely(len == 0)) { return 0; }
 
   u8 *queue_fn = "";
-  u8  hnb = '\0';
+  u8  new_bits = '\0';
   s32 fd;
   u8  keeping = 0, res;
   u64 cksum = 0;
@@ -566,7 +605,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
     /* Keep only if there are new bits in the map, add to queue for
        future fuzzing, etc. */
 
-    if (!(hnb = has_new_bits(afl, afl->virgin_bits))) {
+    if (!(new_bits = has_new_bits(afl, afl->virgin_bits))) {
 
       if (unlikely(afl->crash_mode)) { ++afl->total_crashes; }
       return 0;
@@ -575,8 +614,9 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 
 #ifndef SIMPLE_FILES
 
-    queue_fn = alloc_printf("%s/queue/id:%06u,%s", afl->out_dir,
-                            afl->queued_paths, describe_op(afl, hnb));
+    queue_fn = alloc_printf(
+        "%s/queue/id:%06u,%s", afl->out_dir, afl->queued_paths,
+        describe_op(afl, new_bits, NAME_MAX - strlen("id:000000,")));
 
 #else
 
@@ -619,7 +659,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 
 #endif
 
-    if (hnb == 2) {
+    if (new_bits == 2) {
 
       afl->queue_top->has_new_cov = 1;
       ++afl->queued_with_cov;
@@ -742,7 +782,8 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 #ifndef SIMPLE_FILES
 
       snprintf(fn, PATH_MAX, "%s/hangs/id:%06llu,%s", afl->out_dir,
-               afl->unique_hangs, describe_op(afl, 0));
+               afl->unique_hangs,
+               describe_op(afl, 0, NAME_MAX - strlen("id:000000,")));
 
 #else
 
@@ -787,7 +828,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 
       snprintf(fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s", afl->out_dir,
                afl->unique_crashes, afl->fsrv.last_kill_signal,
-               describe_op(afl, 0));
+               describe_op(afl, 0, NAME_MAX - strlen("id:000000,sig:00,")));
 
 #else
 
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 0360cdb0..6707340b 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -868,7 +868,19 @@ void perform_dry_run(afl_state_t *afl) {
 
         if (skip_crashes) {
 
-          WARNF("Test case results in a crash (skipping)");
+          if (afl->fsrv.uses_crash_exitcode) {
+
+            WARNF(
+                "Test case results in a crash or AFL_CRASH_EXITCODE %d "
+                "(skipping)",
+                (int)(s8)afl->fsrv.crash_exitcode);
+
+          } else {
+
+            WARNF("Test case results in a crash (skipping)");
+
+          }
+
           q->cal_failed = CAL_CHANCES;
           ++cal_failures;
           break;
@@ -954,7 +966,18 @@ void perform_dry_run(afl_state_t *afl) {
 #undef MSG_ULIMIT_USAGE
 #undef MSG_FORK_ON_APPLE
 
-        WARNF("Test case '%s' results in a crash, skipping", fn);
+        if (afl->fsrv.uses_crash_exitcode) {
+
+          WARNF(
+              "Test case '%s' results in a crash or AFL_CRASH_EXITCODE %d, "
+              "skipping",
+              fn, (int)(s8)afl->fsrv.crash_exitcode);
+
+        } else {
+
+          WARNF("Test case '%s' results in a crash, skipping", fn);
+
+        }
 
         /* Remove from fuzzing queue but keep for splicing */
 
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index 1d14f657..0c85458e 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -151,7 +151,11 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
   /* Mutator */
   /* "afl_custom_init", optional for backward compatibility */
   mutator->afl_custom_init = dlsym(dh, "afl_custom_init");
-  if (!mutator->afl_custom_init) FATAL("Symbol 'afl_custom_init' not found.");
+  if (!mutator->afl_custom_init) {
+
+    FATAL("Symbol 'afl_custom_init' not found.");
+
+  }
 
   /* "afl_custom_fuzz" or "afl_custom_mutator", required */
   mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz");
@@ -161,49 +165,74 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
     WARNF("Symbol 'afl_custom_fuzz' not found. Try 'afl_custom_mutator'.");
 
     mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_mutator");
-    if (!mutator->afl_custom_fuzz)
+    if (!mutator->afl_custom_fuzz) {
+
       WARNF("Symbol 'afl_custom_mutator' not found.");
 
+    }
+
   }
 
   /* "afl_custom_introspection", optional */
 #ifdef INTROSPECTION
   mutator->afl_custom_introspection = dlsym(dh, "afl_custom_introspection");
-  if (!mutator->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)
+  if (!mutator->afl_custom_fuzz_count) {
+
     ACTF("optional symbol 'afl_custom_fuzz_count' not found.");
 
+  }
+
   /* "afl_custom_deinit", optional for backward compatibility */
   mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit");
-  if (!mutator->afl_custom_deinit)
+  if (!mutator->afl_custom_deinit) {
+
     FATAL("Symbol 'afl_custom_deinit' not found.");
 
+  }
+
   /* "afl_custom_post_process", optional */
   mutator->afl_custom_post_process = dlsym(dh, "afl_custom_post_process");
-  if (!mutator->afl_custom_post_process)
+  if (!mutator->afl_custom_post_process) {
+
     ACTF("optional symbol 'afl_custom_post_process' not found.");
 
+  }
+
   u8 notrim = 0;
   /* "afl_custom_init_trim", optional */
   mutator->afl_custom_init_trim = dlsym(dh, "afl_custom_init_trim");
-  if (!mutator->afl_custom_init_trim)
+  if (!mutator->afl_custom_init_trim) {
+
     ACTF("optional symbol 'afl_custom_init_trim' not found.");
 
+  }
+
   /* "afl_custom_trim", optional */
   mutator->afl_custom_trim = dlsym(dh, "afl_custom_trim");
-  if (!mutator->afl_custom_trim)
+  if (!mutator->afl_custom_trim) {
+
     ACTF("optional symbol 'afl_custom_trim' not found.");
 
+  }
+
   /* "afl_custom_post_trim", optional */
   mutator->afl_custom_post_trim = dlsym(dh, "afl_custom_post_trim");
-  if (!mutator->afl_custom_post_trim)
+  if (!mutator->afl_custom_post_trim) {
+
     ACTF("optional symbol 'afl_custom_post_trim' not found.");
 
+  }
+
   if (notrim) {
 
     mutator->afl_custom_init_trim = NULL;
@@ -217,31 +246,54 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
 
   /* "afl_custom_havoc_mutation", optional */
   mutator->afl_custom_havoc_mutation = dlsym(dh, "afl_custom_havoc_mutation");
-  if (!mutator->afl_custom_havoc_mutation)
+  if (!mutator->afl_custom_havoc_mutation) {
+
     ACTF("optional symbol 'afl_custom_havoc_mutation' not found.");
 
+  }
+
   /* "afl_custom_havoc_mutation", optional */
   mutator->afl_custom_havoc_mutation_probability =
       dlsym(dh, "afl_custom_havoc_mutation_probability");
-  if (!mutator->afl_custom_havoc_mutation_probability)
+  if (!mutator->afl_custom_havoc_mutation_probability) {
+
     ACTF("optional symbol 'afl_custom_havoc_mutation_probability' not found.");
 
+  }
+
   /* "afl_custom_queue_get", optional */
   mutator->afl_custom_queue_get = dlsym(dh, "afl_custom_queue_get");
-  if (!mutator->afl_custom_queue_get)
+  if (!mutator->afl_custom_queue_get) {
+
     ACTF("optional symbol 'afl_custom_queue_get' not found.");
 
+  }
+
   /* "afl_custom_queue_new_entry", optional */
   mutator->afl_custom_queue_new_entry = dlsym(dh, "afl_custom_queue_new_entry");
-  if (!mutator->afl_custom_queue_new_entry)
+  if (!mutator->afl_custom_queue_new_entry) {
+
     ACTF("optional symbol 'afl_custom_queue_new_entry' not found");
 
+  }
+
+  /* "afl_custom_describe", optional */
+  mutator->afl_custom_describe = dlsym(dh, "afl_custom_describe");
+  if (!mutator->afl_custom_describe) {
+
+    ACTF("Symbol 'afl_custom_describe' not found.");
+
+  }
+
   OKF("Custom mutator '%s' installed successfully.", fn);
 
   /* Initialize the custom mutator */
-  if (mutator->afl_custom_init)
+  if (mutator->afl_custom_init) {
+
     mutator->data = mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF));
 
+  }
+
   mutator->stacked_custom = (mutator && mutator->afl_custom_havoc_mutation);
   mutator->stacked_custom_prob =
       6;  // like one of the default mutations in havoc
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index 0adc3719..e6fa6064 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -445,8 +445,13 @@ u8 fuzz_one_original(afl_state_t *afl) {
 
   if (unlikely(afl->not_on_tty)) {
 
-    ACTF("Fuzzing test case #%u (%u total, %llu uniq crashes found)...",
-         afl->current_entry, afl->queued_paths, afl->unique_crashes);
+    ACTF(
+        "Fuzzing test case #%u (%u total, %llu uniq crashes found, "
+        "perf_score=%0.0f, exec_us=%llu, hits=%u, map=%u)...",
+        afl->current_entry, afl->queued_paths, afl->unique_crashes,
+        afl->queue_cur->perf_score, afl->queue_cur->exec_us,
+        likely(afl->n_fuzz) ? afl->n_fuzz[afl->queue_cur->n_fuzz_entry] : 0,
+        afl->queue_cur->bitmap_size);
     fflush(stdout);
 
   }
@@ -1790,11 +1795,16 @@ custom_mutator_stage:
 
       afl->current_custom_fuzz = el;
 
-      if (el->afl_custom_fuzz_count)
+      if (el->afl_custom_fuzz_count) {
+
         afl->stage_max = el->afl_custom_fuzz_count(el->data, out_buf, len);
-      else
+
+      } else {
+
         afl->stage_max = saved_max;
 
+      }
+
       has_custom_fuzz = true;
 
       afl->stage_short = el->name_short;
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
index 9ac4403b..8760194c 100644
--- a/src/afl-fuzz-python.c
+++ b/src/afl-fuzz-python.c
@@ -111,6 +111,37 @@ static size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf,
 
 }
 
+static const char *custom_describe_py(void * py_mutator,
+                                      size_t max_description_len) {
+
+  PyObject *py_args, *py_value;
+
+  py_args = PyTuple_New(1);
+
+  PyLong_FromSize_t(max_description_len);
+
+  /* add_buf */
+  py_value = PyLong_FromSize_t(max_description_len);
+  if (!py_value) {
+
+    Py_DECREF(py_args);
+    FATAL("Failed to convert arguments");
+
+  }
+
+  PyTuple_SetItem(py_args, 0, py_value);
+
+  py_value = PyObject_CallObject(
+      ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_DESCRIBE], py_args);
+
+  Py_DECREF(py_args);
+
+  if (py_value != NULL) { return PyBytes_AsString(py_value); }
+
+  return NULL;
+
+}
+
 static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
 
   (void)afl;
@@ -156,6 +187,8 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
     py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz");
     if (!py_functions[PY_FUNC_FUZZ])
       py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "mutate");
+    py_functions[PY_FUNC_DESCRIBE] =
+        PyObject_GetAttrString(py_module, "describe");
     py_functions[PY_FUNC_FUZZ_COUNT] =
         PyObject_GetAttrString(py_module, "fuzz_count");
     if (!py_functions[PY_FUNC_FUZZ])
@@ -342,6 +375,12 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
 
   if (py_functions[PY_FUNC_FUZZ]) { mutator->afl_custom_fuzz = fuzz_py; }
 
+  if (py_functions[PY_FUNC_DESCRIBE]) {
+
+    mutator->afl_custom_describe = custom_describe_py;
+
+  }
+
   if (py_functions[PY_FUNC_POST_PROCESS]) {
 
     mutator->afl_custom_post_process = post_process_py;
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index f35b4f57..54afa17c 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -42,11 +42,39 @@ inline u32 select_next_queue_entry(afl_state_t *afl) {
 
 }
 
+double compute_weight(afl_state_t *afl, struct queue_entry *q,
+                      double avg_exec_us, double avg_bitmap_size) {
+
+  u32 hits;
+
+  if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) {
+
+    hits = afl->n_fuzz[q->n_fuzz_entry];
+    if (hits == 0) { hits = 1; }
+
+  } else {
+
+    hits = 1;
+
+  }
+
+  double weight = 1.0;
+  weight *= avg_exec_us / q->exec_us;
+  weight *= log(q->bitmap_size) / avg_bitmap_size;
+  weight /= log10(hits) + 1;
+
+  if (q->favored) weight *= 5;
+
+  return weight;
+
+}
+
 /* create the alias table that allows weighted random selection - expensive */
 
 void create_alias_table(afl_state_t *afl) {
 
-  u32 n = afl->queued_paths, i = 0, a, g;
+  u32    n = afl->queued_paths, i = 0, a, g;
+  double sum = 0;
 
   afl->alias_table =
       (u32 *)afl_realloc((void **)&afl->alias_table, n * sizeof(u32));
@@ -65,22 +93,60 @@ void create_alias_table(afl_state_t *afl) {
   memset((void *)afl->alias_table, 0, n * sizeof(u32));
   memset((void *)afl->alias_probability, 0, n * sizeof(double));
 
-  double sum = 0;
+  if (likely(afl->schedule < RARE)) {
 
-  for (i = 0; i < n; i++) {
+    double avg_exec_us = 0.0;
+    double avg_bitmap_size = 0.0;
+    for (i = 0; i < n; i++) {
 
-    struct queue_entry *q = afl->queue_buf[i];
+      struct queue_entry *q = afl->queue_buf[i];
+      avg_exec_us += q->exec_us;
+      avg_bitmap_size += log(q->bitmap_size);
 
-    if (!q->disabled) { q->perf_score = calculate_score(afl, q); }
+    }
 
-    sum += q->perf_score;
+    avg_exec_us /= afl->queued_paths;
+    avg_bitmap_size /= afl->queued_paths;
 
-  }
+    for (i = 0; i < n; i++) {
+
+      struct queue_entry *q = afl->queue_buf[i];
+
+      if (!q->disabled) {
 
-  for (i = 0; i < n; i++) {
+        q->weight = compute_weight(afl, q, avg_exec_us, avg_bitmap_size);
+        q->perf_score = calculate_score(afl, q);
 
-    struct queue_entry *q = afl->queue_buf[i];
-    P[i] = (q->perf_score * n) / sum;
+      }
+
+      sum += q->weight;
+
+    }
+
+    for (i = 0; i < n; i++) {
+
+      P[i] = (afl->queue_buf[i]->weight * n) / sum;
+
+    }
+
+  } else {
+
+    for (i = 0; i < n; i++) {
+
+      struct queue_entry *q = afl->queue_buf[i];
+
+      if (!q->disabled) { q->perf_score = calculate_score(afl, q); }
+
+      sum += q->perf_score;
+
+    }
+
+    for (i = 0; i < n; i++) {
+
+      struct queue_entry *q = afl->queue_buf[i];
+      P[i] = (q->perf_score * n) / sum;
+
+    }
 
   }
 
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 95b3ee8a..5948d83a 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -79,7 +79,8 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
   s32  doc_fd;
   char fn[PATH_MAX];
   snprintf(fn, PATH_MAX, "%s/mutations/%09u:%s", afl->out_dir,
-           afl->document_counter++, describe_op(afl, 0));
+           afl->document_counter++,
+           describe_op(afl, 0, NAME_MAX - strlen("000000000:")));
 
   if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0) {
 
@@ -484,7 +485,7 @@ void sync_fuzzers(afl_state_t *afl) {
   DIR *          sd;
   struct dirent *sd_ent;
   u32            sync_cnt = 0, synced = 0, entries = 0;
-  u8             path[PATH_MAX + 256];
+  u8             path[PATH_MAX + 1 + NAME_MAX];
 
   sd = opendir(afl->sync_dir);
   if (!sd) { PFATAL("Unable to open '%s'", afl->sync_dir); }
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index 489d4e53..9c51a3ef 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -87,7 +87,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
   afl->w_end = 0.3;
   afl->g_max = 5000;
   afl->period_pilot_tmp = 5000.0;
-  afl->schedule = EXPLORE;             /* Power schedule (default: EXPLORE) */
+  afl->schedule = FAST;                 /* Power schedule (default: FAST)   */
   afl->havoc_max_mult = HAVOC_MAX_MULT;
 
   afl->clear_screen = 1;                /* Window resized?                  */
@@ -394,6 +394,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
             afl->afl_env.afl_statsd_tags_flavor =
                 (u8 *)get_afl_env(afl_environment_variables[i]);
 
+          } else if (!strncmp(env, "AFL_CRASH_EXITCODE",
+
+                              afl_environment_variable_len)) {
+
+            afl->afl_env.afl_crash_exitcode =
+                (u8 *)get_afl_env(afl_environment_variables[i]);
+
           }
 
         } else {
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 1008f28c..391d4c4f 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -26,6 +26,7 @@
 #include "afl-fuzz.h"
 #include "cmplog.h"
 #include <limits.h>
+#include <stdlib.h>
 #ifndef USEMMAP
   #include <sys/mman.h>
   #include <sys/stat.h>
@@ -40,7 +41,7 @@ extern u64 time_spent_working;
 
 static void at_exit() {
 
-  int   i;
+  s32   i, pid1 = 0, pid2 = 0;
   char *list[4] = {SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, CMPLOG_SHM_ENV_VAR, NULL};
   char *ptr;
 
@@ -48,10 +49,10 @@ static void at_exit() {
   if (ptr && *ptr) unlink(ptr);
 
   ptr = getenv("__AFL_TARGET_PID1");
-  if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL);
+  if (ptr && *ptr && (pid1 = atoi(ptr)) > 0) kill(pid1, SIGTERM);
 
   ptr = getenv("__AFL_TARGET_PID2");
-  if (ptr && *ptr && (i = atoi(ptr)) > 0) kill(i, SIGKILL);
+  if (ptr && *ptr && (pid2 = atoi(ptr)) > 0) kill(pid2, SIGTERM);
 
   i = 0;
   while (list[i] != NULL) {
@@ -75,6 +76,9 @@ static void at_exit() {
 
   }
 
+  if (pid1 > 0) { kill(pid1, SIGKILL); }
+  if (pid2 > 0) { kill(pid2, SIGKILL); }
+
 }
 
 /* Display usage hints. */
@@ -162,6 +166,7 @@ static void usage(u8 *argv0, int more_help) {
       "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n"
       "AFL_BENCH_JUST_ONE: run the target just once\n"
       "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n"
+      "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n"
       "AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\n"
       "AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n"
       "AFL_CYCLE_SCHEDULES: after completing a cycle, switch to a different -p schedule\n"
@@ -184,6 +189,7 @@ static void usage(u8 *argv0, int more_help) {
       "                    used. Defaults to 200.\n"
       "AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n"
       "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n"
+      "AFL_NO_AUTODICT: do not load an offered auto dictionary compiled into a target\n"
       "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n"
       "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n"
       "AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n"
@@ -224,6 +230,12 @@ static void usage(u8 *argv0, int more_help) {
   SAYF("Compiled without python module support\n");
 #endif
 
+#ifdef USEMMAP
+  SAYF("Compiled with shm_open support.\n");
+#else
+  SAYF("Compiled with shmat support.\n");
+#endif
+
 #ifdef ASAN_BUILD
   SAYF("Compiled with ASAN_BUILD\n\n");
 #endif
@@ -248,7 +260,7 @@ static void usage(u8 *argv0, int more_help) {
   SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS\n\n");
 #endif
 
-  SAYF("For additional help please consult %s/README.md\n\n", doc_path);
+  SAYF("For additional help please consult %s/README.md :)\n\n", doc_path);
 
   exit(1);
 #undef PHYTON_SUPPORT
@@ -698,7 +710,7 @@ int main(int argc, char **argv_orig, char **envp) {
       case 'N':                                             /* Unicorn mode */
 
         if (afl->no_unlink) { FATAL("Multiple -N options not supported"); }
-        afl->fsrv.no_unlink = afl->no_unlink = 1;
+        afl->fsrv.no_unlink = (afl->no_unlink = true);
 
         break;
 
@@ -909,7 +921,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
-  if (!mem_limit_given && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
+  if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
 
   OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" "
       "Eißfeldt, Andrea Fioraldi and Dominik Maier");
@@ -1131,6 +1143,23 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  if (afl->afl_env.afl_crash_exitcode) {
+
+    long exitcode = strtol(afl->afl_env.afl_crash_exitcode, NULL, 10);
+    if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
+        exitcode < -127 || exitcode > 128) {
+
+      FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
+            afl->afl_env.afl_crash_exitcode);
+
+    }
+
+    afl->fsrv.uses_crash_exitcode = true;
+    // WEXITSTATUS is 8 bit unsigned
+    afl->fsrv.crash_exitcode = (u8)exitcode;
+
+  }
+
   if (afl->non_instrumented_mode == 2 && afl->no_forkserver) {
 
     FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive");
@@ -1482,9 +1511,12 @@ int main(int argc, char **argv_orig, char **envp) {
 
   cull_queue(afl);
 
-  if (!afl->pending_not_fuzzed)
+  if (!afl->pending_not_fuzzed) {
+
     FATAL("We need at least on valid input seed that does not crash!");
 
+  }
+
   show_init_stats(afl);
 
   if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl);
diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c
index 771e2d0d..16feaa80 100644
--- a/src/afl-ld-lto.c
+++ b/src/afl-ld-lto.c
@@ -182,12 +182,12 @@ static void edit_params(int argc, char **argv) {
     instrim = 1;
 
   if (debug)
-    SAYF(cMGN "[D] " cRST
-              "passthrough=%s instrim=%d, gold_pos=%d, gold_present=%s "
-              "inst_present=%s rt_present=%s rt_lto_present=%s\n",
-         passthrough ? "true" : "false", instrim, gold_pos,
-         gold_present ? "true" : "false", inst_present ? "true" : "false",
-         rt_present ? "true" : "false", rt_lto_present ? "true" : "false");
+    DEBUGF(
+        "passthrough=%s instrim=%d, gold_pos=%d, gold_present=%s "
+        "inst_present=%s rt_present=%s rt_lto_present=%s\n",
+        passthrough ? "true" : "false", instrim, gold_pos,
+        gold_present ? "true" : "false", inst_present ? "true" : "false",
+        rt_present ? "true" : "false", rt_lto_present ? "true" : "false");
 
   for (i = 1; i < argc; i++) {
 
@@ -280,7 +280,7 @@ int main(int argc, char **argv) {
 
     if (getcwd(thecwd, sizeof(thecwd)) != 0) strcpy(thecwd, ".");
 
-    SAYF(cMGN "[D] " cRST "cd \"%s\";", thecwd);
+    DEBUGF("cd \"%s\";", thecwd);
     for (i = 0; i < argc; i++)
       SAYF(" \"%s\"", argv[i]);
     SAYF("\n");
@@ -315,7 +315,7 @@ int main(int argc, char **argv) {
 
   if (debug) {
 
-    SAYF(cMGN "[D]" cRST " cd \"%s\";", thecwd);
+    DEBUGF("cd \"%s\";", thecwd);
     for (i = 0; i < ld_param_cnt; i++)
       SAYF(" \"%s\"", ld_params[i]);
     SAYF("\n");
@@ -333,7 +333,7 @@ int main(int argc, char **argv) {
   if (pid < 0) PFATAL("fork() failed");
 
   if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed");
-  if (debug) SAYF(cMGN "[D] " cRST "linker result: %d\n", status);
+  if (debug) DEBUGF("linker result: %d\n", status);
 
   if (!just_version) {
 
diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c
index 6eb63949..3e671df5 100644
--- a/src/afl-sharedmem.c
+++ b/src/afl-sharedmem.c
@@ -248,22 +248,26 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
 
   }
 
-  shm_str = alloc_printf("%d", shm->shm_id);
+  if (!non_instrumented_mode) {
 
-  /* If somebody is asking us to fuzz instrumented binaries in non-instrumented
-     mode, we don't want them to detect instrumentation, since we won't be
-     sending fork server commands. This should be replaced with better
-     auto-detection later on, perhaps? */
+    shm_str = alloc_printf("%d", shm->shm_id);
+
+    /* If somebody is asking us to fuzz instrumented binaries in
+       non-instrumented mode, we don't want them to detect instrumentation,
+       since we won't be sending fork server commands. This should be replaced
+       with better auto-detection later on, perhaps? */
 
-  if (!non_instrumented_mode) { setenv(SHM_ENV_VAR, shm_str, 1); }
+    setenv(SHM_ENV_VAR, shm_str, 1);
 
-  ck_free(shm_str);
+    ck_free(shm_str);
 
-  if (shm->cmplog_mode) {
+  }
+
+  if (shm->cmplog_mode && !non_instrumented_mode) {
 
     shm_str = alloc_printf("%d", shm->cmplog_shm_id);
 
-    if (!non_instrumented_mode) { setenv(CMPLOG_SHM_ENV_VAR, shm_str, 1); }
+    setenv(CMPLOG_SHM_ENV_VAR, shm_str, 1);
 
     ck_free(shm_str);
 
@@ -274,6 +278,7 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
   if (shm->map == (void *)-1 || !shm->map) {
 
     shmctl(shm->shm_id, IPC_RMID, NULL);  // do not leak shmem
+
     if (shm->cmplog_mode) {
 
       shmctl(shm->cmplog_shm_id, IPC_RMID, NULL);  // do not leak shmem
@@ -291,11 +296,8 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
     if (shm->cmp_map == (void *)-1 || !shm->cmp_map) {
 
       shmctl(shm->shm_id, IPC_RMID, NULL);  // do not leak shmem
-      if (shm->cmplog_mode) {
 
-        shmctl(shm->cmplog_shm_id, IPC_RMID, NULL);  // do not leak shmem
-
-      }
+      shmctl(shm->cmplog_shm_id, IPC_RMID, NULL);  // do not leak shmem
 
       PFATAL("shmat() failed");
 
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index 69527007..34a4f30d 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -287,6 +287,8 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
 
   afl_fsrv_write_to_testcase(fsrv, mem, len);
 
+  if (!quiet_mode) { SAYF("-- Program output begins --\n" cRST); }
+
   if (afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon) ==
       FSRV_RUN_ERROR) {
 
@@ -667,6 +669,8 @@ static void usage(u8 *argv0) {
       "AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing "
       "inputs\n"
       "AFL_CMIN_ALLOW_ANY: (cmin_mode) write tuples for crashing inputs also\n"
+      "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as "
+      "crash\n"
       "AFL_DEBUG: enable extra developer output\n"
       "AFL_MAP_SIZE: the shared memory size for that target. must be >= the "
       "size\n"
@@ -709,6 +713,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
       case 'C':
         collect_coverage = 1;
+        quiet_mode = 1;
         break;
 
       case 'i':
@@ -815,7 +820,6 @@ int main(int argc, char **argv_orig, char **envp) {
 
       case 'q':
 
-        if (quiet_mode) { FATAL("Multiple -q options not supported"); }
         quiet_mode = 1;
         break;
 
@@ -904,7 +908,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (getenv("AFL_DEBUG")) {
 
-    SAYF(cMGN "[D]" cRST);
+    DEBUGF("");
     for (i = 0; i < argc; i++)
       SAYF(" %s", argv[i]);
     SAYF("\n");
@@ -1066,7 +1070,7 @@ int main(int argc, char **argv_orig, char **envp) {
     if (get_afl_env("AFL_DEBUG")) {
 
       int i = optind;
-      SAYF(cMGN "[D]" cRST " %s:", fsrv->target_path);
+      DEBUGF("%s:", fsrv->target_path);
       while (argv[i] != NULL) {
 
         SAYF(" \"%s\"", argv[i++]);
@@ -1090,6 +1094,23 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
+    if (getenv("AFL_CRASH_EXITCODE")) {
+
+      long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10);
+      if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
+          exitcode < -127 || exitcode > 128) {
+
+        FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
+              getenv("AFL_CRASH_EXITCODE"));
+
+      }
+
+      fsrv->uses_crash_exitcode = true;
+      // WEXITSTATUS is 8 bit unsigned
+      fsrv->crash_exitcode = (u8)exitcode;
+
+    }
+
     afl_fsrv_start(fsrv, use_argv, &stop_soon,
                    (get_afl_env("AFL_DEBUG_CHILD") ||
                     get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
@@ -1170,7 +1191,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
-  if (!quiet_mode) {
+  if (!quiet_mode || collect_coverage) {
 
     if (!tcnt) { FATAL("No instrumentation detected" cRST); }
     OKF("Captured %u tuples (highest value %u, total values %llu) in "
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index e4fb068d..b9045551 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -51,6 +51,7 @@
 #include <signal.h>
 #include <dirent.h>
 #include <fcntl.h>
+#include <limits.h>
 
 #include <sys/wait.h>
 #include <sys/time.h>
@@ -841,17 +842,17 @@ static void usage(u8 *argv0) {
       "For additional tips, please consult %s/README.md.\n\n"
 
       "Environment variables used:\n"
-      "TMPDIR: directory to use for temporary input files\n"
-      "ASAN_OPTIONS: custom settings for ASAN\n"
-      "              (must contain abort_on_error=1 and symbolize=0)\n"
-      "MSAN_OPTIONS: custom settings for MSAN\n"
-      "              (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
+      "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n"
+      "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n"
       "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
       "              the target was compiled for\n"
       "AFL_PRELOAD:  LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
       "AFL_TMIN_EXACT: require execution paths to match for crashing inputs\n"
-      "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\n"
-
+      "ASAN_OPTIONS: custom settings for ASAN\n"
+      "              (must contain abort_on_error=1 and symbolize=0)\n"
+      "MSAN_OPTIONS: custom settings for MSAN\n"
+      "              (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
+      "TMPDIR: directory to use for temporary input files\n"
       , argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
 
   exit(1);
@@ -1122,6 +1123,23 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  if (getenv("AFL_CRASH_EXITCODE")) {
+
+    long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10);
+    if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
+        exitcode < -127 || exitcode > 128) {
+
+      FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
+            getenv("AFL_CRASH_EXITCODE"));
+
+    }
+
+    fsrv->uses_crash_exitcode = true;
+    // WEXITSTATUS is 8 bit unsigned
+    fsrv->crash_exitcode = (u8)exitcode;
+
+  }
+
   shm_fuzz = ck_alloc(sizeof(sharedmem_t));
 
   /* initialize cmplog_mode */