about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2020-07-29 11:41:54 +0200
committerGitHub <noreply@github.com>2020-07-29 11:41:54 +0200
commit8e3ca8eaa9350cc5967de23a432d8d462855f069 (patch)
tree7896b5ec1f49b3ebe32d1466e85ea8f536ad599e /src
parent015fde3703c7b67ee65d74b0f4b7b68b5d1e4d7e (diff)
parent4550613f58342632061944ef09add63240d774cc (diff)
downloadafl++-8e3ca8eaa9350cc5967de23a432d8d462855f069.tar.gz
Merge pull request #473 from AFLplusplus/text_inputs
add splice
Diffstat (limited to 'src')
-rw-r--r--src/afl-fuzz-one.c783
-rw-r--r--src/afl-fuzz-queue.c111
-rw-r--r--src/afl-fuzz-redqueen.c102
-rw-r--r--src/afl-fuzz-state.c15
-rw-r--r--src/afl-fuzz-stats.c133
-rw-r--r--src/afl-fuzz.c81
6 files changed, 1091 insertions, 134 deletions
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index 72383727..f8680100 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -24,6 +24,12 @@
  */
 
 #include "afl-fuzz.h"
+#include <string.h>
+#include <limits.h>
+
+/* static u8 *strnstr(const u8 *s, const u8 *find, size_t slen);
+static u32 string_replace(u8 **out_buf, s32 *temp_len, u32 pos, u8 *from,
+                          u8 *to); */
 
 /* MOpt */
 
@@ -362,6 +368,526 @@ static void locate_diffs(u8 *ptr1, u8 *ptr2, u32 len, s32 *first, s32 *last) {
 
 #endif                                                     /* !IGNORE_FINDS */
 
+#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
+
+#if 0
+/* search a string */
+
+static u8 *strnstr(const u8 *s, const u8 *find, size_t slen) {
+
+  char   c, sc;
+  size_t len;
+
+  if ((c = *find++) != '\0') {
+
+    len = strlen(find);
+    do {
+
+      do {
+
+        if (slen-- < 1 || (sc = *s++) == '\0') return (NULL);
+
+      } while (sc != c);
+
+      if (len > slen) return (NULL);
+
+    } while (strncmp(s, find, len) != 0);
+
+    s--;
+
+  }
+
+  return ((u8 *)s);
+
+}
+
+/* replace between deliminators, if rep == NULL, then we will duplicate the
+ * target */
+
+static u32 delim_replace(u8 **out_buf, s32 *temp_len, size_t pos,
+                         const u8 *ldelim, const u8 *rdelim, u8 *rep) {
+
+  u8 *end_buf = *out_buf + *temp_len;
+  u8 *ldelim_start = strnstr(*out_buf + pos, ldelim, *temp_len - pos);
+
+  if (ldelim_start != NULL) {
+
+    u32 max = (end_buf - ldelim_start - 1 > AFL_TXT_STRING_MAX_LEN
+                   ? AFL_TXT_STRING_MAX_LEN
+                   : end_buf - ldelim_start - 1);
+
+    if (max > 0) {
+
+      u8 *rdelim_end = strnstr(ldelim_start + 1, rdelim, max);
+
+      if (rdelim_end != NULL) {
+
+        u32 rep_len, delim_space_len = rdelim_end - ldelim_start - 1, xtra = 0;
+
+        if (rep != NULL) {
+
+          rep_len = (u32)strlen(rep);
+
+        } else {  // NULL? then we copy the value in between the delimiters
+
+          rep_len = delim_space_len;
+          delim_space_len = 0;
+          rep = ldelim_start + 1;
+          xtra = rep_len;
+
+        }
+
+        if (rep_len != delim_space_len) {
+
+          memmove(ldelim_start + rep_len + xtra + 1, rdelim_end,
+                  *temp_len - (rdelim_end - *out_buf));
+
+        }
+
+        memcpy(ldelim_start + 1, rep, rep_len);
+        *temp_len = (*temp_len - delim_space_len + rep_len);
+
+        return 1;
+
+      }
+
+    }
+
+  }
+
+  return 0;
+
+}
+
+static u32 delim_swap(u8 **out_buf, s32 *temp_len, size_t pos, const u8 *ldelim,
+                      const u8 *mdelim, const u8 *rdelim) {
+
+  u8 *out_buf_end = *out_buf + *temp_len;
+  u32 max = (*temp_len - pos > AFL_TXT_STRING_MAX_LEN ? AFL_TXT_STRING_MAX_LEN
+                                                      : *temp_len - pos);
+  u8 *ldelim_start = strnstr(*out_buf + pos, ldelim, max);
+
+  if (ldelim_start != NULL) {
+
+    max = (out_buf_end - ldelim_start - 1 > AFL_TXT_STRING_MAX_LEN
+               ? AFL_TXT_STRING_MAX_LEN
+               : out_buf_end - ldelim_start - 1);
+    if (max > 1) {
+
+      u8 *mdelim_pos = strnstr(ldelim_start + 1, mdelim, max);
+
+      if (mdelim_pos != NULL) {
+
+        max = (out_buf_end - mdelim_pos - 1 > AFL_TXT_STRING_MAX_LEN
+                   ? AFL_TXT_STRING_MAX_LEN
+                   : out_buf_end - mdelim_pos - 1);
+        if (max > 0) {
+
+          u8 *rdelim_end = strnstr(mdelim + 1, rdelim, max);
+
+          if (rdelim_end != NULL) {
+
+            u32 first_len = mdelim_pos - ldelim_start - 1;
+            u32 second_len = rdelim_end - mdelim_pos - 1;
+            u8  scratch[AFL_TXT_STRING_MAX_LEN];
+
+            memcpy(scratch, ldelim_start + 1, first_len);
+
+            if (first_len != second_len) {
+
+              memmove(ldelim_start + second_len + 1, mdelim_pos,
+                      out_buf_end - mdelim_pos);
+
+            }
+
+            memcpy(ldelim_start + 1, mdelim_pos + 1, second_len);
+
+            if (first_len != second_len) {
+
+              memmove(mdelim_pos + first_len + 1, rdelim_end,
+                      out_buf_end - rdelim_end);
+
+            }
+
+            memcpy(mdelim_pos + 1, scratch, first_len);
+
+            return 1;
+
+          }
+
+        }
+
+      }
+
+    }
+
+  }
+
+  return 0;
+
+}
+
+/* replace a string */
+
+static u32 string_replace(u8 **out_buf, s32 *temp_len, u32 pos, u8 *from,
+                          u8 *to) {
+
+  u8 *start = strnstr(*out_buf + pos, from, *temp_len - pos);
+
+  if (start) {
+
+    u32 from_len = strlen(from);
+    u32 to_len = strlen(to);
+
+    if (from_len != to_len) {
+
+      memmove(start + to_len, start + from_len,
+              *temp_len - from_len - (start - *out_buf));
+
+    }
+
+    memcpy(start, to, to_len);
+    *temp_len = (*temp_len - from_len + to_len);
+
+    return 1;
+
+  }
+
+  return 0;
+
+}
+
+/* Returns 1 if a mutant was generated and placed in out_buf, 0 if none
+ * generated. */
+
+static const uint8_t text_mutation_special_chars[] = {
+
+    '\t', '\n', '\r', ' ', '!', '"', '$', '%', '&', '\'', '(', ')', '*',
+    '+',  ',',  '-',  '.', '/', ':', ';', '<', '=', '>',  '?', '@', '[',
+    '\\', ']',  '^',  '_', '`', '{', '|', '}', '~', ' '  // space is here twice
+
+};
+
+static int text_mutation(afl_state_t *afl, u8 **out_buf, s32 *orig_temp_len) {
+
+  if (*orig_temp_len < AFL_TXT_MIN_LEN) { return 0; }
+
+  s32 temp_len;
+  u32 pos, yes = 0,
+           mutations = rand_below(afl, AFL_TXT_STRING_MAX_MUTATIONS) + 16;
+  u8 *new_buf =
+      ck_maybe_grow(BUF_PARAMS(out_scratch),
+                    *orig_temp_len + AFL_TXT_STRING_MAX_MUTATIONS + 16);
+  u8 fromc[2] = {0, 0}, toc[2] = {0, 0};
+  temp_len = *orig_temp_len;
+  memcpy(new_buf, *out_buf, temp_len);
+  new_buf[temp_len] = 0;
+
+  for (u32 i = 0; i < mutations; i++) {
+
+    if (temp_len < AFL_TXT_MIN_LEN) { return 0; }
+
+    pos = rand_below(afl, temp_len - 1);
+    int choice = rand_below(afl, 100);
+
+    switch (choice) {
+
+        /* 50% -> fixed replacements */
+
+      case 0:                                /* Semantic statement deletion */
+        yes += string_replace(&new_buf, &temp_len, pos, "\n", "#");
+        break;
+      case 1:
+        yes += string_replace(&new_buf, &temp_len, pos, "(", "(!");
+        break;
+      case 2:
+        yes += string_replace(&new_buf, &temp_len, pos, "==", "!=");
+        break;
+      case 3:
+        yes += string_replace(&new_buf, &temp_len, pos, "!=", "==");
+        break;
+      case 4:
+        yes += string_replace(&new_buf, &temp_len, pos, "==", "<");
+        break;
+      case 5:
+        yes += string_replace(&new_buf, &temp_len, pos, "<", "==");
+        break;
+      case 6:
+        yes += string_replace(&new_buf, &temp_len, pos, "==", ">");
+        break;
+      case 7:
+        yes += string_replace(&new_buf, &temp_len, pos, ">", "==");
+        break;
+      case 8:
+        yes += string_replace(&new_buf, &temp_len, pos, "=", "<");
+        break;
+      case 9:
+        yes += string_replace(&new_buf, &temp_len, pos, "=", ">");
+        break;
+      case 10:
+        yes += string_replace(&new_buf, &temp_len, pos, "<", ">");
+        break;
+      case 11:
+        yes += string_replace(&new_buf, &temp_len, pos, ">", "<");
+        break;
+      case 12:
+        yes += string_replace(&new_buf, &temp_len, pos, "++", "--");
+        break;
+      case 13:
+        yes += string_replace(&new_buf, &temp_len, pos, "--", "++");
+        break;
+      case 14:
+        yes += string_replace(&new_buf, &temp_len, pos, "+", "-");
+        break;
+      case 15:
+        yes += string_replace(&new_buf, &temp_len, pos, "-", "+");
+        break;
+      case 16:
+        yes += string_replace(&new_buf, &temp_len, pos, "0", "1");
+        break;
+      case 17:
+        yes += string_replace(&new_buf, &temp_len, pos, "1", "0");
+        break;
+      case 18:
+        yes += string_replace(&new_buf, &temp_len, pos, "&&", "||");
+        break;
+      case 19:
+        yes += string_replace(&new_buf, &temp_len, pos, "||", "&&");
+        break;
+      case 20:
+        yes += string_replace(&new_buf, &temp_len, pos, "!", "");
+        break;
+      case 21:
+        yes += string_replace(&new_buf, &temp_len, pos, "==", "=");
+        break;
+      case 22:
+        yes += string_replace(&new_buf, &temp_len, pos, "=", "==");
+        break;
+      case 23:
+        yes += string_replace(&new_buf, &temp_len, pos, "--", "");
+        break;
+      case 24:
+        yes += string_replace(&new_buf, &temp_len, pos, "<<", "<");
+        break;
+      case 25:
+        yes += string_replace(&new_buf, &temp_len, pos, ">>", ">");
+        break;
+      case 26:
+        yes += string_replace(&new_buf, &temp_len, pos, "<", "<<");
+        break;
+      case 27:
+        yes += string_replace(&new_buf, &temp_len, pos, ">", ">>");
+        break;
+      case 28:
+        yes += string_replace(&new_buf, &temp_len, pos, "'", "\"");
+        break;
+      case 29:
+        yes += string_replace(&new_buf, &temp_len, pos, "\"", "'");
+        break;
+      case 30:  /* Remove a semicolon delimited statement after a semicolon */
+        yes += delim_replace(&new_buf, &temp_len, pos, ";", ";", ";");
+        break;
+      case 31: /* Remove a semicolon delimited statement after a left curly
+                  brace */
+        yes += delim_replace(&new_buf, &temp_len, pos, "}", ";", "}");
+        break;
+      case 32:                            /* Remove a curly brace construct */
+        yes += delim_replace(&new_buf, &temp_len, pos, "{", "}", "");
+        break;
+      case 33:         /* Replace a curly brace construct with an empty one */
+        yes += delim_replace(&new_buf, &temp_len, pos, "{", "}", "{}");
+        break;
+      case 34:
+        yes += delim_swap(&new_buf, &temp_len, pos, ";", ";", ";");
+        break;
+      case 35:
+        yes += delim_swap(&new_buf, &temp_len, pos, "}", ";", ";");
+        break;
+      case 36:                        /* Swap comma delimited things case 1 */
+        yes += delim_swap(&new_buf, &temp_len, pos, "(", ",", ")");
+        break;
+      case 37:                        /* Swap comma delimited things case 2 */
+        yes += delim_swap(&new_buf, &temp_len, pos, "(", ",", ",");
+        break;
+      case 38:                        /* Swap comma delimited things case 3 */
+        yes += delim_swap(&new_buf, &temp_len, pos, ",", ",", ",");
+        break;
+      case 39:                        /* Swap comma delimited things case 4 */
+        yes += delim_swap(&new_buf, &temp_len, pos, ",", ",", ")");
+        break;
+      case 40:                                        /* Just delete a line */
+        yes += delim_replace(&new_buf, &temp_len, pos, "\n", "\n", "");
+        break;
+      case 41:                      /* Delete something like "const" case 1 */
+        yes += delim_replace(&new_buf, &temp_len, pos, " ", " ", "");
+        break;
+      case 42:                      /* Delete something like "const" case 2 */
+        yes += delim_replace(&new_buf, &temp_len, pos, "\n", " ", "");
+        break;
+      case 43:                      /* Delete something like "const" case 3 */
+        yes += delim_replace(&new_buf, &temp_len, pos, "(", " ", "");
+        break;
+      case 44:                        /* Swap space delimited things case 1 */
+        yes += delim_swap(&new_buf, &temp_len, pos, " ", " ", " ");
+        break;
+      case 45:                        /* Swap space delimited things case 2 */
+        yes += delim_swap(&new_buf, &temp_len, pos, " ", " ", ")");
+        break;
+      case 46:                        /* Swap space delimited things case 3 */
+        yes += delim_swap(&new_buf, &temp_len, pos, "(", " ", " ");
+        break;
+      case 47:                        /* Swap space delimited things case 4 */
+        yes += delim_swap(&new_buf, &temp_len, pos, "(", " ", ")");
+        break;
+      case 48:                           /* Duplicate a single line of code */
+        yes += delim_replace(&new_buf, &temp_len, pos, "\n", "\n", NULL);
+        break;
+      case 49:  /* Duplicate a construct (most often, a non-nested for loop */
+        yes += delim_replace(&new_buf, &temp_len, pos, "\n", "}", NULL);
+        break;
+      default: {
+
+        /* 5% is transforming ascii numbers */
+
+        if (choice < 55) {
+
+          for (u32 j = pos; j < temp_len; ++j) {
+
+            if (isdigit(new_buf[j])) {
+
+              new_buf[temp_len] =
+                  0;  // should be safe thanks to the initial grow
+
+              u8 *               endptr;
+              unsigned long long num =
+                  strtoull(new_buf + j, (char **)&endptr, 0);
+
+              switch (rand_below(afl, 8)) {
+
+                case 0:
+                  num = rand_below(afl, INT_MAX);
+                  break;
+                case 1:
+                  num = rand_next(afl);
+                  break;
+                case 2:
+                  num += 1 + rand_below(afl, 255);
+                  break;
+                case 3:
+                  num -= 1 + rand_below(afl, 255);
+                  break;
+                case 4:
+                  num *= 1 + rand_below(afl, 255);
+                  break;
+                case 5:
+                  num /= 1 + rand_below(afl, 255);
+                  break;
+                case 6:
+                  num /= 1 + rand_below(afl, 255);
+                  break;
+                case 7:
+                  num = ~num;
+                  break;
+
+              }
+
+              const char *fmt = "%llu";
+              if (rand_below(afl, 5) == 0)  // add - sign with 1/5 probability
+                fmt = "-%llu";
+
+              size_t num_len = snprintf(NULL, 0, fmt, num);
+              size_t old_len = endptr - (new_buf + j);
+              if (num_len < old_len) {
+
+                memmove(new_buf + j + num_len, new_buf + j + old_len,
+                        temp_len - (j + old_len));
+                snprintf(new_buf + j, num_len, fmt, num);
+                temp_len -= old_len - num_len;
+
+              } else if (num_len == old_len) {
+
+                snprintf(new_buf + j, num_len, fmt, num);
+
+              } else {
+
+                new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch),
+                                        temp_len + (num_len - old_len) +
+                                            AFL_TXT_STRING_MAX_MUTATIONS + 1);
+                memmove(new_buf + j + num_len, new_buf + j + old_len,
+                        temp_len - (j + old_len));
+                snprintf(new_buf + j, num_len, fmt, num);
+                temp_len += num_len - old_len;
+
+              }
+
+              yes += 1;
+              break;
+
+            }
+
+          }
+
+        } else if (choice < 85) {
+
+          /* 30% is special character transform */
+
+          fromc[0] = text_mutation_special_chars[rand_below(
+              afl, sizeof(text_mutation_special_chars))];
+
+          do {
+
+            toc[0] = text_mutation_special_chars[rand_below(
+                afl, sizeof(text_mutation_special_chars))];
+
+          } while (toc[0] == fromc[0]);
+
+          yes += string_replace(&new_buf, &temp_len, pos, fromc, toc);
+          break;
+
+        } else {
+
+          /* 15% is random text character transform */
+
+          u32 iter, cnt, loc, prev_loc = temp_len;
+          if (temp_len > 32) {
+
+            cnt = 1 + rand_below(afl, 5);
+
+          } else {
+
+            cnt = rand_below(afl, 2);
+
+          }
+
+          for (iter = 0; iter <= cnt; iter++) {
+
+            while ((loc = rand_below(afl, temp_len)) == prev_loc)
+              ;
+            new_buf[loc] = 32 + rand_below(afl, 'z' - ' ' + 1);
+            prev_loc = loc;
+
+          }
+
+        }
+
+      }
+
+    }
+
+  }
+
+  if (yes == 0 || temp_len <= 0) { return 0; }
+
+  swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch));
+  *out_buf = new_buf;
+  *orig_temp_len = temp_len;
+
+  return 1;
+
+}
+
+#endif                                                              /* if 0 */
+
 /* Take the current entry from the queue, fuzz it for a while. This
    function is a tad too long... returns 0 if fuzzed successfully, 1 if
    skipped or bailed out. */
@@ -1854,6 +2380,22 @@ havoc_stage:
   /* We essentially just do several thousand runs (depending on perf_score)
      where we take the input file and make random stacked tweaks. */
 
+  u32 r_max, r;
+
+  if (unlikely(afl->expand_havoc)) {
+
+    /* add expensive havoc cases here, they are activated after a full
+       cycle without finds happened */
+
+    r_max = 16 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0);
+    /* + (afl->queue_cur->is_ascii ? AFL_TXT_BIAS : 0); */
+
+  } else {
+
+    r_max = 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0);
+
+  }
+
   for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
 
     u32 use_stacking = 1 << (1 + rand_below(afl, HAVOC_STACK_POW2));
@@ -1896,8 +2438,9 @@ havoc_stage:
 
       }
 
-      switch (rand_below(
-          afl, 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0))) {
+      // retry_havoc:
+
+      switch ((r = rand_below(afl, r_max))) {
 
         case 0:
 
@@ -2192,85 +2735,206 @@ havoc_stage:
 
         }
 
-          /* Values 15 and 16 can be selected only if there are any extras
-             present in the dictionaries. */
+        default:
 
-        case 15: {
+          if (likely(r <= 16 && (afl->extras_cnt || afl->a_extras_cnt))) {
 
-          /* Overwrite bytes with an extra. */
+            /* Values 15 and 16 can be selected only if there are any extras
+               present in the dictionaries. */
 
-          if (!afl->extras_cnt || (afl->a_extras_cnt && rand_below(afl, 2))) {
+            if (r == 15) {
 
-            /* No user-specified extras or odds in our favor. Let's use an
-               auto-detected one. */
+              /* Overwrite bytes with an extra. */
 
-            u32 use_extra = rand_below(afl, afl->a_extras_cnt);
-            u32 extra_len = afl->a_extras[use_extra].len;
-            u32 insert_at;
+              if (!afl->extras_cnt ||
+                  (afl->a_extras_cnt && rand_below(afl, 2))) {
 
-            if (extra_len > temp_len) { break; }
+                /* No user-specified extras or odds in our favor. Let's use an
+                   auto-detected one. */
 
-            insert_at = rand_below(afl, temp_len - extra_len + 1);
-            memcpy(out_buf + insert_at, afl->a_extras[use_extra].data,
-                   extra_len);
+                u32 use_extra = rand_below(afl, afl->a_extras_cnt);
+                u32 extra_len = afl->a_extras[use_extra].len;
+                u32 insert_at;
 
-          } else {
+                if (extra_len > temp_len) { break; }
 
-            /* No auto extras or odds in our favor. Use the dictionary. */
+                insert_at = rand_below(afl, temp_len - extra_len + 1);
+                memcpy(out_buf + insert_at, afl->a_extras[use_extra].data,
+                       extra_len);
 
-            u32 use_extra = rand_below(afl, afl->extras_cnt);
-            u32 extra_len = afl->extras[use_extra].len;
-            u32 insert_at;
+              } else {
 
-            if (extra_len > temp_len) { break; }
+                /* No auto extras or odds in our favor. Use the dictionary. */
 
-            insert_at = rand_below(afl, temp_len - extra_len + 1);
-            memcpy(out_buf + insert_at, afl->extras[use_extra].data, extra_len);
+                u32 use_extra = rand_below(afl, afl->extras_cnt);
+                u32 extra_len = afl->extras[use_extra].len;
+                u32 insert_at;
 
-          }
+                if (extra_len > temp_len) { break; }
 
-          break;
+                insert_at = rand_below(afl, temp_len - extra_len + 1);
+                memcpy(out_buf + insert_at, afl->extras[use_extra].data,
+                       extra_len);
 
-        }
+              }
+
+              break;
+
+            } else {  // case 16
+
+              u32 use_extra, extra_len,
+                  insert_at = rand_below(afl, temp_len + 1);
+              u8 *ptr;
+
+              /* Insert an extra. Do the same dice-rolling stuff as for the
+                 previous case. */
+
+              if (!afl->extras_cnt ||
+                  (afl->a_extras_cnt && rand_below(afl, 2))) {
+
+                use_extra = rand_below(afl, afl->a_extras_cnt);
+                extra_len = afl->a_extras[use_extra].len;
+                ptr = afl->a_extras[use_extra].data;
+
+              } else {
+
+                use_extra = rand_below(afl, afl->extras_cnt);
+                extra_len = afl->extras[use_extra].len;
+                ptr = afl->extras[use_extra].data;
+
+              }
+
+              if (temp_len + extra_len >= MAX_FILE) { break; }
 
-        case 16: {
+              out_buf = ck_maybe_grow(BUF_PARAMS(out), temp_len + extra_len);
+
+              /* Tail */
+              memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
+                      temp_len - insert_at);
 
-          u32 use_extra, extra_len, insert_at = rand_below(afl, temp_len + 1);
-          u8 *ptr;
+              /* Inserted part */
+              memcpy(out_buf + insert_at, ptr, extra_len);
 
-          /* Insert an extra. Do the same dice-rolling stuff as for the
-             previous case. */
+              temp_len += extra_len;
 
-          if (!afl->extras_cnt || (afl->a_extras_cnt && rand_below(afl, 2))) {
+              break;
 
-            use_extra = rand_below(afl, afl->a_extras_cnt);
-            extra_len = afl->a_extras[use_extra].len;
-            ptr = afl->a_extras[use_extra].data;
+            }
 
           } else {
 
-            use_extra = rand_below(afl, afl->extras_cnt);
-            extra_len = afl->extras[use_extra].len;
-            ptr = afl->extras[use_extra].data;
+            /*
+                        switch (r) {
 
-          }
+                          case 15:  // fall through
+                          case 16:
+                          case 17: {*/
 
-          if (temp_len + extra_len >= MAX_FILE) { break; }
+            /* Overwrite bytes with a randomly selected chunk from another
+               testcase or insert that chunk. */
 
-          out_buf = ck_maybe_grow(BUF_PARAMS(out), temp_len + extra_len);
+            if (afl->queued_paths < 4) break;
 
-          /* Tail */
-          memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
-                  temp_len - insert_at);
+            /* Pick a random queue entry and seek to it. */
 
-          /* Inserted part */
-          memcpy(out_buf + insert_at, ptr, extra_len);
+            u32 tid;
+            do
+              tid = rand_below(afl, afl->queued_paths);
+            while (tid == afl->current_entry);
 
-          temp_len += extra_len;
+            struct queue_entry *target = afl->queue_buf[tid];
 
-          break;
+            /* Make sure that the target has a reasonable length. */
 
-        }
+            while (target && (target->len < 2 || target == afl->queue_cur))
+              target = target->next;
+
+            if (!target) break;
+
+            /* Read the testcase into a new buffer. */
+
+            fd = open(target->fname, O_RDONLY);
+
+            if (unlikely(fd < 0)) {
+
+              PFATAL("Unable to open '%s'", target->fname);
+
+            }
+
+            u32 new_len = target->len;
+            u8 *new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), new_len);
+
+            ck_read(fd, new_buf, new_len, target->fname);
+
+            close(fd);
+
+            u8 overwrite = 0;
+            if (temp_len >= 2 && rand_below(afl, 2))
+              overwrite = 1;
+            else if (temp_len + HAVOC_BLK_XL >= MAX_FILE) {
+
+              if (temp_len >= 2)
+                overwrite = 1;
+              else
+                break;
+
+            }
+
+            if (overwrite) {
+
+              u32 copy_from, copy_to, copy_len;
+
+              copy_len = choose_block_len(afl, new_len - 1);
+              if (copy_len > temp_len) copy_len = temp_len;
+
+              copy_from = rand_below(afl, new_len - copy_len + 1);
+              copy_to = rand_below(afl, temp_len - copy_len + 1);
+
+              memmove(out_buf + copy_to, new_buf + copy_from, copy_len);
+
+            } else {
+
+              u32 clone_from, clone_to, clone_len;
+
+              clone_len = choose_block_len(afl, new_len);
+              clone_from = rand_below(afl, new_len - clone_len + 1);
+
+              clone_to = rand_below(afl, temp_len);
+
+              u8 *temp_buf =
+                  ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + clone_len);
+
+              /* Head */
+
+              memcpy(temp_buf, out_buf, clone_to);
+
+              /* Inserted part */
+
+              memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len);
+
+              /* Tail */
+              memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to,
+                     temp_len - clone_to);
+
+              swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch));
+              out_buf = temp_buf;
+              temp_len += clone_len;
+
+            }
+
+            break;
+
+          }
+
+          /*              default:
+
+                          // perform ascii mutations
+                          if (text_mutation(afl, &out_buf, &temp_len) == 0)
+                            goto retry_havoc;
+
+                      }  // end default: switch(r)
+
+          */
 
       }
 
@@ -2357,20 +3021,7 @@ retry_splicing:
     } while (tid == afl->current_entry);
 
     afl->splicing_with = tid;
-    target = afl->queue;
-
-    while (tid >= 100) {
-
-      target = target->next_100;
-      tid -= 100;
-
-    }
-
-    while (tid--) {
-
-      target = target->next;
-
-    }
+    target = afl->queue_buf[tid];
 
     /* Make sure that the target has a reasonable length. */
 
@@ -4750,7 +5401,7 @@ u8 fuzz_one(afl_state_t *afl) {
 
   return (key_val_lv_1 | key_val_lv_2);
 
-#undef BUF_PARAMS
-
 }
 
+#undef BUF_PARAMS
+
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index 7afdd9f1..56073b0a 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -24,6 +24,9 @@
 
 #include "afl-fuzz.h"
 #include <limits.h>
+#include <ctype.h>
+
+#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
 
 /* Mark deterministic checks as done for a particular queue entry. We use the
    .state file to avoid repeating deterministic fuzzing when resuming aborted
@@ -100,6 +103,108 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) {
 
 }
 
+/* check if ascii or UTF-8 */
+
+static u8 check_if_text(struct queue_entry *q) {
+
+  if (q->len < AFL_TXT_MIN_LEN) return 0;
+
+  u8  buf[MAX_FILE];
+  s32 fd, len = q->len, offset = 0, ascii = 0, utf8 = 0, comp;
+
+  if ((fd = open(q->fname, O_RDONLY)) < 0) return 0;
+  if ((comp = read(fd, buf, len)) != len) return 0;
+  close(fd);
+
+  while (offset < len) {
+
+    // ASCII: <= 0x7F to allow ASCII control characters
+    if ((buf[offset + 0] == 0x09 || buf[offset + 0] == 0x0A ||
+         buf[offset + 0] == 0x0D ||
+         (0x20 <= buf[offset + 0] && buf[offset + 0] <= 0x7E))) {
+
+      offset++;
+      utf8++;
+      ascii++;
+      continue;
+
+    }
+
+    if (isascii((int)buf[offset]) || isprint((int)buf[offset])) {
+
+      ascii++;
+      // we continue though as it can also be a valid utf8
+
+    }
+
+    // non-overlong 2-byte
+    if (((0xC2 <= buf[offset + 0] && buf[offset + 0] <= 0xDF) &&
+         (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF))) {
+
+      offset += 2;
+      utf8++;
+      comp--;
+      continue;
+
+    }
+
+    // excluding overlongs
+    if ((buf[offset + 0] == 0xE0 &&
+         (0xA0 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+         (0x80 <= buf[offset + 2] &&
+          buf[offset + 2] <= 0xBF)) ||  // straight 3-byte
+        (((0xE1 <= buf[offset + 0] && buf[offset + 0] <= 0xEC) ||
+          buf[offset + 0] == 0xEE || buf[offset + 0] == 0xEF) &&
+         (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+         (0x80 <= buf[offset + 2] &&
+          buf[offset + 2] <= 0xBF)) ||  // excluding surrogates
+        (buf[offset + 0] == 0xED &&
+         (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0x9F) &&
+         (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF))) {
+
+      offset += 3;
+      utf8++;
+      comp -= 2;
+      continue;
+
+    }
+
+    // planes 1-3
+    if ((buf[offset + 0] == 0xF0 &&
+         (0x90 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+         (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) &&
+         (0x80 <= buf[offset + 3] &&
+          buf[offset + 3] <= 0xBF)) ||  // planes 4-15
+        ((0xF1 <= buf[offset + 0] && buf[offset + 0] <= 0xF3) &&
+         (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0xBF) &&
+         (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) &&
+         (0x80 <= buf[offset + 3] && buf[offset + 3] <= 0xBF)) ||  // plane 16
+        (buf[offset + 0] == 0xF4 &&
+         (0x80 <= buf[offset + 1] && buf[offset + 1] <= 0x8F) &&
+         (0x80 <= buf[offset + 2] && buf[offset + 2] <= 0xBF) &&
+         (0x80 <= buf[offset + 3] && buf[offset + 3] <= 0xBF))) {
+
+      offset += 4;
+      utf8++;
+      comp -= 3;
+      continue;
+
+    }
+
+    offset++;
+
+  }
+
+  u32 percent_utf8 = (utf8 * 100) / comp;
+  u32 percent_ascii = (ascii * 100) / len;
+
+  if (percent_utf8 >= percent_ascii && percent_utf8 >= AFL_TXT_MIN_PERCENT)
+    return 2;
+  if (percent_ascii >= AFL_TXT_MIN_PERCENT) return 1;
+  return 0;
+
+}
+
 /* Append new test case to the queue. */
 
 void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
@@ -138,6 +243,10 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
 
   }
 
+  struct queue_entry **queue_buf = ck_maybe_grow(
+      BUF_PARAMS(queue), afl->queued_paths * sizeof(struct queue_entry *));
+  queue_buf[afl->queued_paths - 1] = q;
+
   afl->last_path_time = get_cur_time();
 
   if (afl->custom_mutators_count) {
@@ -159,6 +268,8 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
 
   }
 
+  q->is_ascii = check_if_text(q);
+
 }
 
 /* Destroy the entire queue. */
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index c53e0e06..57e60c3d 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -24,6 +24,7 @@
 
  */
 
+#include <limits.h>
 #include "afl-fuzz.h"
 #include "cmplog.h"
 
@@ -262,6 +263,58 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) {
 
 }
 
+static long long strntoll(const char *str, size_t sz, char **end, int base) {
+
+  char        buf[64];
+  long long   ret;
+  const char *beg = str;
+
+  for (; beg && sz && *beg == ' '; beg++, sz--)
+    ;
+
+  if (!sz || sz >= sizeof(buf)) {
+
+    if (end) *end = (char *)str;
+    return 0;
+
+  }
+
+  memcpy(buf, beg, sz);
+  buf[sz] = '\0';
+  ret = strtoll(buf, end, base);
+  if (ret == LLONG_MIN || ret == LLONG_MAX) return ret;
+  if (end) *end = (char *)beg + (*end - buf);
+  return ret;
+
+}
+
+static unsigned long long strntoull(const char *str, size_t sz, char **end,
+                                    int base) {
+
+  char               buf[64];
+  unsigned long long ret;
+  const char *       beg = str;
+
+  for (; beg && sz && *beg == ' '; beg++, sz--)
+    ;
+
+  if (!sz || sz >= sizeof(buf)) {
+
+    if (end) *end = (char *)str;
+    return 0;
+
+  }
+
+  memcpy(buf, beg, sz);
+  buf[sz] = '\0';
+  ret = strtoull(buf, end, base);
+  if (end) *end = (char *)beg + (*end - buf);
+  return ret;
+
+}
+
+#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size
+
 static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
                               u64 pattern, u64 repl, u64 o_pattern, u32 idx,
                               u8 *orig_buf, u8 *buf, u32 len, u8 do_reverse,
@@ -279,7 +332,54 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
   u32 its_len = len - idx;
   // *status = 0;
 
-  if (SHAPE_BYTES(h->shape) >= 8) {
+  u8 *               endptr;
+  u8                 use_num = 0, use_unum = 0;
+  unsigned long long unum;
+  long long          num;
+  if (afl->queue_cur->is_ascii) {
+
+    endptr = buf_8;
+    num = strntoll(buf_8, len - idx, (char **)&endptr, 0);
+    if (endptr == buf_8) {
+
+      unum = strntoull(buf_8, len - idx, (char **)&endptr, 0);
+      if (endptr == buf_8) use_unum = 1;
+
+    } else
+
+      use_num = 1;
+
+  }
+
+  if (use_num && num == pattern) {
+
+    size_t old_len = endptr - buf_8;
+    size_t num_len = snprintf(NULL, 0, "%lld", num);
+
+    u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), len + num_len);
+    memcpy(new_buf, buf, idx);
+
+    snprintf(new_buf + idx, num_len, "%lld", num);
+    memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len);
+
+    if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; }
+
+  } else if (use_unum && unum == pattern) {
+
+    size_t old_len = endptr - buf_8;
+    size_t num_len = snprintf(NULL, 0, "%llu", unum);
+
+    u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), len + num_len);
+    memcpy(new_buf, buf, idx);
+
+    snprintf(new_buf + idx, num_len, "%llu", unum);
+    memcpy(new_buf + idx + num_len, buf_8 + old_len, len - idx - old_len);
+
+    if (unlikely(its_fuzz(afl, new_buf, len, status))) { return 1; }
+
+  }
+
+  if (SHAPE_BYTES(h->shape) >= 8 && *status != 1) {
 
     if (its_len >= 8 && *buf_64 == pattern && *o_buf_64 == o_pattern) {
 
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index e0e43f54..66280ed1 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -293,6 +293,20 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
             afl->afl_env.afl_autoresume =
                 get_afl_env(afl_environment_variables[i]) ? 1 : 0;
 
+          } else if (!strncmp(env, "AFL_CYCLE_SCHEDULES",
+
+                              afl_environment_variable_len)) {
+
+            afl->cycle_schedules = afl->afl_env.afl_cycle_schedules =
+                get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
+          } else if (!strncmp(env, "AFL_EXPAND_HAVOC_NOW",
+
+                              afl_environment_variable_len)) {
+
+            afl->expand_havoc = afl->afl_env.afl_expand_havoc =
+                get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
           } else if (!strncmp(env, "AFL_CAL_FAST",
 
                               afl_environment_variable_len)) {
@@ -405,6 +419,7 @@ void afl_state_deinit(afl_state_t *afl) {
   if (afl->pass_stats) { ck_free(afl->pass_stats); }
   if (afl->orig_cmp_map) { ck_free(afl->orig_cmp_map); }
 
+  if (afl->queue_buf) { free(afl->queue_buf); }
   if (afl->out_buf) { free(afl->out_buf); }
   if (afl->out_scratch_buf) { free(afl->out_scratch_buf); }
   if (afl->eff_buf) { free(afl->eff_buf); }
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 2546a57a..9b16c226 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -82,58 +82,60 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
   if (getrusage(RUSAGE_CHILDREN, &rus)) { rus.ru_maxrss = 0; }
 #endif
 
-  fprintf(f,
-          "start_time        : %llu\n"
-          "last_update       : %llu\n"
-          "run_time          : %llu\n"
-          "fuzzer_pid        : %u\n"
-          "cycles_done       : %llu\n"
-          "cycles_wo_finds   : %llu\n"
-          "execs_done        : %llu\n"
-          "execs_per_sec     : %0.02f\n"
-          "execs_ps_last_min : %0.02f\n"
-          "paths_total       : %u\n"
-          "paths_favored     : %u\n"
-          "paths_found       : %u\n"
-          "paths_imported    : %u\n"
-          "max_depth         : %u\n"
-          "cur_path          : %u\n"    /* Must match find_start_position() */
-          "pending_favs      : %u\n"
-          "pending_total     : %u\n"
-          "variable_paths    : %u\n"
-          "stability         : %0.02f%%\n"
-          "bitmap_cvg        : %0.02f%%\n"
-          "unique_crashes    : %llu\n"
-          "unique_hangs      : %llu\n"
-          "last_path         : %llu\n"
-          "last_crash        : %llu\n"
-          "last_hang         : %llu\n"
-          "execs_since_crash : %llu\n"
-          "exec_timeout      : %u\n"
-          "slowest_exec_ms   : %u\n"
-          "peak_rss_mb       : %lu\n"
-          "cpu_affinity      : %d\n"
-          "edges_found       : %u\n"
-          "var_byte_count    : %u\n"
-          "afl_banner        : %s\n"
-          "afl_version       : " VERSION
-          "\n"
-          "target_mode       : %s%s%s%s%s%s%s%s%s\n"
-          "command_line      : %s\n",
-          afl->start_time / 1000, cur_time / 1000,
-          (cur_time - afl->start_time) / 1000, (u32)getpid(),
-          afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds,
-          afl->fsrv.total_execs,
-          afl->fsrv.total_execs /
-              ((double)(get_cur_time() - afl->start_time) / 1000),
-          afl->last_avg_execs_saved, afl->queued_paths, afl->queued_favored,
-          afl->queued_discovered, afl->queued_imported, afl->max_depth,
-          afl->current_entry, afl->pending_favored, afl->pending_not_fuzzed,
-          afl->queued_variable, stability, bitmap_cvg, afl->unique_crashes,
-          afl->unique_hangs, afl->last_path_time / 1000,
-          afl->last_crash_time / 1000, afl->last_hang_time / 1000,
-          afl->fsrv.total_execs - afl->last_crash_execs, afl->fsrv.exec_tmout,
-          afl->slowest_exec_ms,
+  fprintf(
+      f,
+      "start_time        : %llu\n"
+      "last_update       : %llu\n"
+      "run_time          : %llu\n"
+      "fuzzer_pid        : %u\n"
+      "cycles_done       : %llu\n"
+      "cycles_wo_finds   : %llu\n"
+      "execs_done        : %llu\n"
+      "execs_per_sec     : %0.02f\n"
+      "execs_ps_last_min : %0.02f\n"
+      "paths_total       : %u\n"
+      "paths_favored     : %u\n"
+      "paths_found       : %u\n"
+      "paths_imported    : %u\n"
+      "max_depth         : %u\n"
+      "cur_path          : %u\n"        /* Must match find_start_position() */
+      "pending_favs      : %u\n"
+      "pending_total     : %u\n"
+      "variable_paths    : %u\n"
+      "stability         : %0.02f%%\n"
+      "bitmap_cvg        : %0.02f%%\n"
+      "unique_crashes    : %llu\n"
+      "unique_hangs      : %llu\n"
+      "last_path         : %llu\n"
+      "last_crash        : %llu\n"
+      "last_hang         : %llu\n"
+      "execs_since_crash : %llu\n"
+      "exec_timeout      : %u\n"
+      "slowest_exec_ms   : %u\n"
+      "peak_rss_mb       : %lu\n"
+      "cpu_affinity      : %d\n"
+      "edges_found       : %u\n"
+      "var_byte_count    : %u\n"
+      "havoc_expansion   : %u\n"
+      "afl_banner        : %s\n"
+      "afl_version       : " VERSION
+      "\n"
+      "target_mode       : %s%s%s%s%s%s%s%s%s\n"
+      "command_line      : %s\n",
+      afl->start_time / 1000, cur_time / 1000,
+      (cur_time - afl->start_time) / 1000, (u32)getpid(),
+      afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds,
+      afl->fsrv.total_execs,
+      afl->fsrv.total_execs /
+          ((double)(get_cur_time() - afl->start_time) / 1000),
+      afl->last_avg_execs_saved,
+      afl->queued_paths, afl->queued_favored, afl->queued_discovered,
+      afl->queued_imported, afl->max_depth, afl->current_entry,
+      afl->pending_favored, afl->pending_not_fuzzed, afl->queued_variable,
+      stability, bitmap_cvg, afl->unique_crashes, afl->unique_hangs,
+      afl->last_path_time / 1000, afl->last_crash_time / 1000,
+      afl->last_hang_time / 1000, afl->fsrv.total_execs - afl->last_crash_execs,
+      afl->fsrv.exec_tmout, afl->slowest_exec_ms,
 #ifndef __HAIKU__
   #ifdef __APPLE__
           (unsigned long int)(rus.ru_maxrss >> 20),
@@ -148,20 +150,19 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
 #else
           -1,
 #endif
-          t_bytes, afl->var_byte_count, 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 " : "",
-          afl->persistent_mode ? "persistent " : "",
-          afl->shmem_testcase_mode ? "shmem_testcase " : "",
-          afl->deferred_mode ? "deferred " : "",
-          (afl->unicorn_mode || afl->fsrv.qemu_mode ||
-           afl->non_instrumented_mode || afl->no_forkserver ||
-           afl->crash_mode || afl->persistent_mode || afl->deferred_mode)
-              ? ""
-              : "default",
-          afl->orig_cmdline);
+      t_bytes, afl->var_byte_count, afl->expand_havoc, 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 " : "",
+      afl->persistent_mode ? "persistent " : "",
+      afl->shmem_testcase_mode ? "shmem_testcase " : "",
+      afl->deferred_mode ? "deferred " : "",
+      (afl->unicorn_mode || afl->fsrv.qemu_mode || afl->non_instrumented_mode ||
+       afl->no_forkserver || afl->crash_mode || afl->persistent_mode ||
+       afl->deferred_mode)
+          ? ""
+          : "default",
+      afl->orig_cmdline);
   /* ignore errors */
 
   if (afl->debug) {
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index eb4b6a87..5bedf6e1 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -916,6 +916,7 @@ int main(int argc, char **argv_orig, char **envp) {
   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) {
 
@@ -1271,11 +1272,42 @@ int main(int argc, char **argv_orig, char **envp) {
       /* If we had a full queue cycle with no new finds, try
          recombination strategies next. */
 
-      if (afl->queued_paths == prev_queued) {
+      if (afl->queued_paths == prev_queued &&
+          (get_cur_time() - afl->start_time) >= 3600) {
 
         if (afl->use_splicing) {
 
           ++afl->cycles_wo_finds;
+          switch (afl->expand_havoc) {
+
+            case 0:
+              afl->expand_havoc = 1;
+              break;
+            case 1:
+              if (afl->limit_time_sig == 0) {
+
+                afl->limit_time_sig = -1;
+                afl->limit_time_puppet = 0;
+
+              }
+
+              afl->expand_havoc = 2;
+              break;
+            case 2:
+              // afl->cycle_schedules = 1;
+              afl->expand_havoc = 3;
+              break;
+            case 3:
+              // nothing else currently
+              break;
+
+          }
+
+          if (afl->expand_havoc) {
+
+          } else
+
+            afl->expand_havoc = 1;
 
         } else {
 
@@ -1289,6 +1321,53 @@ int main(int argc, char **argv_orig, char **envp) {
 
       }
 
+      if (afl->cycle_schedules) {
+
+        /* we cannot mix non-AFLfast schedules with others */
+
+        switch (afl->schedule) {
+
+          case EXPLORE:
+            afl->schedule = EXPLOIT;
+            break;
+          case EXPLOIT:
+            afl->schedule = MMOPT;
+            break;
+          case MMOPT:
+            afl->schedule = SEEK;
+            break;
+          case SEEK:
+            afl->schedule = EXPLORE;
+            break;
+          case FAST:
+            afl->schedule = COE;
+            break;
+          case COE:
+            afl->schedule = LIN;
+            break;
+          case LIN:
+            afl->schedule = QUAD;
+            break;
+          case QUAD:
+            afl->schedule = RARE;
+            break;
+          case RARE:
+            afl->schedule = FAST;
+            break;
+
+        }
+
+        struct queue_entry *q = afl->queue;
+        // we must recalculate the scores of all queue entries
+        while (q) {
+
+          update_bitmap_score(afl, q);
+          q = q->next;
+
+        }
+
+      }
+
       prev_queued = afl->queued_paths;
 
       if (afl->sync_id && afl->queue_cycle == 1 &&