about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/afl-common.c5
-rw-r--r--src/afl-forkserver.c42
-rw-r--r--src/afl-fuzz-bitmap.c12
-rw-r--r--src/afl-fuzz-extras.c4
-rw-r--r--src/afl-fuzz-init.c19
-rw-r--r--src/afl-fuzz-one.c2
-rw-r--r--src/afl-fuzz-queue.c151
-rw-r--r--src/afl-fuzz-run.c60
-rw-r--r--src/afl-fuzz-state.c14
-rw-r--r--src/afl-fuzz-stats.c90
-rw-r--r--src/afl-fuzz.c406
-rw-r--r--src/afl-performance.c2
-rw-r--r--src/hashmap.c2
13 files changed, 668 insertions, 141 deletions
diff --git a/src/afl-common.c b/src/afl-common.c
index efdb5d60..892745a7 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -108,7 +108,8 @@ void set_sanitizer_defaults() {
     if (!have_san_options) { strcpy(buf, default_options); }
     if (have_asan_options) {
 
-      if (NULL != strstr(have_asan_options, "detect_leaks=0")) {
+      if (NULL != strstr(have_asan_options, "detect_leaks=0") ||
+          NULL != strstr(have_asan_options, "detect_leaks=false")) {
 
         strcat(buf, "exitcode=" STRINGIFY(LSAN_ERROR) ":fast_unwind_on_malloc=0:print_suppressions=0:detect_leaks=0:malloc_context_size=0:");
 
@@ -979,6 +980,7 @@ inline u64 get_cur_time(void) {
   struct timeval  tv;
   struct timezone tz;
 
+  // TO NOT REPLACE WITH clock_gettime!!!
   gettimeofday(&tv, &tz);
 
   return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000);
@@ -992,6 +994,7 @@ inline u64 get_cur_time_us(void) {
   struct timeval  tv;
   struct timezone tz;
 
+  // TO NOT REPLACE WITH clock_gettime!!!
   gettimeofday(&tv, &tz);
 
   return (tv.tv_sec * 1000000ULL) + tv.tv_usec;
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 71d8570d..c7c493cf 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -241,6 +241,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
   fsrv->mem_limit = MEM_LIMIT;
   fsrv->out_file = NULL;
   fsrv->child_kill_signal = SIGKILL;
+  fsrv->max_length = MAX_FILE;
 
   /* exec related stuff */
   fsrv->child_pid = -1;
@@ -252,6 +253,10 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
   fsrv->uses_crash_exitcode = false;
   fsrv->uses_asan = false;
 
+#ifdef __AFL_CODE_COVERAGE
+  fsrv->persistent_trace_bits = NULL;
+#endif
+
   fsrv->init_child_func = fsrv_exec_child;
   list_append(&fsrv_list, fsrv);
 
@@ -278,12 +283,19 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
   fsrv_to->fsrv_kill_signal = from->fsrv_kill_signal;
   fsrv_to->debug = from->debug;
 
+#ifdef __AFL_CODE_COVERAGE
+  fsrv_to->persistent_trace_bits = from->persistent_trace_bits;
+#endif
+
   // These are forkserver specific.
   fsrv_to->out_dir_fd = -1;
   fsrv_to->child_pid = -1;
   fsrv_to->use_fauxsrv = 0;
   fsrv_to->last_run_timed_out = 0;
 
+  fsrv_to->late_send = from->late_send;
+  fsrv_to->custom_data_ptr = from->custom_data_ptr;
+
   fsrv_to->init_child_func = from->init_child_func;
   // Note: do not copy ->add_extra_func or ->persistent_record*
 
@@ -295,8 +307,8 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
   Returns the time passed to read.
   If the wait times out, returns timeout_ms + 1;
   Returns 0 if an error occurred (fd closed, signal, ...); */
-static u32 __attribute__((hot))
-read_s32_timed(s32 fd, s32 *buf, u32 timeout_ms, volatile u8 *stop_soon_p) {
+static u32 __attribute__((hot)) read_s32_timed(s32 fd, s32 *buf, u32 timeout_ms,
+                                               volatile u8 *stop_soon_p) {
 
   fd_set readfds;
   FD_ZERO(&readfds);
@@ -1326,6 +1338,10 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
           fsrv->map_size = tmp_map_size;
 
+        } else {
+
+          fsrv->real_map_size = fsrv->map_size = MAP_SIZE;
+
         }
 
         if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) {
@@ -1432,6 +1448,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
         }
 
+      } else {
+
+        // The binary is most likely instrumented using AFL's tool, and we will
+        // set map_size to MAP_SIZE.
+        fsrv->real_map_size = fsrv->map_size = MAP_SIZE;
+
       }
 
     }
@@ -1683,8 +1705,8 @@ u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv,
 
 /* Delete the current testcase and write the buf to the testcase file */
 
-void __attribute__((hot))
-afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
+void __attribute__((hot)) afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv,
+                                                     u8 *buf, size_t len) {
 
 #ifdef __linux__
   if (unlikely(fsrv->nyx_mode)) {
@@ -1802,9 +1824,8 @@ afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
 /* Execute target application, monitoring for timeouts. Return status
    information. The called program will update afl->fsrv->trace_bits. */
 
-fsrv_run_result_t __attribute__((hot))
-afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
-                    volatile u8 *stop_soon_p) {
+fsrv_run_result_t __attribute__((hot)) afl_fsrv_run_target(
+    afl_forkserver_t *fsrv, u32 timeout, volatile u8 *stop_soon_p) {
 
   s32 res;
   u32 exec_ms;
@@ -1944,6 +1965,13 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
 
   }
 
+  if (unlikely(fsrv->late_send)) {
+
+    fsrv->late_send(fsrv->custom_data_ptr, fsrv->custom_input,
+                    fsrv->custom_input_len);
+
+  }
+
   exec_ms = read_s32_timed(fsrv->fsrv_st_fd, &fsrv->child_status, timeout,
                            stop_soon_p);
 
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index 03bc5d6c..fd75a822 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -75,9 +75,13 @@ u32 count_bits(afl_state_t *afl, u8 *mem) {
 
     }
 
+#if __has_builtin(__builtin_popcount)
+    ret += __builtin_popcount(v);
+#else
     v -= ((v >> 1) & 0x55555555);
     v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
     ret += (((v + (v >> 4)) & 0xF0F0F0F) * 0x01010101) >> 24;
+#endif
 
   }
 
@@ -452,14 +456,14 @@ void write_crash_readme(afl_state_t *afl) {
    save or queue the input test case for further analysis if so. Returns 1 if
    entry is saved, 0 otherwise. */
 
-u8 __attribute__((hot))
-save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
+u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
+                                            u32 len, u8 fault) {
 
   if (unlikely(len == 0)) { return 0; }
 
   if (unlikely(fault == FSRV_RUN_TMOUT && afl->afl_env.afl_ignore_timeouts)) {
 
-    if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) {
+    if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
 
       classify_counts(&afl->fsrv);
       u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
@@ -485,7 +489,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
 
   /* Generating a hash on every input is super expensive. Bad idea and should
      only be used for special schedules */
-  if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) {
+  if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
 
     classify_counts(&afl->fsrv);
     classified = 1;
diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c
index 55b6be04..da996602 100644
--- a/src/afl-fuzz-extras.c
+++ b/src/afl-fuzz-extras.c
@@ -455,13 +455,13 @@ void deunicode_extras(afl_state_t *afl) {
 
         case 2:
           if (!afl->extras[i].data[j]) { ++z3; }
-          // fall through
+          __attribute__((fallthrough));
         case 0:
           if (!afl->extras[i].data[j]) { ++z1; }
           break;
         case 3:
           if (!afl->extras[i].data[j]) { ++z4; }
-          // fall through
+          __attribute__((fallthrough));
         case 1:
           if (!afl->extras[i].data[j]) { ++z2; }
           break;
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 7310e49f..10951300 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -1019,7 +1019,7 @@ void perform_dry_run(afl_state_t *afl) {
 
           }
 
-          if (!q->was_fuzzed) {
+          if (unlikely(!q->was_fuzzed)) {
 
             q->was_fuzzed = 1;
             afl->reinit_table = 1;
@@ -2443,20 +2443,19 @@ void check_crash_handling(void) {
 
     SAYF(
         "\n" cLRD "[-] " cRST
-        "Hmm, your system is configured to send core dump notifications to an\n"
+        "Your system is configured to send core dump notifications to an\n"
         "    external utility. This will cause issues: there will be an "
         "extended delay\n"
         "    between stumbling upon a crash and having this information "
         "relayed to the\n"
         "    fuzzer via the standard waitpid() API.\n"
-        "    If you're just testing, set "
+        "    If you're just experimenting, set "
         "'AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1'.\n\n"
 
-        "    To avoid having crashes misinterpreted as timeouts, please log in "
-        "as root\n"
-        "    and temporarily modify /proc/sys/kernel/core_pattern, like so:\n\n"
+        "    To avoid having crashes misinterpreted as timeouts, please \n"
+        "    temporarily modify /proc/sys/kernel/core_pattern, like so:\n\n"
 
-        "    echo core >/proc/sys/kernel/core_pattern\n");
+        "    echo core | sudo tee /proc/sys/kernel/core_pattern\n");
 
     if (!getenv("AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES")) {
 
@@ -2717,7 +2716,11 @@ void fix_up_sync(afl_state_t *afl) {
 
   }
 
-  if (strlen(afl->sync_id) > 32) { FATAL("Fuzzer ID too long"); }
+  if (strlen(afl->sync_id) > 50) {
+
+    FATAL("sync_id max length is 50 characters");
+
+  }
 
   x = alloc_printf("%s/%s", afl->out_dir, afl->sync_id);
 
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index 74bb8cbc..fd5ed87c 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -3914,7 +3914,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
 #define EFF_APOS(_p) ((_p) >> EFF_MAP_SCALE2)
 #define EFF_REM(_x) ((_x) & ((1 << EFF_MAP_SCALE2) - 1))
 #define EFF_ALEN(_l) (EFF_APOS(_l) + !!EFF_REM(_l))
-#define EFF_SPAN_ALEN(_p, _l) (EFF_APOS((_p) + (_l)-1) - EFF_APOS(_p) + 1)
+#define EFF_SPAN_ALEN(_p, _l) (EFF_APOS((_p) + (_l) - 1) - EFF_APOS(_p) + 1)
 
   /* Initialize effector map for the next step (see comments below). Always
          flag first and last byte as doing something. */
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index 313e8ae5..8db89775 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -123,7 +123,7 @@ void create_alias_table(afl_state_t *afl) {
         double weight = 1.0;
         {  // inline does result in a compile error with LTO, weird
 
-          if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) {
+          if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
 
             u32 hits = afl->n_fuzz[q->n_fuzz_entry];
             if (likely(hits)) { weight /= (log10(hits) + 1); }
@@ -133,39 +133,127 @@ void create_alias_table(afl_state_t *afl) {
           if (likely(afl->schedule < RARE)) {
 
             double t = q->exec_us / avg_exec_us;
+
             if (likely(t < 0.1)) {
 
               // nothing
 
-            } else if (likely(t <= 0.25))
+            } else if (likely(t <= 0.25)) {
+
+              weight *= 0.95;
 
-              weight *= 0.9;
-            else if (likely(t <= 0.5)) {
+            } else if (likely(t <= 0.5)) {
 
               // nothing
 
-            } else if (likely(t < 1.0))
+            } else if (likely(t <= 0.75)) {
+
+              weight *= 1.05;
+
+            } else if (likely(t <= 1.0)) {
+
+              weight *= 1.1;
+
+            } else if (likely(t < 1.25)) {
+
+              weight *= 0.2;  // WTF ??? makes no sense
+
+            } else if (likely(t <= 1.5)) {
+
+              // nothing
+
+            } else if (likely(t <= 2.0)) {
+
+              weight *= 1.1;
+
+            } else if (likely(t <= 2.5)) {
+
+            } else if (likely(t <= 5.0)) {
 
               weight *= 1.15;
-            else if (unlikely(t > 2.5 && t < 5.0))
+
+            } else if (likely(t <= 20.0)) {
+
               weight *= 1.1;
-            // else nothing
+              // else nothing
+
+            }
 
           }
 
           double l = q->len / avg_len;
-          if (likely(l < 0.1))
-            weight *= 0.75;
-          else if (likely(l < 0.25))
-            weight *= 1.1;
-          else if (unlikely(l >= 10))
-            weight *= 1.1;
+          if (likely(l < 0.1)) {
+
+            weight *= 0.5;
+
+          } else if (likely(l <= 0.5)) {
+
+            // nothing
+
+          } else if (likely(l <= 1.25)) {
+
+            weight *= 1.05;
+
+          } else if (likely(l <= 1.75)) {
+
+            // nothing
+
+          } else if (likely(l <= 2.0)) {
+
+            weight *= 0.95;
+
+          } else if (likely(l <= 5.0)) {
+
+            // nothing
+
+          } else if (likely(l <= 10.0)) {
+
+            weight *= 1.05;
+
+          } else {
+
+            weight *= 1.15;
+
+          }
 
           double bms = q->bitmap_size / avg_bitmap_size;
-          if (likely(bms < 0.5))
-            weight *= (1.0 + ((bms - 0.5) / 2));
-          else if (unlikely(bms > 1.33))
-            weight *= 1.1;
+          if (likely(bms < 0.1)) {
+
+            weight *= 0.01;
+
+          } else if (likely(bms <= 0.25)) {
+
+            weight *= 0.55;
+
+          } else if (likely(bms <= 0.5)) {
+
+            // nothing
+
+          } else if (likely(bms <= 0.75)) {
+
+            weight *= 1.2;
+
+          } else if (likely(bms <= 1.25)) {
+
+            weight *= 1.3;
+
+          } else if (likely(bms <= 1.75)) {
+
+            weight *= 1.25;
+
+          } else if (likely(bms <= 2.0)) {
+
+            // nothing
+
+          } else if (likely(bms <= 2.5)) {
+
+            weight *= 1.3;
+
+          } else {
+
+            weight *= 0.75;
+
+          }
 
           if (unlikely(!q->was_fuzzed)) { weight *= 2.5; }
           if (unlikely(q->fs_redundant)) { weight *= 0.75; }
@@ -387,6 +475,17 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) {
 
   q->fs_redundant = state;
 
+  if (likely(q->fs_redundant)) {
+
+    if (unlikely(q->trace_mini)) {
+
+      ck_free(q->trace_mini);
+      q->trace_mini = NULL;
+
+    }
+
+  }
+
   sprintf(fn, "%s/queue/.state/redundant_edges/%s", afl->out_dir,
           strrchr((char *)q->fname, '/') + 1);
 
@@ -400,7 +499,9 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) {
 
   } else {
 
-    if (unlink(fn)) { PFATAL("Unable to remove '%s'", fn); }
+    if (unlink(fn)) {                 /*PFATAL("Unable to remove '%s'", fn);*/
+
+    }
 
   }
 
@@ -698,12 +799,11 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
 
 void destroy_queue(afl_state_t *afl) {
 
-  u32 i;
+  u32                 i;
+  struct queue_entry *q;
 
   for (i = 0; i < afl->queued_items; i++) {
 
-    struct queue_entry *q;
-
     q = afl->queue_buf[i];
     ck_free(q->fname);
     ck_free(q->trace_mini);
@@ -739,7 +839,7 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
   u64 fav_factor;
   u64 fuzz_p2;
 
-  if (likely(afl->schedule >= FAST && afl->schedule < RARE)) {
+  if (unlikely(afl->schedule >= FAST && afl->schedule < RARE)) {
 
     fuzz_p2 = 0;  // Skip the fuzz_p2 comparison
 
@@ -775,7 +875,7 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
         u64 top_rated_fav_factor;
         u64 top_rated_fuzz_p2;
 
-        if (likely(afl->schedule >= FAST && afl->schedule < RARE)) {
+        if (unlikely(afl->schedule >= FAST && afl->schedule < RARE)) {
 
           top_rated_fuzz_p2 = 0;  // Skip the fuzz_p2 comparison
 
@@ -811,7 +911,7 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
         if (!--afl->top_rated[i]->tc_ref) {
 
           ck_free(afl->top_rated[i]->trace_mini);
-          afl->top_rated[i]->trace_mini = 0;
+          afl->top_rated[i]->trace_mini = NULL;
 
         }
 
@@ -872,7 +972,8 @@ void cull_queue(afl_state_t *afl) {
 
   for (i = 0; i < afl->fsrv.map_size; ++i) {
 
-    if (afl->top_rated[i] && (temp_v[i >> 3] & (1 << (i & 7)))) {
+    if (afl->top_rated[i] && (temp_v[i >> 3] & (1 << (i & 7))) &&
+        afl->top_rated[i]->trace_mini) {
 
       u32 j = len;
 
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 6a0da6ab..4ce17eb2 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -41,8 +41,9 @@ u64 time_spent_working = 0;
 /* Execute target application, monitoring for timeouts. Return status
    information. The called program will update afl->fsrv->trace_bits. */
 
-fsrv_run_result_t __attribute__((hot))
-fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) {
+fsrv_run_result_t __attribute__((hot)) fuzz_run_target(afl_state_t      *afl,
+                                                       afl_forkserver_t *fsrv,
+                                                       u32 timeout) {
 
 #ifdef PROFILING
   static u64      time_spent_start = 0;
@@ -60,6 +61,27 @@ fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) {
 
   fsrv_run_result_t res = afl_fsrv_run_target(fsrv, timeout, &afl->stop_soon);
 
+#ifdef __AFL_CODE_COVERAGE
+  if (unlikely(!fsrv->persistent_trace_bits)) {
+
+    // On the first run, we allocate the persistent map to collect coverage.
+    fsrv->persistent_trace_bits = (u8 *)malloc(fsrv->map_size);
+    memset(fsrv->persistent_trace_bits, 0, fsrv->map_size);
+
+  }
+
+  for (u32 i = 0; i < fsrv->map_size; ++i) {
+
+    if (fsrv->persistent_trace_bits[i] != 255 && fsrv->trace_bits[i]) {
+
+      fsrv->persistent_trace_bits[i]++;
+
+    }
+
+  }
+
+#endif
+
   /* If post_run() function is defined in custom mutator, the function will be
      called each time after AFL++ executes the target program. */
 
@@ -90,8 +112,8 @@ fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) {
    old file is unlinked and a new one is created. Otherwise, afl->fsrv.out_fd is
    rewound and truncated. */
 
-u32 __attribute__((hot))
-write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
+u32 __attribute__((hot)) write_to_testcase(afl_state_t *afl, void **mem,
+                                           u32 len, u32 fix) {
 
   u8 sent = 0;
 
@@ -173,7 +195,17 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
 
       if (el->afl_custom_fuzz_send) {
 
-        el->afl_custom_fuzz_send(el->data, *mem, new_size);
+        if (!afl->afl_env.afl_custom_mutator_late_send) {
+
+          el->afl_custom_fuzz_send(el->data, *mem, new_size);
+
+        } else {
+
+          afl->fsrv.custom_input = *mem;
+          afl->fsrv.custom_input_len = new_size;
+
+        }
+
         sent = 1;
 
       }
@@ -185,17 +217,17 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
       /* everything as planned. use the potentially new data. */
       afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size);
 
-      if (likely(!afl->afl_env.afl_post_process_keep_original)) {
+    }
 
-        len = new_size;
+    if (likely(!afl->afl_env.afl_post_process_keep_original)) {
 
-      } else {
+      len = new_size;
 
-        /* restore the original memory which was saved in new_mem */
-        *mem = new_mem;
-        afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+    } else {
 
-      }
+      /* restore the original memory which was saved in new_mem */
+      *mem = new_mem;
+      afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
 
     }
 
@@ -1142,8 +1174,8 @@ abort_trimming:
    error conditions, returning 1 if it's time to bail out. This is
    a helper function for fuzz_one(). */
 
-u8 __attribute__((hot))
-common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
+u8 __attribute__((hot)) common_fuzz_stuff(afl_state_t *afl, u8 *out_buf,
+                                          u32 len) {
 
   u8 fault;
 
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index fbe6d32a..eead3e50 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -286,6 +286,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
             afl->afl_env.afl_no_sync =
                 get_afl_env(afl_environment_variables[i]) ? 1 : 0;
 
+          } else if (!strncmp(env, "AFL_NO_FASTRESUME",
+
+                              afl_environment_variable_len)) {
+
+            afl->afl_env.afl_no_fastresume =
+                get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
           } else if (!strncmp(env, "AFL_CUSTOM_MUTATOR_ONLY",
 
                               afl_environment_variable_len)) {
@@ -293,6 +300,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
             afl->afl_env.afl_custom_mutator_only =
                 get_afl_env(afl_environment_variables[i]) ? 1 : 0;
 
+          } else if (!strncmp(env, "AFL_CUSTOM_MUTATOR_LATE_SEND",
+
+                              afl_environment_variable_len)) {
+
+            afl->afl_env.afl_custom_mutator_late_send =
+                get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
           } else if (!strncmp(env, "AFL_CMPLOG_ONLY_NEW",
 
                               afl_environment_variable_len)) {
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 3a71e158..9f5f59c0 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -76,7 +76,13 @@ char *get_fuzzing_state(afl_state_t *afl) {
 
 void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
 
-  u8 fn[PATH_MAX];
+  u8 fn[PATH_MAX], fn2[PATH_MAX];
+
+  snprintf(fn2, PATH_MAX, "%s/target_hash", afl->out_dir);
+  FILE *f2 = create_ffile(fn2);
+  fprintf(f2, "%p\n", (void *)get_binary_hash(afl->fsrv.target_path));
+  fclose(f2);
+
   snprintf(fn, PATH_MAX, "%s/fuzzer_setup", afl->out_dir);
   FILE *f = create_ffile(fn);
   u32   i;
@@ -957,9 +963,9 @@ void show_stats_normal(afl_state_t *afl) {
 
   /* Lord, forgive me this. */
 
-  SAYF(SET_G1 bSTG bLT bH bSTOP                         cCYA
+  SAYF(SET_G1 bSTG bLT bH                         bSTOP cCYA
        " process timing " bSTG bH30 bH5 bH bHB bH bSTOP cCYA
-       " overall results " bSTG bH2 bH2                 bRT "\n");
+       " overall results " bSTG bH2               bH2 bRT "\n");
 
   if (afl->non_instrumented_mode) {
 
@@ -1001,7 +1007,7 @@ void show_stats_normal(afl_state_t *afl) {
 
   u_stringify_time_diff(time_tmp, afl->prev_run_time + cur_ms, afl->start_time);
   SAYF(bV bSTOP "        run time : " cRST "%-33s " bSTG bV bSTOP
-                "  cycles done : %s%-5s " bSTG              bV "\n",
+                "  cycles done : %s%-5s " bSTG bV "\n",
        time_tmp, tmp, u_stringify_int(IB(0), afl->queue_cycle - 1));
 
   /* We want to warn people about not seeing new paths after a full cycle,
@@ -1041,7 +1047,7 @@ void show_stats_normal(afl_state_t *afl) {
 
   u_stringify_time_diff(time_tmp, cur_ms, afl->last_crash_time);
   SAYF(bV bSTOP "last saved crash : " cRST "%-33s " bSTG bV bSTOP
-                "saved crashes : %s%-6s" bSTG               bV "\n",
+                "saved crashes : %s%-6s" bSTG bV "\n",
        time_tmp, crash_color, tmp);
 
   sprintf(tmp, "%s%s", u_stringify_int(IB(0), afl->saved_hangs),
@@ -1049,12 +1055,12 @@ void show_stats_normal(afl_state_t *afl) {
 
   u_stringify_time_diff(time_tmp, cur_ms, afl->last_hang_time);
   SAYF(bV bSTOP " last saved hang : " cRST "%-33s " bSTG bV bSTOP
-                "  saved hangs : " cRST "%-6s" bSTG         bV "\n",
+                "  saved hangs : " cRST "%-6s" bSTG bV "\n",
        time_tmp, tmp);
 
-  SAYF(bVR bH bSTOP                                              cCYA
+  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");
+       " 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
@@ -1085,9 +1091,9 @@ void show_stats_normal(afl_state_t *afl) {
 
   SAYF(bSTOP " count coverage : " cRST "%-19s" bSTG bV "\n", tmp);
 
-  SAYF(bVR bH bSTOP                                             cCYA
+  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");
+       " 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_items);
@@ -1095,7 +1101,7 @@ void show_stats_normal(afl_state_t *afl) {
   /* Yeah... it's still going on... halp? */
 
   SAYF(bV bSTOP "  now trying : " cRST "%-22s " bSTG bV bSTOP
-                " favored items : " cRST "%-20s" bSTG   bV "\n",
+                " favored items : " cRST "%-20s" bSTG bV "\n",
        afl->stage_name, tmp);
 
   if (!afl->stage_max) {
@@ -1124,13 +1130,13 @@ void show_stats_normal(afl_state_t *afl) {
   if (afl->crash_mode) {
 
     SAYF(bV bSTOP " total execs : " cRST "%-22s " bSTG bV bSTOP
-                  "   new crashes : %s%-20s" bSTG         bV "\n",
+                  "   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 "%-22s " bSTG bV bSTOP
-                  " total crashes : %s%-20s" bSTG         bV "\n",
+                  " total crashes : %s%-20s" bSTG bV "\n",
          u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp);
 
   }
@@ -1183,7 +1189,7 @@ void show_stats_normal(afl_state_t *afl) {
   }
 
   SAYF(bV bSTOP "   bit flips : " cRST "%-36s " bSTG bV bSTOP
-                "    levels : " cRST "%-10s" bSTG       bV "\n",
+                "    levels : " cRST "%-10s" bSTG bV "\n",
        tmp, u_stringify_int(IB(0), afl->max_depth));
 
   if (unlikely(!afl->skip_deterministic)) {
@@ -1199,7 +1205,7 @@ void show_stats_normal(afl_state_t *afl) {
   }
 
   SAYF(bV bSTOP "  byte flips : " cRST "%-36s " bSTG bV bSTOP
-                "   pending : " cRST "%-10s" bSTG       bV "\n",
+                "   pending : " cRST "%-10s" bSTG bV "\n",
        tmp, u_stringify_int(IB(0), afl->pending_not_fuzzed));
 
   if (unlikely(!afl->skip_deterministic)) {
@@ -1215,7 +1221,7 @@ void show_stats_normal(afl_state_t *afl) {
   }
 
   SAYF(bV bSTOP " arithmetics : " cRST "%-36s " bSTG bV bSTOP
-                "  pend fav : " cRST "%-10s" bSTG       bV "\n",
+                "  pend fav : " cRST "%-10s" bSTG bV "\n",
        tmp, u_stringify_int(IB(0), afl->pending_favored));
 
   if (unlikely(!afl->skip_deterministic)) {
@@ -1231,7 +1237,7 @@ void show_stats_normal(afl_state_t *afl) {
   }
 
   SAYF(bV bSTOP "  known ints : " cRST "%-36s " bSTG bV bSTOP
-                " own finds : " cRST "%-10s" bSTG       bV "\n",
+                " own finds : " cRST "%-10s" bSTG bV "\n",
        tmp, u_stringify_int(IB(0), afl->queued_discovered));
 
   if (unlikely(!afl->skip_deterministic)) {
@@ -1257,7 +1263,7 @@ void show_stats_normal(afl_state_t *afl) {
   }
 
   SAYF(bV bSTOP "  dictionary : " cRST "%-36s " bSTG bV bSTOP
-                "  imported : " cRST "%-10s" bSTG       bV "\n",
+                "  imported : " cRST "%-10s" bSTG bV "\n",
        tmp,
        afl->sync_id ? u_stringify_int(IB(0), afl->queued_imported)
                     : (u8 *)"n/a");
@@ -1445,8 +1451,8 @@ void show_stats_normal(afl_state_t *afl) {
 
   /* Last line */
 
-  SAYF(SET_G1 "\n" bSTG bLB bH cCYA          bSTOP " strategy:" cPIN
-              " %s " bSTG bH10 cCYA          bSTOP " state:" cPIN
+  SAYF(SET_G1 "\n" bSTG bLB bH               cCYA bSTOP " strategy:" cPIN
+              " %s " bSTG bH10               cCYA bSTOP " state:" cPIN
               " %s " bSTG bH2 bRB bSTOP cRST RESET_G1,
        afl->fuzz_mode == 0 ? "explore" : "exploit", get_fuzzing_state(afl));
 
@@ -1815,8 +1821,8 @@ void show_stats_pizza(afl_state_t *afl) {
   }
 
   u_stringify_time_diff(time_tmp, afl->prev_run_time + cur_ms, afl->start_time);
-  SAYF(bV                                                               bSTOP
-       "                         open time : " cRST "%-37s " bSTG bV    bSTOP
+  SAYF(bV bSTOP
+       "                         open time : " cRST "%-37s " bSTG bV bSTOP
        "                     seasons done : %s%-5s               " bSTG bV "\n",
        time_tmp, tmp, u_stringify_int(IB(0), afl->queue_cycle - 1));
 
@@ -1859,7 +1865,7 @@ void show_stats_pizza(afl_state_t *afl) {
           (afl->saved_crashes >= KEEP_UNIQUE_CRASH) ? "+" : "");
 
   u_stringify_time_diff(time_tmp, cur_ms, afl->last_crash_time);
-  SAYF(bV                                                                bSTOP
+  SAYF(bV bSTOP
        "                last ordered pizza : " cRST "%-33s     " bSTG bV bSTOP
        "                         at table : %s%-6s              " bSTG bV "\n",
        time_tmp, crash_color, tmp);
@@ -1868,15 +1874,15 @@ void show_stats_pizza(afl_state_t *afl) {
           (afl->saved_hangs >= KEEP_UNIQUE_HANG) ? "+" : "");
 
   u_stringify_time_diff(time_tmp, cur_ms, afl->last_hang_time);
-  SAYF(bV                                                                bSTOP
+  SAYF(bV bSTOP
        "  last conversation with customers : " cRST "%-33s     " bSTG bV bSTOP
        "                 number of Peroni : " cRST "%-6s              " bSTG bV
        "\n",
        time_tmp, tmp);
 
-  SAYF(bVR bH bSTOP                                           cCYA
+  SAYF(bVR bH                                           bSTOP cCYA
        " Baking progress  " bSTG bH30 bH20 bH5 bH bX bH bSTOP cCYA
-       " Pizzeria busyness" bSTG bH30 bH5 bH bH               bVL "\n");
+       " Pizzeria busyness" bSTG bH30 bH5 bH            bH 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
@@ -1912,8 +1918,8 @@ void show_stats_pizza(afl_state_t *afl) {
   SAYF(bSTOP "                   count coverage : " cRST "%-19s " bSTG bV "\n",
        tmp);
 
-  SAYF(bVR bH bSTOP                                              cCYA
-       " Pizzas almost ready " bSTG bH30 bH20 bH2 bH bX bH bSTOP cCYA
+  SAYF(bVR bH                                                 bSTOP cCYA
+       " Pizzas almost ready " bSTG bH30 bH20 bH2 bH bX bH    bSTOP cCYA
        " Types of pizzas cooking " bSTG bH10 bH5 bH2 bH10 bH2 bH bVL "\n");
 
   sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->queued_favored),
@@ -1922,7 +1928,7 @@ void show_stats_pizza(afl_state_t *afl) {
   /* Yeah... it's still going on... halp? */
 
   SAYF(bV bSTOP "                     now preparing : " cRST
-                "%-22s                " bSTG bV                          bSTOP
+                "%-22s                " bSTG bV bSTOP
                 "                favourite topping : " cRST "%-20s" bSTG bV
                 "\n",
        afl->stage_name, tmp);
@@ -1955,14 +1961,14 @@ void show_stats_pizza(afl_state_t *afl) {
   if (afl->crash_mode) {
 
     SAYF(bV bSTOP "                      total pizzas : " cRST
-                  "%-22s                " bSTG bV              bSTOP
+                  "%-22s                " bSTG bV bSTOP
                   "      pizzas with pineapple : %s%-20s" bSTG bV "\n",
          u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp);
 
   } else {
 
     SAYF(bV bSTOP "                      total pizzas : " cRST
-                  "%-22s                " bSTG bV                    bSTOP
+                  "%-22s                " bSTG bV bSTOP
                   "      total pizzas with pineapple : %s%-20s" bSTG bV "\n",
          u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp);
 
@@ -1999,7 +2005,7 @@ void show_stats_pizza(afl_state_t *afl) {
   /* Aaaalmost there... hold on! */
 
   SAYF(bVR bH cCYA bSTOP " Promotional campaign on TikTok yields " bSTG bH30 bH2
-           bH bH2 bX bH bSTOP                                       cCYA
+           bH bH2 bX bH                                          bSTOP cCYA
                          " Customer type " bSTG bH5 bH2 bH30 bH2 bH bVL "\n");
 
   if (unlikely(afl->custom_only)) {
@@ -2022,8 +2028,8 @@ void show_stats_pizza(afl_state_t *afl) {
 
   }
 
-  SAYF(bV                                                                 bSTOP
-       "                pizzas for celiac  : " cRST "%-36s  " bSTG bV     bSTOP
+  SAYF(bV bSTOP
+       "                pizzas for celiac  : " cRST "%-36s  " bSTG bV bSTOP
        "                           levels : " cRST "%-10s          " bSTG bV
        "\n",
        tmp, u_stringify_int(IB(0), afl->max_depth));
@@ -2040,8 +2046,8 @@ void show_stats_pizza(afl_state_t *afl) {
 
   }
 
-  SAYF(bV                                                                 bSTOP
-       "                   pizzas for kids : " cRST "%-36s  " bSTG bV     bSTOP
+  SAYF(bV bSTOP
+       "                   pizzas for kids : " cRST "%-36s  " bSTG bV bSTOP
        "                   pizzas to make : " cRST "%-10s          " bSTG bV
        "\n",
        tmp, u_stringify_int(IB(0), afl->pending_not_fuzzed));
@@ -2058,8 +2064,8 @@ void show_stats_pizza(afl_state_t *afl) {
 
   }
 
-  SAYF(bV                                                                 bSTOP
-       "                      pizza bianca : " cRST "%-36s  " bSTG bV     bSTOP
+  SAYF(bV bSTOP
+       "                      pizza bianca : " cRST "%-36s  " bSTG bV bSTOP
        "                       nice table : " cRST "%-10s          " bSTG bV
        "\n",
        tmp, u_stringify_int(IB(0), afl->pending_favored));
@@ -2076,8 +2082,8 @@ void show_stats_pizza(afl_state_t *afl) {
 
   }
 
-  SAYF(bV                                                                 bSTOP
-       "               recurring customers : " cRST "%-36s  " bSTG bV     bSTOP
+  SAYF(bV bSTOP
+       "               recurring customers : " cRST "%-36s  " bSTG bV bSTOP
        "                    new customers : " cRST "%-10s          " bSTG bV
        "\n",
        tmp, u_stringify_int(IB(0), afl->queued_discovered));
@@ -2104,8 +2110,8 @@ void show_stats_pizza(afl_state_t *afl) {
 
   }
 
-  SAYF(bV                                                                 bSTOP
-       "                        dictionary : " cRST "%-36s  " bSTG bV     bSTOP
+  SAYF(bV bSTOP
+       "                        dictionary : " cRST "%-36s  " bSTG bV bSTOP
        "       patrons from old resturant : " cRST "%-10s          " bSTG bV
        "\n",
        tmp,
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index a7ddef6e..726a2260 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -36,6 +36,67 @@
   #include <sys/ipc.h>
   #include <sys/shm.h>
 #endif
+#ifdef HAVE_ZLIB
+
+  #define ck_gzread(fd, buf, len, fn)                            \
+    do {                                                         \
+                                                                 \
+      s32 _len = (s32)(len);                                     \
+      s32 _res = gzread(fd, buf, _len);                          \
+      if (_res != _len) RPFATAL(_res, "Short read from %s", fn); \
+                                                                 \
+    } while (0)
+
+  #define ck_gzwrite(fd, buf, len, fn)                                    \
+    do {                                                                  \
+                                                                          \
+      if (len <= 0) break;                                                \
+      s32 _written = 0, _off = 0, _len = (s32)(len);                      \
+                                                                          \
+      do {                                                                \
+                                                                          \
+        s32 _res = gzwrite(fd, (buf) + _off, _len);                       \
+        if (_res != _len && (_res > 0 && _written + _res != _len)) {      \
+                                                                          \
+          if (_res > 0) {                                                 \
+                                                                          \
+            _written += _res;                                             \
+            _len -= _res;                                                 \
+            _off += _res;                                                 \
+                                                                          \
+          } else {                                                        \
+                                                                          \
+            RPFATAL(_res, "Short write to %s (%d of %d bytes)", fn, _res, \
+                    _len);                                                \
+                                                                          \
+          }                                                               \
+                                                                          \
+        } else {                                                          \
+                                                                          \
+          break;                                                          \
+                                                                          \
+        }                                                                 \
+                                                                          \
+      } while (1);                                                        \
+                                                                          \
+                                                                          \
+                                                                          \
+    } while (0)
+
+  #include <zlib.h>
+  #define ZLIBOPEN gzopen
+  #define ZLIBREAD ck_gzread
+  #define NZLIBREAD gzread
+  #define ZLIBWRITE ck_gzwrite
+  #define ZLIBCLOSE gzclose
+  #define ZLIB_EXTRA "9"
+#else
+  #define ZLIBOPEN open
+  #define NZLIBREAD read
+  #define ZLIBREAD ck_read
+  #define ZLIBWRITE ck_write
+  #define ZLIBCLOSE close
+#endif
 
 #ifdef __APPLE__
   #include <sys/qos.h>
@@ -181,7 +242,7 @@ static void usage(u8 *argv0, int more_help) {
       "it.\n"
       "                  if using QEMU/FRIDA or the fuzzing target is "
       "compiled\n"
-      "                  for CmpLog then use '-c 0'. To disable Cmplog use '-c "
+      "                  for CmpLog then use '-c 0'. To disable CMPLOG use '-c "
       "-'.\n"
       "  -l cmplog_opts - CmpLog configuration values (e.g. \"2ATR\"):\n"
       "                  1=small files, 2=larger files (default), 3=all "
@@ -335,6 +396,7 @@ static void usage(u8 *argv0, int more_help) {
       "AFL_STATSD_PORT: change default statsd port (default: 8125)\n"
       "AFL_STATSD_TAGS_FLAVOR: set statsd tags format (default: disable tags)\n"
       "                        suported formats: dogstatsd, librato, signalfx, influxdb\n"
+      "AFL_NO_FASTRESUME: do not read or write a fast resume file\n"
       "AFL_NO_SYNC: disables all syncing\n"
       "AFL_SYNC_TIME: sync time between fuzzing instances (in minutes)\n"
       "AFL_FINAL_SYNC: sync a final time when exiting (will delay the exit!)\n"
@@ -960,7 +1022,11 @@ int main(int argc, char **argv_orig, char **envp) {
 
         }
 
-        if (afl->fsrv.mem_limit < 5) { FATAL("Dangerously low value of -m"); }
+        if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 5) {
+
+          FATAL("Dangerously low value of -m");
+
+        }
 
         if (sizeof(rlim_t) == 4 && afl->fsrv.mem_limit > 2000) {
 
@@ -1544,17 +1610,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   #endif
 
-  if (afl->sync_id) {
-
-    if (strlen(afl->sync_id) > 50) {
-
-      FATAL("sync_id max length is 50 characters");
-
-    }
-
-    fix_up_sync(afl);
-
-  }
+  if (afl->sync_id) { fix_up_sync(afl); }
 
   if (!strcmp(afl->in_dir, afl->out_dir)) {
 
@@ -1868,6 +1924,15 @@ int main(int argc, char **argv_orig, char **envp) {
 
           OKF("Using Frida Address Sanitizer Mode");
 
+          if (afl->fsrv.mem_limit) {
+
+            WARNF(
+                "in the Frida Address Sanitizer Mode we disable all memory "
+                "limits");
+            afl->fsrv.mem_limit = 0;
+
+          }
+
           fasan_check_afl_preload(afl_preload);
 
           setenv("ASAN_OPTIONS", "detect_leaks=false", 1);
@@ -2067,6 +2132,31 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  if (afl->custom_mutators_count && afl->afl_env.afl_custom_mutator_late_send) {
+
+    u32 count_send = 0;
+    LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+      if (el->afl_custom_fuzz_send) {
+
+        if (count_send) {
+
+          FATAL(
+              "You can only have one custom send() function if you are using "
+              "AFL_CUSTOM_MUTATOR_LATE_SEND!");
+
+        }
+
+        afl->fsrv.late_send = el->afl_custom_fuzz_send;
+        afl->fsrv.custom_data_ptr = el->data;
+        count_send = 1;
+
+      }
+
+    });
+
+  }
+
   if (afl->limit_time_sig > 0 && afl->custom_mutators_count) {
 
     if (afl->custom_only) {
@@ -2101,13 +2191,92 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  setup_cmdline_file(afl, argv + optind);
+  check_binary(afl, argv[optind]);
+
+  u64 prev_target_hash = 0;
+  s32 fast_resume = 0;
+  #ifdef HAVE_ZLIB
+  gzFile fr_fd = NULL;
+  #else
+  s32 fr_fd = -1;
+  #endif
+
+  if (afl->in_place_resume && !afl->afl_env.afl_no_fastresume) {
+
+    u8 fn[PATH_MAX], buf[32];
+    snprintf(fn, PATH_MAX, "%s/target_hash", afl->out_dir);
+    s32 fd = open(fn, O_RDONLY);
+    if (fd >= 0) {
+
+      if (read(fd, buf, 32) >= 16) {
+
+        sscanf(buf, "%p", (void **)&prev_target_hash);
+
+      }
+
+      close(fd);
+
+    }
+
+  }
+
   write_setup_file(afl, argc, argv);
 
-  setup_cmdline_file(afl, argv + optind);
+  if (afl->in_place_resume && !afl->afl_env.afl_no_fastresume) {
+
+    u64 target_hash = get_binary_hash(afl->fsrv.target_path);
+
+    if (!target_hash || prev_target_hash != target_hash) {
+
+      ACTF("Target binary is different, cannot perform FAST RESUME!");
+
+    } else {
+
+      u8 fn[PATH_MAX];
+      snprintf(fn, PATH_MAX, "%s/fastresume.bin", afl->out_dir);
+  #ifdef HAVE_ZLIB
+      if ((fr_fd = ZLIBOPEN(fn, "rb")) != NULL) {
+
+  #else
+      if ((fr_fd = open(fn, O_RDONLY)) >= 0) {
+
+  #endif
+
+        u8   ver_string[8];
+        u64 *ver = (u64 *)ver_string;
+        u64  expect_ver =
+            afl->shm.cmplog_mode + (sizeof(struct queue_entry) << 1);
+
+        if (NZLIBREAD(fr_fd, ver_string, sizeof(ver_string)) !=
+            sizeof(ver_string))
+          WARNF("Emtpy fastresume.bin, ignoring, cannot perform FAST RESUME");
+        else if (expect_ver != *ver)
+          WARNF(
+              "Different AFL++ version or feature usage, cannot perform FAST "
+              "RESUME");
+        else {
+
+          OKF("Will perform FAST RESUME");
+          fast_resume = 1;
+
+        }
+
+      } else {
+
+        ACTF("fastresume.bin not found, cannot perform FAST RESUME!");
+
+      }
+
+      // If the fast resume file is not valid we will be unable to start, so
+      // we remove the file but keep the file descriptor open.
+      unlink(fn);
+
+    }
+
+  }
 
   read_testcases(afl, NULL);
-  // read_foreign_testcases(afl, 1); for the moment dont do this
-  OKF("Loaded a total of %u seeds.", afl->queued_items);
 
   pivot_inputs(afl);
 
@@ -2140,6 +2309,9 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+  // read_foreign_testcases(afl, 1); for the moment dont do this
+  OKF("Loaded a total of %u seeds.", afl->queued_items);
+
   /* If we don't have a file name chosen yet, use a safe default. */
 
   if (!afl->fsrv.out_file) {
@@ -2196,8 +2368,6 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
-  check_binary(afl, argv[optind]);
-
   #ifdef AFL_PERSISTENT_RECORD
   if (unlikely(afl->fsrv.persistent_record)) {
 
@@ -2416,7 +2586,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
-    OKF("Cmplog forkserver successfully started");
+    OKF("CMPLOG forkserver successfully started");
 
   }
 
@@ -2454,29 +2624,102 @@ int main(int argc, char **argv_orig, char **envp) {
   dedup_extras(afl);
   if (afl->extras_cnt) { OKF("Loaded a total of %u extras.", afl->extras_cnt); }
 
-  // after we have the correct bitmap size we can read the bitmap -B option
-  // and set the virgin maps
-  if (afl->in_bitmap) {
+  if (unlikely(fast_resume)) {
 
-    read_bitmap(afl->in_bitmap, afl->virgin_bits, afl->fsrv.map_size);
+    u64 resume_start = get_cur_time_us();
+    // if we get here then we should abort on errors
+    ZLIBREAD(fr_fd, afl->virgin_bits, afl->fsrv.map_size, "virgin_bits");
+    ZLIBREAD(fr_fd, afl->virgin_tmout, afl->fsrv.map_size, "virgin_tmout");
+    ZLIBREAD(fr_fd, afl->virgin_crash, afl->fsrv.map_size, "virgin_crash");
+    ZLIBREAD(fr_fd, afl->var_bytes, afl->fsrv.map_size, "var_bytes");
 
-  } else {
+    u8                  res[1] = {0};
+    u8                 *o_start = (u8 *)&(afl->queue_buf[0]->colorized);
+    u8                 *o_end = (u8 *)&(afl->queue_buf[0]->mother);
+    u32                 r = 8 + afl->fsrv.map_size * 4;
+    u32                 q_len = o_end - o_start;
+    u32                 m_len = (afl->fsrv.map_size >> 3);
+    struct queue_entry *q;
 
-    memset(afl->virgin_bits, 255, map_size);
+    for (u32 i = 0; i < afl->queued_items; i++) {
 
-  }
+      q = afl->queue_buf[i];
+      ZLIBREAD(fr_fd, (u8 *)&(q->colorized), q_len, "queue data");
+      ZLIBREAD(fr_fd, res, 1, "check map");
+      if (res[0]) {
+
+        q->trace_mini = ck_alloc(m_len);
+        ZLIBREAD(fr_fd, q->trace_mini, m_len, "trace_mini");
+        r += q_len + m_len + 1;
+
+      } else {
+
+        r += q_len + 1;
+
+      }
+
+      afl->total_bitmap_size += q->bitmap_size;
+      ++afl->total_bitmap_entries;
+      update_bitmap_score(afl, q);
+
+      if (q->was_fuzzed) { --afl->pending_not_fuzzed; }
+
+      if (q->disabled) {
+
+        if (!q->was_fuzzed) { --afl->pending_not_fuzzed; }
+        --afl->active_items;
 
-  memset(afl->virgin_tmout, 255, map_size);
-  memset(afl->virgin_crash, 255, map_size);
+      }
+
+      if (q->var_behavior) { ++afl->queued_variable; }
+      if (q->favored) {
 
-  if (likely(!afl->afl_env.afl_no_startup_calibration)) {
+        ++afl->queued_favored;
+        if (!q->was_fuzzed) { ++afl->pending_favored; }
 
-    perform_dry_run(afl);
+      }
+
+    }
+
+    u8 buf[4];
+    if (NZLIBREAD(fr_fd, buf, 3) > 0) {
+
+      FATAL("invalid trailing data in fastresume.bin");
+
+    }
+
+    OKF("Successfully loaded fastresume.bin (%u bytes)!", r);
+    ZLIBCLOSE(fr_fd);
+    afl->reinit_table = 1;
+    update_calibration_time(afl, &resume_start);
 
   } else {
 
-    ACTF("skipping initial seed calibration due option override!");
-    usleep(1000);
+    // after we have the correct bitmap size we can read the bitmap -B option
+    // and set the virgin maps
+    if (afl->in_bitmap) {
+
+      read_bitmap(afl->in_bitmap, afl->virgin_bits, afl->fsrv.map_size);
+
+    } else {
+
+      memset(afl->virgin_bits, 255, map_size);
+
+    }
+
+    memset(afl->virgin_tmout, 255, map_size);
+    memset(afl->virgin_crash, 255, map_size);
+
+    if (likely(!afl->afl_env.afl_no_startup_calibration)) {
+
+      perform_dry_run(afl);
+
+    } else {
+
+      ACTF("Skipping initial seed calibration due option override!");
+      usleep(1000);
+
+    }
 
   }
 
@@ -2562,7 +2805,7 @@ int main(int argc, char **argv_orig, char **envp) {
   // (void)nice(-20);  // does not improve the speed
 
   #ifdef INTROSPECTION
-  u32 prev_saved_crashes = 0, prev_saved_tmouts = 0;
+  u32 prev_saved_crashes = 0, prev_saved_tmouts = 0, stat_prev_queued_items = 0;
   #endif
   u32 prev_queued_items = 0, runs_in_current_cycle = (u32)-1;
   u8  skipped_fuzz;
@@ -2879,10 +3122,11 @@ int main(int argc, char **argv_orig, char **envp) {
 
       } else {
 
-        if (unlikely(afl->queued_items > prev_queued_items)) {
+        if (unlikely(afl->queued_items > stat_prev_queued_items)) {
 
-          afl->queue_cur->stats_finds += afl->queued_items - prev_queued_items;
-          prev_queued_items = afl->queued_items;
+          afl->queue_cur->stats_finds +=
+              afl->queued_items - stat_prev_queued_items;
+          stat_prev_queued_items = afl->queued_items;
 
         }
 
@@ -2984,6 +3228,28 @@ stop_fuzzing:
   write_bitmap(afl);
   save_auto(afl);
 
+  #ifdef __AFL_CODE_COVERAGE
+  if (afl->fsrv.persistent_trace_bits) {
+
+    char cfn[4096];
+    snprintf(cfn, sizeof(cfn), "%s/covmap.dump", afl->out_dir);
+
+    FILE *cov_fd;
+    if ((cov_fd = fopen(cfn, "w")) == NULL) {
+
+      PFATAL("could not create '%s'", cfn);
+
+    }
+
+    // Write the real map size, as the map size must exactly match the pointer
+    // map in length.
+    fwrite(afl->fsrv.persistent_trace_bits, 1, afl->fsrv.real_map_size, cov_fd);
+    fclose(cov_fd);
+
+  }
+
+  #endif
+
   if (afl->pizza_is_served) {
 
     SAYF(CURSOR_SHOW cLRD "\n\n+++ Baking aborted %s +++\n" cRST,
@@ -3067,6 +3333,74 @@ stop_fuzzing:
   fclose(afl->fsrv.det_plot_file);
   #endif
 
+  if (!afl->afl_env.afl_no_fastresume) {
+
+    /* create fastresume.bin */
+    u8 fr[PATH_MAX];
+    snprintf(fr, PATH_MAX, "%s/fastresume.bin", afl->out_dir);
+    ACTF("Writing %s ...", fr);
+  #ifdef HAVE_ZLIB
+    if ((fr_fd = ZLIBOPEN(fr, "wb9")) != NULL) {
+
+  #else
+    if ((fr_fd = open(fr, O_WRONLY | O_TRUNC | O_CREAT, DEFAULT_PERMISSION)) >=
+        0) {
+
+  #endif
+
+      u8   ver_string[8];
+      u32  w = 0;
+      u64 *ver = (u64 *)ver_string;
+      *ver = afl->shm.cmplog_mode + (sizeof(struct queue_entry) << 1);
+
+      ZLIBWRITE(fr_fd, ver_string, sizeof(ver_string), "ver_string");
+      ZLIBWRITE(fr_fd, afl->virgin_bits, afl->fsrv.map_size, "virgin_bits");
+      ZLIBWRITE(fr_fd, afl->virgin_tmout, afl->fsrv.map_size, "virgin_tmout");
+      ZLIBWRITE(fr_fd, afl->virgin_crash, afl->fsrv.map_size, "virgin_crash");
+      ZLIBWRITE(fr_fd, afl->var_bytes, afl->fsrv.map_size, "var_bytes");
+      w += sizeof(ver_string) + afl->fsrv.map_size * 4;
+
+      u8                  on[1] = {1}, off[1] = {0};
+      u8                 *o_start = (u8 *)&(afl->queue_buf[0]->colorized);
+      u8                 *o_end = (u8 *)&(afl->queue_buf[0]->mother);
+      u32                 q_len = o_end - o_start;
+      u32                 m_len = (afl->fsrv.map_size >> 3);
+      struct queue_entry *q;
+
+      afl->pending_not_fuzzed = afl->queued_items;
+      afl->active_items = afl->queued_items;
+
+      for (u32 i = 0; i < afl->queued_items; i++) {
+
+        q = afl->queue_buf[i];
+        ZLIBWRITE(fr_fd, (u8 *)&(q->colorized), q_len, "queue data");
+        if (!q->trace_mini) {
+
+          ZLIBWRITE(fr_fd, off, 1, "no_mini");
+          w += q_len + 1;
+
+        } else {
+
+          ZLIBWRITE(fr_fd, on, 1, "yes_mini");
+          ZLIBWRITE(fr_fd, q->trace_mini, m_len, "trace_mini");
+          w += q_len + m_len + 1;
+
+        }
+
+      }
+
+      ZLIBCLOSE(fr_fd);
+      afl->var_byte_count = count_bytes(afl, afl->var_bytes);
+      OKF("Written fastresume.bin with %u bytes!", w);
+
+    } else {
+
+      WARNF("Could not create fastresume.bin");
+
+    }
+
+  }
+
   destroy_queue(afl);
   destroy_extras(afl);
   destroy_custom_mutators(afl);
diff --git a/src/afl-performance.c b/src/afl-performance.c
index e8ece6b5..b824fd35 100644
--- a/src/afl-performance.c
+++ b/src/afl-performance.c
@@ -99,11 +99,13 @@ inline u64 hash64(u8 *key, u32 len, u64 seed) {
 
 u64 get_binary_hash(u8 *fn) {
 
+  if (!fn) { return 0; }
   int fd = open(fn, O_RDONLY);
   if (fd < 0) { PFATAL("Unable to open '%s'", fn); }
   struct stat st;
   if (fstat(fd, &st) < 0) { PFATAL("Unable to fstat '%s'", fn); }
   u32 f_len = st.st_size;
+  if (!f_len) { return 0; }
   u8 *f_data = mmap(0, f_len, PROT_READ, MAP_PRIVATE, fd, 0);
   if (f_data == MAP_FAILED) { PFATAL("Unable to mmap file '%s'", fn); }
   close(fd);
diff --git a/src/hashmap.c b/src/hashmap.c
index a0a9283c..5834802f 100644
--- a/src/hashmap.c
+++ b/src/hashmap.c
@@ -59,7 +59,7 @@ static inline unsigned int hash(uint64_t key) {
 bool hashmap_search_and_add(uint8_t type, uint64_t key) {
 
   if (unlikely(type >= 8)) return false;
-  uint64_t     val = (key & 0xf8ffffffffffffff) + (type << 56);
+  uint64_t     val = (key & 0xf8ffffffffffffff) + ((uint64_t)type << 56);
   unsigned int index = hash(val);
   HashNode    *node = _hashmap->table[index];
   while (node) {