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.c225
-rw-r--r--src/afl-cc.c33
-rw-r--r--src/afl-common.c2
-rw-r--r--src/afl-forkserver.c10
-rw-r--r--src/afl-fuzz-bitmap.c13
-rw-r--r--src/afl-fuzz-init.c132
-rw-r--r--src/afl-fuzz-mutators.c1
-rw-r--r--src/afl-fuzz-one.c13
-rw-r--r--src/afl-fuzz-queue.c9
-rw-r--r--src/afl-fuzz-redqueen.c98
-rw-r--r--src/afl-fuzz-run.c24
-rw-r--r--src/afl-fuzz-state.c9
-rw-r--r--src/afl-fuzz-stats.c68
-rw-r--r--src/afl-fuzz.c31
-rw-r--r--src/afl-showmap.c189
-rw-r--r--src/afl-tmin.c11
16 files changed, 496 insertions, 372 deletions
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index aabdbf1a..a5cad03c 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -55,12 +55,7 @@
 #include <sys/types.h>
 #include <sys/resource.h>
 
-static s32 child_pid;                  /* PID of the tested program         */
-
-static u8 *trace_bits;                 /* SHM with instrumentation bitmap   */
-
-static u8 *in_file,                    /* Analyzer input test case          */
-    *prog_in;                          /* Targeted program input file       */
+static u8 *in_file;                    /* Analyzer input test case          */
 
 static u8 *in_data;                    /* Input data for analysis           */
 
@@ -73,20 +68,19 @@ static u64 orig_cksum;                 /* Original checksum                 */
 
 static u64 mem_limit = MEM_LIMIT;      /* Memory limit (MB)                 */
 
-static s32 dev_null_fd = -1;           /* FD to /dev/null                   */
-
 static bool edges_only,                  /* Ignore hit counts?              */
     use_hex_offsets,                   /* Show hex offsets?                 */
     use_stdin = true;                     /* Use stdin for program input?   */
 
-static volatile u8 stop_soon,          /* Ctrl-C pressed?                   */
-    child_timed_out;                   /* Child timed out?                  */
+static volatile u8 stop_soon;          /* Ctrl-C pressed?                   */
 
 static u8 *target_path;
 static u8  frida_mode;
 static u8  qemu_mode;
 static u32 map_size = MAP_SIZE;
 
+static afl_forkserver_t fsrv = {0};   /* The forkserver                     */
+
 /* Constants used for describing byte behavior. */
 
 #define RESP_NONE 0x00                 /* Changing byte is a no-op.         */
@@ -156,7 +150,7 @@ static void classify_counts(u8 *mem) {
 
 static inline u8 anything_set(void) {
 
-  u32 *ptr = (u32 *)trace_bits;
+  u32 *ptr = (u32 *)fsrv.trace_bits;
   u32  i = (map_size >> 2);
 
   while (i--) {
@@ -173,7 +167,7 @@ static inline u8 anything_set(void) {
 
 static void at_exit_handler(void) {
 
-  unlink(prog_in);                                         /* Ignore errors */
+  unlink(fsrv.out_file);                                   /* Ignore errors */
 
 }
 
@@ -205,116 +199,29 @@ static void read_initial_file(void) {
 
 }
 
-/* Write output file. */
-
-static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
-
-  s32 ret;
-
-  unlink(path);                                            /* Ignore errors */
-
-  ret = open(path, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
-
-  if (ret < 0) { PFATAL("Unable to create '%s'", path); }
-
-  ck_write(ret, mem, len, path);
-
-  lseek(ret, 0, SEEK_SET);
-
-  return ret;
-
-}
-
 /* Execute target application. Returns exec checksum, or 0 if program
    times out. */
 
-static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) {
-
-  static struct itimerval it;
-  int                     status = 0;
-
-  s32 prog_in_fd;
-  u64 cksum;
-
-  memset(trace_bits, 0, map_size);
-  MEM_BARRIER();
-
-  prog_in_fd = write_to_file(prog_in, mem, len);
-
-  child_pid = fork();
-
-  if (child_pid < 0) { PFATAL("fork() failed"); }
-
-  if (!child_pid) {
-
-    struct rlimit r;
-
-    if (dup2(use_stdin ? prog_in_fd : dev_null_fd, 0) < 0 ||
-        dup2(dev_null_fd, 1) < 0 || dup2(dev_null_fd, 2) < 0) {
-
-      *(u32 *)trace_bits = EXEC_FAIL_SIG;
-      PFATAL("dup2() failed");
-
-    }
-
-    close(dev_null_fd);
-    close(prog_in_fd);
-
-    if (mem_limit) {
-
-      r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20;
-
-#ifdef RLIMIT_AS
-
-      setrlimit(RLIMIT_AS, &r);                            /* Ignore errors */
-
-#else
-
-      setrlimit(RLIMIT_DATA, &r);                          /* Ignore errors */
+static u32 analyze_run_target(u8 *mem, u32 len, u8 first_run) {
 
-#endif                                                        /* ^RLIMIT_AS */
+  afl_fsrv_write_to_testcase(&fsrv, mem, len);
+  fsrv_run_result_t ret = afl_fsrv_run_target(&fsrv, exec_tmout, &stop_soon);
 
-    }
-
-    r.rlim_max = r.rlim_cur = 0;
-    setrlimit(RLIMIT_CORE, &r);                            /* Ignore errors */
-
-    execv(target_path, argv);
-
-    *(u32 *)trace_bits = EXEC_FAIL_SIG;
-    exit(0);
-
-  }
-
-  close(prog_in_fd);
-
-  /* Configure timeout, wait for child, cancel timeout. */
-
-  child_timed_out = 0;
-  it.it_value.tv_sec = (exec_tmout / 1000);
-  it.it_value.tv_usec = (exec_tmout % 1000) * 1000;
+  if (ret == FSRV_RUN_ERROR) {
 
-  setitimer(ITIMER_REAL, &it, NULL);
+    FATAL("Error in forkserver");
 
-  if (waitpid(child_pid, &status, 0) <= 0) { FATAL("waitpid() failed"); }
+  } else if (ret == FSRV_RUN_NOINST) {
 
-  child_pid = 0;
-  it.it_value.tv_sec = 0;
-  it.it_value.tv_usec = 0;
+    FATAL("Target not instrumented");
 
-  setitimer(ITIMER_REAL, &it, NULL);
+  } else if (ret == FSRV_RUN_NOBITS) {
 
-  MEM_BARRIER();
-
-  /* Clean up bitmap, analyze exit condition, etc. */
-
-  if (*(u32 *)trace_bits == EXEC_FAIL_SIG) {
-
-    FATAL("Unable to execute '%s'", argv[0]);
+    FATAL("Failed to run target");
 
   }
 
-  classify_counts(trace_bits);
+  classify_counts(fsrv.trace_bits);
   total_execs++;
 
   if (stop_soon) {
@@ -326,21 +233,19 @@ static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) {
 
   /* Always discard inputs that time out. */
 
-  if (child_timed_out) {
+  if (fsrv.last_run_timed_out) {
 
     exec_hangs++;
     return 0;
 
   }
 
-  cksum = hash64(trace_bits, map_size, HASH_CONST);
+  u64 cksum = hash64(fsrv.trace_bits, fsrv.map_size, HASH_CONST);
 
-  /* We don't actually care if the target is crashing or not,
-     except that when it does, the checksum should be different. */
+  if (ret == FSRV_RUN_CRASH) {
 
-  if (WIFSIGNALED(status) ||
-      (WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) ||
-      (WIFEXITED(status) && WEXITSTATUS(status))) {
+    /* We don't actually care if the target is crashing or not,
+       except that when it does, the checksum should be different. */
 
     cksum ^= 0xffffffff;
 
@@ -604,7 +509,7 @@ static void dump_hex(u32 len, u8 *b_data) {
 
 /* Actually analyze! */
 
-static void analyze(char **argv) {
+static void analyze() {
 
   u32 i;
   u32 boring_len = 0, prev_xff = 0, prev_x01 = 0, prev_s10 = 0, prev_a10 = 0;
@@ -630,16 +535,16 @@ static void analyze(char **argv) {
        code. */
 
     in_data[i] ^= 0xff;
-    xor_ff = analyze_run_target(argv, in_data, in_len, 0);
+    xor_ff = analyze_run_target(in_data, in_len, 0);
 
     in_data[i] ^= 0xfe;
-    xor_01 = analyze_run_target(argv, in_data, in_len, 0);
+    xor_01 = analyze_run_target(in_data, in_len, 0);
 
     in_data[i] = (in_data[i] ^ 0x01) - 0x10;
-    sub_10 = analyze_run_target(argv, in_data, in_len, 0);
+    sub_10 = analyze_run_target(in_data, in_len, 0);
 
     in_data[i] += 0x20;
-    add_10 = analyze_run_target(argv, in_data, in_len, 0);
+    add_10 = analyze_run_target(in_data, in_len, 0);
     in_data[i] -= 0x10;
 
     /* Classify current behavior. */
@@ -712,7 +617,7 @@ static void handle_stop_sig(int sig) {
   (void)sig;
   stop_soon = 1;
 
-  if (child_pid > 0) { kill(child_pid, SIGKILL); }
+  afl_fsrv_killall();
 
 }
 
@@ -724,10 +629,10 @@ static void set_up_environment(char **argv) {
   char *afl_preload;
   char *frida_afl_preload = NULL;
 
-  dev_null_fd = open("/dev/null", O_RDWR);
-  if (dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
+  fsrv.dev_null_fd = open("/dev/null", O_RDWR);
+  if (fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
 
-  if (!prog_in) {
+  if (!fsrv.out_file) {
 
     u8 *use_dir = ".";
 
@@ -738,10 +643,17 @@ static void set_up_environment(char **argv) {
 
     }
 
-    prog_in = alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid());
+    fsrv.out_file =
+        alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid());
 
   }
 
+  unlink(fsrv.out_file);
+  fsrv.out_fd =
+      open(fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+
+  if (fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fsrv.out_file); }
+
   /* Set sane defaults... */
 
   x = get_afl_env("ASAN_OPTIONS");
@@ -977,9 +889,9 @@ int main(int argc, char **argv_orig, char **envp) {
 
       case 'f':
 
-        if (prog_in) { FATAL("Multiple -f options not supported"); }
-        use_stdin = 0;
-        prog_in = optarg;
+        if (fsrv.out_file) { FATAL("Multiple -f options not supported"); }
+        fsrv.use_stdin = 0;
+        fsrv.out_file = ck_strdup(optarg);
         break;
 
       case 'e':
@@ -1000,6 +912,7 @@ int main(int argc, char **argv_orig, char **envp) {
         if (!strcmp(optarg, "none")) {
 
           mem_limit = 0;
+          fsrv.mem_limit = 0;
           break;
 
         }
@@ -1038,6 +951,8 @@ int main(int argc, char **argv_orig, char **envp) {
 
         }
 
+        fsrv.mem_limit = mem_limit;
+
       }
 
       break;
@@ -1057,6 +972,17 @@ int main(int argc, char **argv_orig, char **envp) {
 
         }
 
+        fsrv.exec_tmout = exec_tmout;
+
+        break;
+
+      case 'O':                                               /* FRIDA mode */
+
+        if (frida_mode) { FATAL("Multiple -O options not supported"); }
+
+        frida_mode = 1;
+        fsrv.frida_mode = frida_mode;
+
         break;
 
       case 'O':                                               /* FRIDA mode */
@@ -1073,6 +999,8 @@ int main(int argc, char **argv_orig, char **envp) {
         if (!mem_limit_given) { mem_limit = MEM_LIMIT_QEMU; }
 
         qemu_mode = 1;
+        fsrv.mem_limit = mem_limit;
+        fsrv.qemu_mode = qemu_mode;
         break;
 
       case 'U':
@@ -1081,6 +1009,7 @@ int main(int argc, char **argv_orig, char **envp) {
         if (!mem_limit_given) { mem_limit = MEM_LIMIT_UNICORN; }
 
         unicorn_mode = 1;
+        fsrv.mem_limit = mem_limit;
         break;
 
       case 'W':                                           /* Wine+QEMU mode */
@@ -1090,6 +1019,8 @@ int main(int argc, char **argv_orig, char **envp) {
         use_wine = 1;
 
         if (!mem_limit_given) { mem_limit = 0; }
+        fsrv.qemu_mode = qemu_mode;
+        fsrv.mem_limit = mem_limit;
 
         break;
 
@@ -1108,6 +1039,7 @@ int main(int argc, char **argv_orig, char **envp) {
   if (optind == argc || !in_file) { usage(argv[0]); }
 
   map_size = get_map_size();
+  fsrv.map_size = map_size;
 
   use_hex_offsets = !!get_afl_env("AFL_ANALYZE_HEX");
 
@@ -1117,14 +1049,15 @@ int main(int argc, char **argv_orig, char **envp) {
 
   /* initialize cmplog_mode */
   shm.cmplog_mode = 0;
-  trace_bits = afl_shm_init(&shm, map_size, 0);
+
   atexit(at_exit_handler);
   setup_signal_handlers();
 
   set_up_environment(argv);
 
-  target_path = find_binary(argv[optind]);
-  detect_file_args(argv + optind, prog_in, &use_stdin);
+  fsrv.target_path = find_binary(argv[optind]);
+  fsrv.trace_bits = afl_shm_init(&shm, map_size, 0);
+  detect_file_args(argv + optind, fsrv.out_file, &use_stdin);
 
   if (qemu_mode) {
 
@@ -1148,14 +1081,31 @@ int main(int argc, char **argv_orig, char **envp) {
 
   SAYF("\n");
 
+  if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
+
+    s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
+    if (forksrv_init_tmout < 1) {
+
+      FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT");
+
+    }
+
+    fsrv.init_tmout = (u32)forksrv_init_tmout;
+
+  }
+
+  fsrv.kill_signal =
+      parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL);
+
   read_initial_file();
 
   ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
        mem_limit, exec_tmout, edges_only ? ", edges only" : "");
 
-  analyze_run_target(use_argv, in_data, in_len, 1);
+  afl_fsrv_start(&fsrv, use_argv, &stop_soon, false);
+  analyze_run_target(in_data, in_len, 1);
 
-  if (child_timed_out) {
+  if (fsrv.last_run_timed_out) {
 
     FATAL("Target binary times out (adjusting -t may help).");
 
@@ -1167,13 +1117,14 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
-  analyze(use_argv);
+  analyze();
 
   OKF("We're done here. Have a nice day!\n");
 
-  if (target_path) { ck_free(target_path); }
-
   afl_shm_deinit(&shm);
+  afl_fsrv_deinit(&fsrv);
+  if (fsrv.target_path) { ck_free(fsrv.target_path); }
+  if (in_data) { ck_free(in_data); }
 
   exit(0);
 
diff --git a/src/afl-cc.c b/src/afl-cc.c
index 486f7468..6a60fb85 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -315,7 +315,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
   u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0, shared_linking = 0,
      preprocessor_only = 0, have_unroll = 0, have_o = 0, have_pic = 0,
-     have_c = 0;
+     have_c = 0, partial_linking = 0;
 
   cc_params = ck_alloc((argc + 128) * sizeof(u8 *));
 
@@ -514,14 +514,14 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
     unsetenv("AFL_LD");
     unsetenv("AFL_LD_CALLER");
+
     if (cmplog_mode) {
 
       if (lto_mode && !have_c) {
 
         cc_params[cc_par_cnt++] = alloc_printf(
-            "-Wl,-mllvm=-load=%s/cmplog-routines-pass.so", obj_path);
-        cc_params[cc_par_cnt++] = alloc_printf(
-            "-Wl,-mllvm=-load=%s/cmplog-instructions-pass.so", obj_path);
+            "-Wl,-mllvm=-load=%s/cmplog-switches-pass.so", obj_path);
+
         cc_params[cc_par_cnt++] = alloc_printf(
             "-Wl,-mllvm=-load=%s/split-switches-pass.so", obj_path);
 
@@ -531,13 +531,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
         cc_params[cc_par_cnt++] = "-load";
         cc_params[cc_par_cnt++] = "-Xclang";
         cc_params[cc_par_cnt++] =
-            alloc_printf("%s/cmplog-routines-pass.so", obj_path);
-
-        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/cmplog-instructions-pass.so", obj_path);
+            alloc_printf("%s/cmplog-switches-pass.so", obj_path);
 
         // reuse split switches from laf
         cc_params[cc_par_cnt++] = "-Xclang";
@@ -746,6 +740,11 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
         cc_params[cc_par_cnt++] = afllib;
 
+#ifdef __APPLE__
+        cc_params[cc_par_cnt++] = "-undefined";
+        cc_params[cc_par_cnt++] = "dynamic_lookup";
+#endif
+
       }
 
       continue;
@@ -767,6 +766,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
     if (!strcmp(cur, "-x")) x_set = 1;
     if (!strcmp(cur, "-E")) preprocessor_only = 1;
     if (!strcmp(cur, "-shared")) shared_linking = 1;
+    if (!strcmp(cur, "-Wl,-r")) partial_linking = 1;
+    if (!strcmp(cur, "-Wl,--relocatable")) partial_linking = 1;
+    if (!strcmp(cur, "-r")) partial_linking = 1;
+    if (!strcmp(cur, "--relocatable")) partial_linking = 1;
     if (!strcmp(cur, "-c")) have_c = 1;
 
     if (!strncmp(cur, "-O", 2)) have_o = 1;
@@ -996,7 +999,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
     switch (bit_mode) {
 
       case 0:
-        if (!shared_linking)
+        if (!shared_linking && !partial_linking)
           cc_params[cc_par_cnt++] =
               alloc_printf("%s/afl-compiler-rt.o", obj_path);
         if (lto_mode)
@@ -1005,7 +1008,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
         break;
 
       case 32:
-        if (!shared_linking) {
+        if (!shared_linking && !partial_linking) {
 
           cc_params[cc_par_cnt++] =
               alloc_printf("%s/afl-compiler-rt-32.o", obj_path);
@@ -1026,7 +1029,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
         break;
 
       case 64:
-        if (!shared_linking) {
+        if (!shared_linking && !partial_linking) {
 
           cc_params[cc_par_cnt++] =
               alloc_printf("%s/afl-compiler-rt-64.o", obj_path);
@@ -1049,7 +1052,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
     }
 
   #if !defined(__APPLE__) && !defined(__sun)
-    if (!shared_linking)
+    if (!shared_linking && !partial_linking)
       cc_params[cc_par_cnt++] =
           alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path);
   #endif
diff --git a/src/afl-common.c b/src/afl-common.c
index c61ce3d8..9ca2b3e8 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -751,6 +751,8 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) {
 
 }
 
+/* Get unix time in milliseconds */
+
 u64 get_cur_time(void) {
 
   struct timeval  tv;
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 3d472b36..8fb8a75a 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -90,6 +90,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
   /* exec related stuff */
   fsrv->child_pid = -1;
   fsrv->map_size = get_map_size();
+  fsrv->real_map_size = fsrv->map_size;
   fsrv->use_fauxsrv = false;
   fsrv->last_run_timed_out = false;
   fsrv->debug = false;
@@ -110,6 +111,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
   fsrv_to->init_tmout = from->init_tmout;
   fsrv_to->mem_limit = from->mem_limit;
   fsrv_to->map_size = from->map_size;
+  fsrv_to->real_map_size = from->real_map_size;
   fsrv_to->support_shmem_fuzz = from->support_shmem_fuzz;
   fsrv_to->out_file = from->out_file;
   fsrv_to->dev_urandom_fd = from->dev_urandom_fd;
@@ -691,15 +693,15 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
         if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; }
 
-        if (unlikely(tmp_map_size % 64)) {
+        fsrv->real_map_size = tmp_map_size;
+
+        if (tmp_map_size % 64) {
 
-          // should not happen
-          WARNF("Target reported non-aligned map size of %u", tmp_map_size);
           tmp_map_size = (((tmp_map_size + 63) >> 6) << 6);
 
         }
 
-        if (!be_quiet) { ACTF("Target map size: %u", tmp_map_size); }
+        if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); }
         if (tmp_map_size > fsrv->map_size) {
 
           FATAL(
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index 97f10e6f..0a9242a5 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -551,19 +551,18 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 
     }
 
-    if (cksum)
-      afl->queue_top->exec_cksum = cksum;
-    else
-      cksum = afl->queue_top->exec_cksum =
-          hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
-
-    if (afl->schedule >= FAST && afl->schedule <= RARE) {
+    /* AFLFast schedule? update the new queue entry */
+    if (cksum) {
 
       afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
       afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
 
     }
 
+    /* due to classify counts we have to recalculate the checksum */
+    cksum = afl->queue_top->exec_cksum =
+        hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+
     /* Try to calibrate inline; this also calls update_bitmap_score() when
        successful. */
 
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 88b5bc02..5e4f1585 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -480,13 +480,22 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
 
   for (iter = 0; iter < afl->foreign_sync_cnt; iter++) {
 
-    if (afl->foreign_syncs[iter].dir != NULL &&
-        afl->foreign_syncs[iter].dir[0] != 0) {
+    if (afl->foreign_syncs[iter].dir && afl->foreign_syncs[iter].dir[0]) {
 
       if (first) ACTF("Scanning '%s'...", afl->foreign_syncs[iter].dir);
       time_t mtime_max = 0;
-      u8 *   name = strrchr(afl->foreign_syncs[iter].dir, '/');
-      if (!name) { name = afl->foreign_syncs[iter].dir; }
+
+      u8 *name = strrchr(afl->foreign_syncs[iter].dir, '/');
+      if (!name) {
+
+        name = afl->foreign_syncs[iter].dir;
+
+      } else {
+
+        ++name;
+
+      }
+
       if (!strcmp(name, "queue") || !strcmp(name, "out") ||
           !strcmp(name, "default")) {
 
@@ -701,96 +710,103 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
 
   }
 
-  for (i = 0; i < (u32)nl_cnt; ++i) {
+  if (nl_cnt) {
 
-    struct stat st;
+    i = nl_cnt;
+    do {
 
-    u8 dfn[PATH_MAX];
-    snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir,
-             nl[i]->d_name);
-    u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name);
+      --i;
 
-    u8 passed_det = 0;
+      struct stat st;
+      u8          dfn[PATH_MAX];
+      snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir,
+               nl[i]->d_name);
+      u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name);
 
-    if (lstat(fn2, &st) || access(fn2, R_OK)) {
+      u8 passed_det = 0;
 
-      PFATAL("Unable to access '%s'", fn2);
+      if (lstat(fn2, &st) || access(fn2, R_OK)) {
 
-    }
+        PFATAL("Unable to access '%s'", fn2);
 
-    /* obviously we want to skip "descending" into . and .. directories,
-       however it is a good idea to skip also directories that start with
-       a dot */
-    if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') {
+      }
 
-      free(nl[i]);                                           /* not tracked */
-      read_testcases(afl, fn2);
-      ck_free(fn2);
-      continue;
+      /* obviously we want to skip "descending" into . and .. directories,
+         however it is a good idea to skip also directories that start with
+         a dot */
+      if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') {
 
-    }
+        free(nl[i]);                                         /* not tracked */
+        read_testcases(afl, fn2);
+        ck_free(fn2);
+        continue;
 
-    free(nl[i]);
+      }
 
-    if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) {
+      free(nl[i]);
 
-      ck_free(fn2);
-      continue;
+      if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) {
 
-    }
+        ck_free(fn2);
+        continue;
 
-    if (st.st_size > MAX_FILE) {
+      }
 
-      WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", fn2,
-            stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
-            stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
+      if (st.st_size > MAX_FILE) {
 
-    }
+        WARNF("Test case '%s' is too big (%s, limit is %s), partial reading",
+              fn2,
+              stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
+              stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
 
-    /* Check for metadata that indicates that deterministic fuzzing
-       is complete for this entry. We don't want to repeat deterministic
-       fuzzing when resuming aborted scans, because it would be pointless
-       and probably very time-consuming. */
+      }
 
-    if (!access(dfn, F_OK)) { passed_det = 1; }
+      /* Check for metadata that indicates that deterministic fuzzing
+         is complete for this entry. We don't want to repeat deterministic
+         fuzzing when resuming aborted scans, because it would be pointless
+         and probably very time-consuming. */
 
-    add_to_queue(afl, fn2, st.st_size >= MAX_FILE ? MAX_FILE : st.st_size,
-                 passed_det);
+      if (!access(dfn, F_OK)) { passed_det = 1; }
 
-    if (unlikely(afl->shm.cmplog_mode)) {
+      add_to_queue(afl, fn2, st.st_size >= MAX_FILE ? MAX_FILE : st.st_size,
+                   passed_det);
 
-      if (afl->cmplog_lvl == 1) {
+      if (unlikely(afl->shm.cmplog_mode)) {
 
-        if (!afl->cmplog_max_filesize ||
-            afl->cmplog_max_filesize < st.st_size) {
+        if (afl->cmplog_lvl == 1) {
 
-          afl->cmplog_max_filesize = st.st_size;
+          if (!afl->cmplog_max_filesize ||
+              afl->cmplog_max_filesize < st.st_size) {
 
-        }
+            afl->cmplog_max_filesize = st.st_size;
 
-      } else if (afl->cmplog_lvl == 2) {
+          }
+
+        } else if (afl->cmplog_lvl == 2) {
 
-        if (!afl->cmplog_max_filesize ||
-            afl->cmplog_max_filesize > st.st_size) {
+          if (!afl->cmplog_max_filesize ||
+              afl->cmplog_max_filesize > st.st_size) {
 
-          afl->cmplog_max_filesize = st.st_size;
+            afl->cmplog_max_filesize = st.st_size;
+
+          }
 
         }
 
       }
 
-    }
+      /*
+          if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
 
-    /*
-        if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
+            u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size,
+         HASH_CONST); afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
+            afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
 
-          u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size,
-       HASH_CONST); afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
-          afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
+          }
 
-        }
+      */
 
-    */
+    } while (i > 0);
 
   }
 
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index e27d6fae..79a47744 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -393,6 +393,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf,
 
       if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; }
 
+      classify_counts(&afl->fsrv);
       cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
 
     }
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index c3ce2edd..1bc5854e 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -73,7 +73,7 @@ static int select_algorithm(afl_state_t *afl, u32 max_algorithm) {
 /* Helper to choose random block len for block operations in fuzz_one().
    Doesn't return zero, provided that max_len is > 0. */
 
-static u32 choose_block_len(afl_state_t *afl, u32 limit) {
+static inline u32 choose_block_len(afl_state_t *afl, u32 limit) {
 
   u32 min_value, max_value;
   u32 rlim = MIN(afl->queue_cycle, (u32)3);
@@ -2057,7 +2057,7 @@ havoc_stage:
               temp_len = new_len;
               if (out_buf != custom_havoc_buf) {
 
-                afl_realloc(AFL_BUF_PARAM(out), temp_len);
+                out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len);
                 if (unlikely(!afl->out_buf)) { PFATAL("alloc"); }
                 memcpy(out_buf, custom_havoc_buf, temp_len);
 
@@ -2102,9 +2102,9 @@ havoc_stage:
 
         case 8 ... 9: {
 
-          /* Set word to interesting value, randomly choosing endian. */
+        case 8 ... 9: {
 
-          if (temp_len < 2) { break; }
+          /* Set word to interesting value, little endian. */
 
 #ifdef INTROSPECTION
           snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16");
@@ -2136,9 +2136,9 @@ havoc_stage:
 
         case 12 ... 13: {
 
-          /* Set dword to interesting value, randomly choosing endian. */
+        case 12 ... 13: {
 
-          if (temp_len < 4) { break; }
+          /* Set dword to interesting value, little endian. */
 
 #ifdef INTROSPECTION
           snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32");
@@ -2862,6 +2862,7 @@ abandon_entry:
 
       --afl->pending_not_fuzzed;
       afl->queue_cur->was_fuzzed = 1;
+      afl->reinit_table = 1;
       if (afl->queue_cur->favored) { --afl->pending_favored; }
 
     }
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index 811e805c..b759532c 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -58,7 +58,8 @@ double compute_weight(afl_state_t *afl, struct queue_entry *q,
   if (likely(afl->schedule < RARE)) { weight *= (avg_exec_us / q->exec_us); }
   weight *= (log(q->bitmap_size) / avg_bitmap_size);
   weight *= (1 + (q->tc_ref / avg_top_size));
-  if (unlikely(q->favored)) weight *= 5;
+  if (unlikely(q->favored)) { weight *= 5; }
+  if (unlikely(!q->was_fuzzed)) { weight *= 2; }
 
   return weight;
 
@@ -198,6 +199,8 @@ void create_alias_table(afl_state_t *afl) {
   while (nS)
     afl->alias_probability[S[--nS]] = 1;
 
+  afl->reinit_table = 0;
+
   /*
   #ifdef INTROSPECTION
     u8 fn[PATH_MAX];
@@ -1132,12 +1135,10 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) {
 
         do_once = 1;
         // release unneeded memory
-        u8 *ptr = ck_realloc(
+        afl->q_testcase_cache = ck_realloc(
             afl->q_testcase_cache,
             (afl->q_testcase_max_cache_entries + 1) * sizeof(size_t));
 
-        if (ptr) { afl->q_testcase_cache = (struct queue_entry **)ptr; }
-
       }
 
       /* Cache full. We neet to evict one or more to map one.
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index 22fd0621..268f726c 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -252,7 +252,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
   u64 start_time = get_cur_time();
 #endif
 
-  u32 screen_update = 1000000 / afl->queue_cur->exec_us;
+  u32 screen_update;
   u64 orig_hit_cnt, new_hit_cnt, exec_cksum;
   orig_hit_cnt = afl->queued_paths + afl->unique_crashes;
 
@@ -261,6 +261,24 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
   afl->stage_max = (len << 1);
   afl->stage_cur = 0;
 
+  if (likely(afl->queue_cur->exec_us)) {
+
+    if (likely((100000 / 2) >= afl->queue_cur->exec_us)) {
+
+      screen_update = 100000 / afl->queue_cur->exec_us;
+
+    } else {
+
+      screen_update = 1;
+
+    }
+
+  } else {
+
+    screen_update = 100000;
+
+  }
+
   // in colorization we do not classify counts, hence we have to calculate
   // the original checksum.
   if (unlikely(get_exec_checksum(afl, buf, len, &exec_cksum))) {
@@ -905,17 +923,16 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
       // test for arithmetic, eg. "if ((user_val - 0x1111) == 0x1234) ..."
       s64 diff = pattern - b_val;
       s64 o_diff = o_pattern - o_b_val;
-      /*
-            fprintf(stderr, "DIFF1 idx=%03u shape=%02u %llx-%llx=%lx\n", idx,
-                    h->shape + 1, o_pattern, o_b_val, o_diff);
-            fprintf(stderr, "DIFF1 %016llx %llx-%llx=%lx\n", repl, pattern,
-         b_val, diff);*/
+      /* fprintf(stderr, "DIFF1 idx=%03u shape=%02u %llx-%llx=%lx\n", idx,
+                 h->shape + 1, o_pattern, o_b_val, o_diff);
+         fprintf(stderr, "DIFF1 %016llx %llx-%llx=%lx\n", repl, pattern,
+                 b_val, diff); */
       if (diff == o_diff && diff) {
 
         // this could be an arithmetic transformation
 
         u64 new_repl = (u64)((s64)repl - diff);
-        //        fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
+        // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
 
         if (unlikely(cmp_extend_encoding(
                 afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx,
@@ -935,15 +952,17 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
         diff = pattern ^ b_val;
         s64 o_diff = o_pattern ^ o_b_val;
 
-        /*        fprintf(stderr, "DIFF2 idx=%03u shape=%02u %llx-%llx=%lx\n",
-           idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr,
-           "DIFF2 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/
+        /* fprintf(stderr, "DIFF2 idx=%03u shape=%02u %llx-%llx=%lx\n",
+                   idx, h->shape + 1, o_pattern, o_b_val, o_diff);
+           fprintf(stderr,
+                   "DIFF2 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);
+        */
         if (diff == o_diff && diff) {
 
           // this could be a XOR transformation
 
           u64 new_repl = (u64)((s64)repl ^ diff);
-          //          fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
+          // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
 
           if (unlikely(cmp_extend_encoding(
                   afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx,
@@ -982,15 +1001,17 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
 
         }
 
-        /*        fprintf(stderr, "DIFF3 idx=%03u shape=%02u %llx-%llx=%lx\n",
-           idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr,
-           "DIFF3 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/
+        /* fprintf(stderr, "DIFF3 idx=%03u shape=%02u %llx-%llx=%lx\n",
+                   idx, h->shape + 1, o_pattern, o_b_val, o_diff);
+           fprintf(stderr,
+                   "DIFF3 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);
+        */
         if (o_diff && diff) {
 
           // this could be a lower to upper
 
           u64 new_repl = (repl & (0x5f5f5f5f5f5f5f5f & mask));
-          //          fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
+          // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
 
           if (unlikely(cmp_extend_encoding(
                   afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx,
@@ -1029,15 +1050,17 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
 
         }
 
-        /*        fprintf(stderr, "DIFF4 idx=%03u shape=%02u %llx-%llx=%lx\n",
-           idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr,
-           "DIFF4 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/
+        /* fprintf(stderr, "DIFF4 idx=%03u shape=%02u %llx-%llx=%lx\n",
+                   idx, h->shape + 1, o_pattern, o_b_val, o_diff);
+           fprintf(stderr,
+                   "DIFF4 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);
+        */
         if (o_diff && diff) {
 
           // this could be a lower to upper
 
           u64 new_repl = (repl | (0x2020202020202020 & mask));
-          //          fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
+          // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl);
 
           if (unlikely(cmp_extend_encoding(
                   afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx,
@@ -1383,7 +1406,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
 
   }
 
-  //#endif                                           /* CMPLOG_SOLVE_ARITHMETIC
+  //#endif                                           /*
+  // CMPLOG_SOLVE_ARITHMETIC
 
   return 0;
 
@@ -2152,7 +2176,8 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl,
 
         memcpy(buf + idx, tmp, i + 1);
         if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
-        // fprintf(stderr, "RTN ATTEMPT tohex %u result %u\n", tohex, *status);
+        // fprintf(stderr, "RTN ATTEMPT tohex %u result %u\n", tohex,
+        // *status);
 
       }
 
@@ -2235,7 +2260,8 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl,
         for (j = 0; j <= i; j++)
           buf[idx + j] = repl[j] - arith_val[j];
         if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
-        // fprintf(stderr, "RTN ATTEMPT arith %u result %u\n", arith, *status);
+        // fprintf(stderr, "RTN ATTEMPT arith %u result %u\n", arith,
+        // *status);
 
       }
 
@@ -2328,16 +2354,17 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
 
     /*
       struct cmp_header *hh = &afl->orig_cmp_map->headers[key];
-    fprintf(stderr, "RTN N hits=%u id=%u shape=%u attr=%u v0=", h->hits, h->id,
-    h->shape, h->attribute); for (j = 0; j < 8; j++) fprintf(stderr, "%02x",
-    o->v0[j]); fprintf(stderr, " v1="); for (j = 0; j < 8; j++) fprintf(stderr,
-    "%02x", o->v1[j]); fprintf(stderr, "\nRTN O hits=%u id=%u shape=%u attr=%u
-    o0=", hh->hits, hh->id, hh->shape, hh->attribute); for (j = 0; j < 8; j++)
-      fprintf(stderr, "%02x", orig_o->v0[j]);
-    fprintf(stderr, " o1=");
-    for (j = 0; j < 8; j++)
-      fprintf(stderr, "%02x", orig_o->v1[j]);
-    fprintf(stderr, "\n");
+      fprintf(stderr, "RTN N hits=%u id=%u shape=%u attr=%u v0=", h->hits,
+              h->id, h->shape, h->attribute);
+      for (j = 0; j < 8; j++) fprintf(stderr, "%02x", o->v0[j]);
+      fprintf(stderr, " v1=");
+      for (j = 0; j < 8; j++) fprintf(stderr, "%02x", o->v1[j]);
+      fprintf(stderr, "\nRTN O hits=%u id=%u shape=%u attr=%u o0=",
+              hh->hits, hh->id, hh->shape, hh->attribute);
+      for (j = 0; j < 8; j++) fprintf(stderr, "%02x", orig_o->v0[j]);
+      fprintf(stderr, " o1=");
+      for (j = 0; j < 8; j++) fprintf(stderr, "%02x", orig_o->v1[j]);
+      fprintf(stderr, "\n");
     */
 
     t = taint;
@@ -2663,7 +2690,12 @@ exit_its:
 
     afl->queue_cur->colorized = CMPLOG_LVL_MAX;
 
-    ck_free(afl->queue_cur->cmplog_colorinput);
+    if (afl->queue_cur->cmplog_colorinput) {
+
+      ck_free(afl->queue_cur->cmplog_colorinput);
+
+    }
+
     while (taint) {
 
       t = taint->next;
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 2c3e8a1b..fb81522e 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -314,7 +314,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
   ++q->cal_failed;
 
   afl->stage_name = "calibration";
-  afl->stage_max = afl->fast_cal ? 3 : CAL_CYCLES;
+  afl->stage_max = afl->afl_env.afl_cal_fast ? 3 : CAL_CYCLES;
 
   /* Make sure the forkserver is up before we do anything, and let's not
      count its spin-up time toward binary calibration. */
@@ -333,7 +333,6 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
 
     if (afl->fsrv.support_shmem_fuzz && !afl->fsrv.use_shmem_fuzz) {
 
-      unsetenv(SHM_FUZZ_ENV_VAR);
       afl_shm_deinit(afl->shm_fuzz);
       ck_free(afl->shm_fuzz);
       afl->shm_fuzz = NULL;
@@ -356,6 +355,12 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
 
   for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
 
+    if (unlikely(afl->debug)) {
+
+      DEBUGF("calibration stage %d/%d\n", afl->stage_cur + 1, afl->stage_max);
+
+    }
+
     u64 cksum;
 
     write_to_testcase(afl, use_mem, q->len);
@@ -403,6 +408,21 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
 
         }
 
+        if (unlikely(!var_detected)) {
+
+          // note: from_queue seems to only be set during initialization
+          if (afl->afl_env.afl_no_ui || from_queue) {
+
+            WARNF("instability detected during calibration");
+
+          } else if (afl->debug) {
+
+            DEBUGF("instability detected during calibration\n");
+
+          }
+
+        }
+
         var_detected = 1;
         afl->stage_max = afl->fast_cal ? CAL_CYCLES : CAL_CYCLES_LONG;
 
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index 0658070e..b832c11e 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -96,8 +96,6 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
   afl->splicing_with = -1;              /* Splicing with which test case?   */
   afl->cpu_to_bind = -1;
   afl->havoc_stack_pow2 = HAVOC_STACK_POW2;
-  afl->cal_cycles = CAL_CYCLES;
-  afl->cal_cycles_long = CAL_CYCLES_LONG;
   afl->hang_tmout = EXEC_TIMEOUT;
   afl->exit_on_time = 0;
   afl->stats_update_freq = 1;
@@ -341,6 +339,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
             afl->afl_env.afl_cal_fast =
                 get_afl_env(afl_environment_variables[i]) ? 1 : 0;
 
+          } else if (!strncmp(env, "AFL_FAST_CAL",
+
+                              afl_environment_variable_len)) {
+
+            afl->afl_env.afl_cal_fast =
+                get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
           } else if (!strncmp(env, "AFL_STATSD",
 
                               afl_environment_variable_len)) {
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 4884b942..c2294f7c 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -264,6 +264,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
           "peak_rss_mb       : %lu\n"
           "cpu_affinity      : %d\n"
           "edges_found       : %u\n"
+          "total_edges       : %u\n"
           "var_byte_count    : %u\n"
           "havoc_expansion   : %u\n"
           "testcache_size    : %llu\n"
@@ -303,10 +304,10 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
 #else
           -1,
 #endif
-          t_bytes, afl->var_byte_count, afl->expand_havoc,
-          afl->q_testcase_cache_size, afl->q_testcase_cache_count,
-          afl->q_testcase_evictions, afl->use_banner,
-          afl->unicorn_mode ? "unicorn" : "",
+          t_bytes, afl->fsrv.real_map_size, afl->var_byte_count,
+          afl->expand_havoc, afl->q_testcase_cache_size,
+          afl->q_testcase_cache_count, afl->q_testcase_evictions,
+          afl->use_banner, afl->unicorn_mode ? "unicorn" : "",
           afl->fsrv.qemu_mode ? "qemu " : "",
           afl->non_instrumented_mode ? " non_instrumented " : "",
           afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "",
@@ -326,7 +327,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
 
     u32 i = 0;
     fprintf(f, "virgin_bytes     :");
-    for (i = 0; i < afl->fsrv.map_size; i++) {
+    for (i = 0; i < afl->fsrv.real_map_size; i++) {
 
       if (afl->virgin_bits[i] != 0xff) {
 
@@ -338,7 +339,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
 
     fprintf(f, "\n");
     fprintf(f, "var_bytes        :");
-    for (i = 0; i < afl->fsrv.map_size; i++) {
+    for (i = 0; i < afl->fsrv.real_map_size; i++) {
 
       if (afl->var_bytes[i]) { fprintf(f, " %u", i); }
 
@@ -520,7 +521,7 @@ void show_stats(afl_state_t *afl) {
   /* Do some bitmap stats. */
 
   t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
-  t_byte_ratio = ((double)t_bytes * 100) / afl->fsrv.map_size;
+  t_byte_ratio = ((double)t_bytes * 100) / afl->fsrv.real_map_size;
 
   if (likely(t_bytes) && unlikely(afl->var_byte_count)) {
 
@@ -766,9 +767,9 @@ void show_stats(afl_state_t *afl) {
                 "   uniq hangs : " cRST "%-6s" bSTG         bV "\n",
        time_tmp, tmp);
 
-  SAYF(bVR bH bSTOP                                          cCYA
-       " cycle progress " bSTG bH10 bH5 bH2 bH2 bHB bH bSTOP cCYA
-       " map coverage " bSTG bH bHT bH20 bH2                 bVL "\n");
+  SAYF(bVR bH bSTOP                                              cCYA
+       " cycle progress " bSTG bH10 bH5 bH2 bH2 bH2 bHB bH bSTOP cCYA
+       " map coverage" bSTG bHT bH20 bH2                         bVL "\n");
 
   /* This gets funny because we want to print several variable-length variables
      together, but then cram them into a fixed-width field - so we need to
@@ -778,13 +779,13 @@ void show_stats(afl_state_t *afl) {
           afl->queue_cur->favored ? "." : "*", afl->queue_cur->fuzz_level,
           ((double)afl->current_entry * 100) / afl->queued_paths);
 
-  SAYF(bV bSTOP "  now processing : " cRST "%-16s " bSTG bV bSTOP, tmp);
+  SAYF(bV bSTOP "  now processing : " cRST "%-18s " bSTG bV bSTOP, tmp);
 
   sprintf(tmp, "%0.02f%% / %0.02f%%",
-          ((double)afl->queue_cur->bitmap_size) * 100 / afl->fsrv.map_size,
+          ((double)afl->queue_cur->bitmap_size) * 100 / afl->fsrv.real_map_size,
           t_byte_ratio);
 
-  SAYF("    map density : %s%-21s" bSTG bV "\n",
+  SAYF("    map density : %s%-19s" bSTG bV "\n",
        t_byte_ratio > 70
            ? cLRD
            : ((t_bytes < 200 && !afl->non_instrumented_mode) ? cPIN : cRST),
@@ -793,23 +794,23 @@ void show_stats(afl_state_t *afl) {
   sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->cur_skipped_paths),
           ((double)afl->cur_skipped_paths * 100) / afl->queued_paths);
 
-  SAYF(bV bSTOP " paths timed out : " cRST "%-16s " bSTG bV, tmp);
+  SAYF(bV bSTOP " paths timed out : " cRST "%-18s " bSTG bV, tmp);
 
   sprintf(tmp, "%0.02f bits/tuple", t_bytes ? (((double)t_bits) / t_bytes) : 0);
 
-  SAYF(bSTOP " count coverage : " cRST "%-21s" bSTG bV "\n", tmp);
+  SAYF(bSTOP " count coverage : " cRST "%-19s" bSTG bV "\n", tmp);
 
-  SAYF(bVR bH bSTOP                                         cCYA
-       " stage progress " bSTG bH10 bH5 bH2 bH2 bX bH bSTOP cCYA
-       " findings in depth " bSTG bH10 bH5 bH2 bH2          bVL "\n");
+  SAYF(bVR bH bSTOP                                             cCYA
+       " stage progress " bSTG bH10 bH5 bH2 bH2 bH2 bX bH bSTOP cCYA
+       " findings in depth " bSTG bH10 bH5 bH2                  bVL "\n");
 
   sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->queued_favored),
           ((double)afl->queued_favored) * 100 / afl->queued_paths);
 
   /* Yeah... it's still going on... halp? */
 
-  SAYF(bV bSTOP "  now trying : " cRST "%-20s " bSTG bV bSTOP
-                " favored paths : " cRST "%-22s" bSTG   bV "\n",
+  SAYF(bV bSTOP "  now trying : " cRST "%-22s " bSTG bV bSTOP
+                " favored paths : " cRST "%-20s" bSTG   bV "\n",
        afl->stage_name, tmp);
 
   if (!afl->stage_max) {
@@ -824,12 +825,12 @@ void show_stats(afl_state_t *afl) {
 
   }
 
-  SAYF(bV bSTOP " stage execs : " cRST "%-21s" bSTG bV bSTOP, tmp);
+  SAYF(bV bSTOP " stage execs : " cRST "%-23s" bSTG bV bSTOP, tmp);
 
   sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->queued_with_cov),
           ((double)afl->queued_with_cov) * 100 / afl->queued_paths);
 
-  SAYF("  new edges on : " cRST "%-22s" bSTG bV "\n", tmp);
+  SAYF("  new edges on : " cRST "%-20s" bSTG bV "\n", tmp);
 
   sprintf(tmp, "%s (%s%s unique)", u_stringify_int(IB(0), afl->total_crashes),
           u_stringify_int(IB(1), afl->unique_crashes),
@@ -837,14 +838,14 @@ void show_stats(afl_state_t *afl) {
 
   if (afl->crash_mode) {
 
-    SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP
-                  "   new crashes : %s%-22s" bSTG         bV "\n",
+    SAYF(bV bSTOP " total execs : " cRST "%-22s " bSTG bV bSTOP
+                  "   new crashes : %s%-20s" bSTG         bV "\n",
          u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp);
 
   } else {
 
-    SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP
-                  " total crashes : %s%-22s" bSTG         bV "\n",
+    SAYF(bV bSTOP " total execs : " cRST "%-22s " bSTG bV bSTOP
+                  " total crashes : %s%-20s" bSTG         bV "\n",
          u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp);
 
   }
@@ -856,12 +857,12 @@ void show_stats(afl_state_t *afl) {
     sprintf(tmp, "%s/sec (%s)", u_stringify_float(IB(0), afl->stats_avg_exec),
             afl->stats_avg_exec < 20 ? "zzzz..." : "slow!");
 
-    SAYF(bV bSTOP "  exec speed : " cLRD "%-20s ", tmp);
+    SAYF(bV bSTOP "  exec speed : " cLRD "%-22s ", tmp);
 
   } else {
 
     sprintf(tmp, "%s/sec", u_stringify_float(IB(0), afl->stats_avg_exec));
-    SAYF(bV bSTOP "  exec speed : " cRST "%-20s ", tmp);
+    SAYF(bV bSTOP "  exec speed : " cRST "%-22s ", tmp);
 
   }
 
@@ -869,13 +870,16 @@ void show_stats(afl_state_t *afl) {
           u_stringify_int(IB(1), afl->unique_tmouts),
           (afl->unique_hangs >= KEEP_UNIQUE_HANG) ? "+" : "");
 
-  SAYF(bSTG bV bSTOP "  total tmouts : " cRST "%-22s" bSTG bV "\n", tmp);
+  SAYF(bSTG bV bSTOP "  total tmouts : " cRST "%-20s" bSTG bV "\n", tmp);
 
   /* Aaaalmost there... hold on! */
 
-  SAYF(bVR bH cCYA                                                     bSTOP
-       " fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA
-       " path geometry " bSTG bH5 bH2 bVL "\n");
+  SAYF(bVR bH cCYA bSTOP " fuzzing strategy yields " bSTG bH10 bH2 bHT bH10 bH2
+           bH bHB bH bSTOP cCYA " path geometry " bSTG bH5 bH2 bVL "\n");
+
+  if (unlikely(afl->custom_only)) {
+
+    strcpy(tmp, "disabled (custom-mutator-only mode)");
 
   if (unlikely(afl->custom_only)) {
 
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 5bdb4c8d..0c7b6e42 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -125,7 +125,7 @@ static void usage(u8 *argv0, int more_help) {
       "entering the\n"
       "                  pacemaker mode (minutes of no new paths). 0 = "
       "immediately,\n"
-      "                  -1 = immediately and together with normal mutation).\n"
+      "                  -1 = immediately and together with normal mutation.\n"
       "                  See docs/README.MOpt.md\n"
       "  -c program    - enable CmpLog by specifying a binary compiled for "
       "it.\n"
@@ -143,7 +143,7 @@ static void usage(u8 *argv0, int more_help) {
       "  -x dict_file  - fuzzer dictionary (see README.md, specify up to 4 "
       "times)\n\n"
 
-      "Testing settings:\n"
+      "Test settings:\n"
       "  -s seed       - use a fixed seed for the RNG\n"
       "  -V seconds    - fuzz for a specified time then terminate\n"
       "  -E execs      - fuzz for an approx. no. of total executions then "
@@ -158,7 +158,7 @@ static void usage(u8 *argv0, int more_help) {
       "  -F path       - sync to a foreign fuzzer queue directory (requires "
       "-M, can\n"
       "                  be specified up to %u times)\n"
-      "  -d            - skip deterministic fuzzing in -M mode\n"
+      // "  -d            - skip deterministic fuzzing in -M mode\n"
       "  -T text       - text banner to show on the screen\n"
       "  -I command    - execute this command/script when a new crash is "
       "found\n"
@@ -575,7 +575,6 @@ int main(int argc, char **argv_orig, char **envp) {
         }
 
         afl->sync_id = ck_strdup(optarg);
-        afl->skip_deterministic = 0;  // force deterministic fuzzing
         afl->old_seed_selection = 1;  // force old queue walking seed selection
         afl->disable_trim = 1;        // disable trimming
 
@@ -1206,6 +1205,8 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  setenv("__AFL_OUT_DIR", afl->out_dir, 1);
+
   if (get_afl_env("AFL_DISABLE_TRIM")) { afl->disable_trim = 1; }
 
   if (getenv("AFL_NO_UI") && getenv("AFL_FORCE_UI")) {
@@ -1275,7 +1276,6 @@ int main(int argc, char **argv_orig, char **envp) {
   if (get_afl_env("AFL_NO_CPU_RED")) { afl->no_cpu_meter_red = 1; }
   if (get_afl_env("AFL_NO_ARITH")) { afl->no_arith = 1; }
   if (get_afl_env("AFL_SHUFFLE_QUEUE")) { afl->shuffle_queue = 1; }
-  if (get_afl_env("AFL_FAST_CAL")) { afl->fast_cal = 1; }
   if (get_afl_env("AFL_EXPAND_HAVOC_NOW")) { afl->expand_havoc = 1; }
 
   if (afl->afl_env.afl_autoresume) {
@@ -1488,14 +1488,6 @@ int main(int argc, char **argv_orig, char **envp) {
   check_if_tty(afl);
   if (afl->afl_env.afl_force_ui) { afl->not_on_tty = 0; }
 
-  if (afl->afl_env.afl_cal_fast) {
-
-    /* Use less calibration cycles, for slow applications */
-    afl->cal_cycles = 3;
-    afl->cal_cycles_long = 5;
-
-  }
-
   if (afl->afl_env.afl_custom_mutator_only) {
 
     /* This ensures we don't proceed to havoc/splice */
@@ -1919,7 +1911,12 @@ int main(int argc, char **argv_orig, char **envp) {
   if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl);
 
   afl->start_time = get_cur_time();
-  if (afl->in_place_resume || afl->afl_env.afl_autoresume) load_stats_file(afl);
+  if (afl->in_place_resume || afl->afl_env.afl_autoresume) {
+
+    load_stats_file(afl);
+
+  }
+
   write_stats_file(afl, 0, 0, 0, 0);
   maybe_update_plot_file(afl, 0, 0, 0);
   save_auto(afl);
@@ -2157,7 +2154,8 @@ int main(int argc, char **argv_orig, char **envp) {
 
       if (likely(!afl->old_seed_selection)) {
 
-        if (unlikely(prev_queued_paths < afl->queued_paths)) {
+        if (unlikely(prev_queued_paths < afl->queued_paths ||
+                     afl->reinit_table)) {
 
           // we have new queue entries since the last run, recreate alias table
           prev_queued_paths = afl->queued_paths;
@@ -2283,13 +2281,10 @@ stop_fuzzing:
   destroy_queue(afl);
   destroy_extras(afl);
   destroy_custom_mutators(afl);
-  unsetenv(SHM_ENV_VAR);
-  unsetenv(CMPLOG_SHM_ENV_VAR);
   afl_shm_deinit(&afl->shm);
 
   if (afl->shm_fuzz) {
 
-    unsetenv(SHM_FUZZ_ENV_VAR);
     afl_shm_deinit(afl->shm_fuzz);
     ck_free(afl->shm_fuzz);
 
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index 96b72dd9..5278c839 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -67,6 +67,8 @@ static char *stdin_file;               /* stdin file                        */
 static u8 *in_dir = NULL,              /* input folder                      */
     *out_file = NULL, *at_file = NULL;        /* Substitution string for @@ */
 
+static u8 outfile[PATH_MAX];
+
 static u8 *in_data,                    /* Input data                        */
     *coverage_map;                     /* Coverage map                      */
 
@@ -230,7 +232,11 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
   u8 cco = !!getenv("AFL_CMIN_CRASHES_ONLY"),
      caa = !!getenv("AFL_CMIN_ALLOW_ANY");
 
-  if (!outfile) { FATAL("Output filename not set (Bug in AFL++?)"); }
+  if (!outfile || !*outfile) {
+
+    FATAL("Output filename not set (Bug in AFL++?)");
+
+  }
 
   if (cmin_mode &&
       (fsrv->last_run_timed_out || (!caa && child_crashed != cco))) {
@@ -394,7 +400,28 @@ static u32 read_file(u8 *in_file) {
 
   if (fstat(fd, &st) || !st.st_size) {
 
-    WARNF("Zero-sized input file '%s'.", in_file);
+    if (!be_quiet && !quiet_mode) {
+
+      WARNF("Zero-sized input file '%s'.", in_file);
+
+    }
+
+  }
+
+  if (st.st_size > MAX_FILE) {
+
+    if (!be_quiet && !quiet_mode) {
+
+      WARNF("Input file '%s' is too large, only reading %u bytes.", in_file,
+            MAX_FILE);
+
+    }
+
+    in_len = MAX_FILE;
+
+  } else {
+
+    in_len = st.st_size;
 
   }
 
@@ -692,6 +719,96 @@ static void setup_signal_handlers(void) {
 
 }
 
+u32 execute_testcases(u8 *dir) {
+
+  struct dirent **nl;
+  s32             nl_cnt, subdirs = 1;
+  u32             i, done = 0;
+  u8              val_buf[2][STRINGIFY_VAL_SIZE_MAX];
+
+  if (!be_quiet) { ACTF("Scanning '%s'...", dir); }
+
+  /* We use scandir() + alphasort() rather than readdir() because otherwise,
+     the ordering of test cases would vary somewhat randomly and would be
+     difficult to control. */
+
+  nl_cnt = scandir(dir, &nl, NULL, alphasort);
+
+  if (nl_cnt < 0) { return 0; }
+
+  for (i = 0; i < (u32)nl_cnt; ++i) {
+
+    struct stat st;
+
+    u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name);
+
+    if (lstat(fn2, &st) || access(fn2, R_OK)) {
+
+      PFATAL("Unable to access '%s'", fn2);
+
+    }
+
+    /* obviously we want to skip "descending" into . and .. directories,
+       however it is a good idea to skip also directories that start with
+       a dot */
+    if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') {
+
+      free(nl[i]);                                           /* not tracked */
+      done += execute_testcases(fn2);
+      ck_free(fn2);
+      continue;
+
+    }
+
+    if (!S_ISREG(st.st_mode) || !st.st_size) {
+
+      free(nl[i]);
+      ck_free(fn2);
+      continue;
+
+    }
+
+    if (st.st_size > MAX_FILE && !be_quiet && !quiet_mode) {
+
+      WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", fn2,
+            stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
+            stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
+
+    }
+
+    if (!collect_coverage)
+      snprintf(outfile, sizeof(outfile), "%s/%s", out_file, nl[i]->d_name);
+
+    free(nl[i]);
+
+    if (read_file(fn2)) {
+
+      if (wait_for_gdb) {
+
+        fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid);
+        fprintf(stderr, "exec: kill -CONT %d\n", getpid());
+        kill(0, SIGSTOP);
+
+      }
+
+      showmap_run_target_forkserver(fsrv, in_data, in_len);
+      ck_free(in_data);
+      ++done;
+
+      if (collect_coverage)
+        analyze_results(fsrv);
+      else
+        tcnt = write_results_to_file(fsrv, outfile);
+
+    }
+
+  }
+
+  free(nl);                                                  /* not tracked */
+  return done;
+
+}
+
 /* Show banner. */
 
 static void show_banner(void) {
@@ -710,7 +827,7 @@ static void usage(u8 *argv0) {
       "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
 
       "Required parameters:\n"
-      "  -o file       - file to write the trace data to\n\n"
+      "  -o file    - file to write the trace data to\n\n"
 
       "Execution control settings:\n"
       "  -t msec       - timeout for each run (none)\n"
@@ -722,19 +839,19 @@ static void usage(u8 *argv0) {
       "                  (Not necessary, here for consistency with other afl-* "
       "tools)\n\n"
       "Other settings:\n"
-      "  -i dir        - process all files in this directory, must be combined "
+      "  -i dir     - process all files below this directory, must be combined "
       "with -o.\n"
-      "                  With -C, -o is a file, without -C it must be a "
+      "               With -C, -o is a file, without -C it must be a "
       "directory\n"
-      "                  and each bitmap will be written there individually.\n"
-      "  -C            - collect coverage, writes all edges to -o and gives a "
+      "               and each bitmap will be written there individually.\n"
+      "  -C         - collect coverage, writes all edges to -o and gives a "
       "summary\n"
-      "                  Must be combined with -i.\n"
-      "  -q            - sink program's output and don't show messages\n"
-      "  -e            - show edge coverage only, ignore hit counts\n"
-      "  -r            - show real tuple values instead of AFL filter values\n"
-      "  -s            - do not classify the map\n"
-      "  -c            - allow core dumps\n\n"
+      "               Must be combined with -i.\n"
+      "  -q         - sink program's output and don't show messages\n"
+      "  -e         - show edge coverage only, ignore hit counts\n"
+      "  -r         - show real tuple values instead of AFL filter values\n"
+      "  -s         - do not classify the map\n"
+      "  -c         - allow core dumps\n\n"
 
       "This tool displays raw tuple data captured by AFL instrumentation.\n"
       "For additional help, consult %s/README.md.\n\n"
@@ -1000,6 +1117,11 @@ int main(int argc, char **argv_orig, char **envp) {
 
   check_environment_vars(envp);
 
+  if (getenv("AFL_NO_FORKSRV")) {             /* if set, use the fauxserver */
+    fsrv->use_fauxsrv = true;
+
+  }
+
   if (getenv("AFL_DEBUG")) {
 
     DEBUGF("");
@@ -1177,7 +1299,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
     } else {
 
-      if ((coverage_map = (u8 *)malloc(map_size)) == NULL)
+      if ((coverage_map = (u8 *)malloc(map_size + 64)) == NULL)
         FATAL("coult not grab memory");
       edges_only = false;
       raw_instr_output = true;
@@ -1260,44 +1382,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
         continue;  // skip anything that starts with '.'
 
-      }
-
-#if defined(DT_REG)      /* Posix and Solaris do not know d_type and DT_REG */
-      if (dir_ent->d_type != DT_REG) {
-
-        continue;  // only regular files
-
-      }
-
-#endif
-
-      snprintf(infile, sizeof(infile), "%s/%s", in_dir, dir_ent->d_name);
-
-#if !defined(DT_REG)                                          /* use stat() */
-      if (-1 == stat(infile, &statbuf) || !S_ISREG(statbuf.st_mode)) continue;
-#endif
-
-      if (!collect_coverage)
-        snprintf(outfile, sizeof(outfile), "%s/%s", out_file, dir_ent->d_name);
-
-      if (read_file(infile)) {
-
-        if (wait_for_gdb) {
-
-          fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid);
-          fprintf(stderr, "exec: kill -CONT %d\n", getpid());
-          kill(0, SIGSTOP);
-
-        }
-
-        showmap_run_target_forkserver(fsrv, in_data, in_len);
-        ck_free(in_data);
-        if (collect_coverage)
-          analyze_results(fsrv);
-        else
-          tcnt = write_results_to_file(fsrv, outfile);
-
-      }
+      FATAL("could not read input testcases from %s", in_dir);
 
     }
 
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index 6656712a..2d80abe4 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -877,12 +877,13 @@ static void usage(u8 *argv0) {
       "              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_NO_FORKSRV: run target via execve instead of using the forkserver\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);
+      "TMPDIR: directory to use for temporary input files\n",
+      argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
 
   exit(1);
 
@@ -1104,6 +1105,12 @@ int main(int argc, char **argv_orig, char **envp) {
   if (optind == argc || !in_file || !output_file) { usage(argv[0]); }
 
   check_environment_vars(envp);
+
+  if (getenv("AFL_NO_FORKSRV")) {             /* if set, use the fauxserver */
+    fsrv->use_fauxsrv = true;
+
+  }
+
   setenv("AFL_NO_AUTODICT", "1", 1);
 
   /* initialize cmplog_mode */