added afl_custom_fuzz_count
diff --git a/GNUmakefile b/GNUmakefile
index 3c5e10e..cae172d 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -37,18 +37,18 @@
 ASAN_OPTIONS=detect_leaks=0
 
 ifeq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" ""
-ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+ ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=full -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
 	CFLAGS_FLTO ?= -flto=full
-else
- ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
-	CFLAGS_FLTO ?= -flto=thin
  else
-  ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+  ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto=thin -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
+	CFLAGS_FLTO ?= -flto=thin
+  else
+   ifeq "$(shell echo 'int main() {return 0; }' | $(CC) $(CFLAGS) -Werror -x c - -flto -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
 	CFLAGS_FLTO ?= -flto
+   endif
   endif
  endif
 endif
-endif
 
 ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -fno-move-loop-invariants -fdisable-tree-cunrolli -x c - -o .test 2>/dev/null && echo 1 || echo 0 ; rm -f .test )" "1"
 	SPECIAL_PERFORMANCE += -fno-move-loop-invariants -fdisable-tree-cunrolli
diff --git a/docs/Changelog.md b/docs/Changelog.md
index f7bc960..45fbd52 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -18,6 +18,9 @@
       dict entries without recompiling.
     - AFL_FORKSRV_INIT_TMOUT env variable added to control the time to wait for
       the forkserver to come up without the need to increase the overall timeout.
+  - custom mutators:
+    - added afl_custom_fuzz_count/fuzz_count function to allow specifying the 
+      number of fuzz attempts for custom_fuzz
   - llvm_mode:
     - Ported SanCov to LTO, and made it the default for LTO. better
       instrumentation locations
diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md
index a22c809..75dbea2 100644
--- a/docs/custom_mutators.md
+++ b/docs/custom_mutators.md
@@ -32,6 +32,7 @@
 C/C++:
 ```c
 void *afl_custom_init(afl_t *afl, unsigned int seed);
+uint32_t afl_custom_fuzz_count(void *data, const u8 *buf, size_t buf_size);
 size_t afl_custom_fuzz(void *data, uint8_t *buf, size_t buf_size, u8 **out_buf, uint8_t *add_buf, size_t add_buf_size, size_t max_size);
 size_t afl_custom_post_process(void *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf);
 int32_t afl_custom_init_trim(void *data, uint8_t *buf, size_t buf_size);
@@ -49,6 +50,9 @@
 def init(seed):
     pass
 
+def fuzz_count(buf, add_buf, max_size):
+    return cnt
+
 def fuzz(buf, add_buf, max_size):
     return mutated_out
 
@@ -88,6 +92,11 @@
     This method determines whether the custom fuzzer should fuzz the current
     queue entry or not
 
+- `fuzz_count` (optional):
+
+    This method can be used to instruct afl-fuzz how often to perform a fuzz
+    attempt on this input data.
+
 - `fuzz` (optional):
 
     This method performs custom mutations on a given input. It also accepts an
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 1f1dda3..01aa1a7 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -288,6 +288,7 @@
 enum {
 
   /* 00 */ PY_FUNC_INIT,
+  /* 01 */ PY_FUNC_FUZZ_COUNT,
   /* 01 */ PY_FUNC_FUZZ,
   /* 02 */ PY_FUNC_POST_PROCESS,
   /* 03 */ PY_FUNC_INIT_TRIM,
@@ -680,6 +681,24 @@
   void *(*afl_custom_init)(afl_state_t *afl, unsigned int seed);
 
   /**
+   * This method is called just before fuzzing a queue entry with the custom
+   * mutator, and receives the initial buffer. It should return the number of
+   * fuzzes to perform.
+   *
+   * A value of 0 means no fuzzing of this queue entry.
+   *
+   * The function is now allowed to change the data.
+   *
+   * (Optional)
+   *
+   * @param data pointer returned in afl_custom_init for this fuzz case
+   * @param buf Buffer containing the test case
+   * @param buf_size Size of the test case
+   * @return The amount of fuzzes to perform on this queue entry, 0 = skip
+   */
+  u32 (*afl_custom_fuzz_count)(void *data, const u8 *buf, size_t buf_size);
+
+  /**
    * Perform custom mutations on a given input
    *
    * (Optional for now. Required in the future)
@@ -867,6 +886,7 @@
 struct custom_mutator *load_custom_mutator_py(afl_state_t *, char *);
 void                   finalize_py_module(void *);
 
+u32    fuzz_count_py(void *, const u8 *, size_t);
 size_t post_process_py(void *, u8 *, size_t, u8 **);
 s32    init_trim_py(void *, u8 *, size_t);
 s32    post_trim_py(void *, u8);
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index c496975..72f3dc3 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -634,7 +634,7 @@
 
         if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) {
 
-          // this is not afl-fuzz - we deny and return
+          // this is not afl-fuzz - or it is cmplog - we deny and return
           if (fsrv->use_shmem_fuzz) {
 
             status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c
index 8cc2425..d6c368d 100644
--- a/src/afl-fuzz-extras.c
+++ b/src/afl-fuzz-extras.c
@@ -251,7 +251,7 @@
   if (afl->extras_cnt > afl->max_det_extras) {
 
     OKF("More than %d tokens - will use them probabilistically.",
-          afl->max_det_extras);
+        afl->max_det_extras);
 
   }
 
@@ -406,7 +406,7 @@
   if (afl->extras_cnt == afl->max_det_extras + 1) {
 
     OKF("More than %d tokens - will use them probabilistically.",
-          afl->max_det_extras);
+        afl->max_det_extras);
 
   }
 
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index 22578df..d24b7db 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -166,6 +166,11 @@
 
   }
 
+  /* "afl_custom_fuzz_count", optional */
+  mutator->afl_custom_fuzz_count = dlsym(dh, "afl_custom_fuzz_count");
+  if (!mutator->afl_custom_fuzz_count)
+    ACTF("optional symbol 'afl_custom_fuzz_count' not found.");
+
   /* "afl_custom_deinit", optional for backward compatibility */
   mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit");
   if (!mutator->afl_custom_deinit)
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index c0c036d..03c0d3a 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -1672,7 +1672,7 @@
 
   if (afl->stage_max < HAVOC_MIN) { afl->stage_max = HAVOC_MIN; }
 
-  const u32 max_seed_size = MAX_FILE;
+  const u32 max_seed_size = MAX_FILE, saved_max = afl->stage_max;
 
   orig_hit_cnt = afl->queued_paths + afl->unique_crashes;
 
@@ -1680,104 +1680,119 @@
 
     if (el->afl_custom_fuzz) {
 
+      if (el->afl_custom_fuzz_count)
+        afl->stage_max = el->afl_custom_fuzz_count(el->data, out_buf, len);
+      else
+        afl->stage_max = saved_max;
+
       has_custom_fuzz = true;
 
       afl->stage_short = el->name_short;
 
-      for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max;
-           ++afl->stage_cur) {
+      if (afl->stage_max) {
 
-        struct queue_entry *target;
-        u32                 tid;
-        u8 *                new_buf;
+        for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max;
+             ++afl->stage_cur) {
 
-      retry_external_pick:
-        /* Pick a random other queue entry for passing to external API */
+          struct queue_entry *target;
+          u32                 tid;
+          u8 *                new_buf;
 
-        do {
+        retry_external_pick:
+          /* Pick a random other queue entry for passing to external API */
 
-          tid = rand_below(afl, afl->queued_paths);
+          do {
 
-        } while (tid == afl->current_entry && afl->queued_paths > 1);
+            tid = rand_below(afl, afl->queued_paths);
 
-        target = afl->queue;
+          } while (tid == afl->current_entry && afl->queued_paths > 1);
 
-        while (tid >= 100) {
+          target = afl->queue;
 
-          target = target->next_100;
-          tid -= 100;
+          while (tid >= 100) {
 
-        }
-
-        while (tid--) {
-
-          target = target->next;
-
-        }
-
-        /* Make sure that the target has a reasonable length. */
-
-        while (target && (target->len < 2 || target == afl->queue_cur) &&
-               afl->queued_paths > 3) {
-
-          target = target->next;
-          ++afl->splicing_with;
-
-        }
-
-        if (!target) { goto retry_external_pick; }
-
-        /* Read the additional testcase into a new buffer. */
-        fd = open(target->fname, O_RDONLY);
-        if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", target->fname); }
-
-        new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), target->len);
-        if (unlikely(!new_buf)) { PFATAL("alloc"); }
-        ck_read(fd, new_buf, target->len, target->fname);
-        close(fd);
-
-        u8 *mutated_buf = NULL;
-
-        size_t mutated_size =
-            el->afl_custom_fuzz(el->data, out_buf, len, &mutated_buf, new_buf,
-                                target->len, max_seed_size);
-
-        if (unlikely(!mutated_buf)) {
-
-          FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size);
-
-        }
-
-        if (mutated_size > 0) {
-
-          if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) {
-
-            goto abandon_entry;
+            target = target->next_100;
+            tid -= 100;
 
           }
 
-          /* If we're finding new stuff, let's run for a bit longer, limits
-            permitting. */
+          while (tid--) {
 
-          if (afl->queued_paths != havoc_queued) {
+            target = target->next;
 
-            if (perf_score <= afl->havoc_max_mult * 100) {
+          }
 
-              afl->stage_max *= 2;
-              perf_score *= 2;
+          /* Make sure that the target has a reasonable length. */
+
+          while (target && (target->len < 2 || target == afl->queue_cur) &&
+                 afl->queued_paths > 3) {
+
+            target = target->next;
+            ++afl->splicing_with;
+
+          }
+
+          if (!target) { goto retry_external_pick; }
+
+          /* Read the additional testcase into a new buffer. */
+          fd = open(target->fname, O_RDONLY);
+          if (unlikely(fd < 0)) {
+
+            PFATAL("Unable to open '%s'", target->fname);
+
+          }
+
+          new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), target->len);
+          if (unlikely(!new_buf)) { PFATAL("alloc"); }
+          ck_read(fd, new_buf, target->len, target->fname);
+          close(fd);
+
+          u8 *mutated_buf = NULL;
+
+          size_t mutated_size =
+              el->afl_custom_fuzz(el->data, out_buf, len, &mutated_buf, new_buf,
+                                  target->len, max_seed_size);
+
+          if (unlikely(!mutated_buf)) {
+
+            FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size);
+
+          }
+
+          if (mutated_size > 0) {
+
+            if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) {
+
+              goto abandon_entry;
 
             }
 
-            havoc_queued = afl->queued_paths;
+            /* If we're finding new stuff, let's run for a bit longer, limits
+              permitting. */
+
+            if (afl->queued_paths != havoc_queued) {
+
+              if (perf_score <= afl->havoc_max_mult * 100) {
+
+                afl->stage_max *= 2;
+                perf_score *= 2;
+
+              }
+
+              havoc_queued = afl->queued_paths;
+
+            }
 
           }
 
-        }
+          /* `(afl->)out_buf` may have been changed by the call to custom_fuzz
+           */
+          /* TODO: Only do this when `mutated_buf` == `out_buf`? Branch vs
+           * Memcpy.
+           */
+          memcpy(out_buf, in_buf, len);
 
-        /* `(afl->)out_buf` may have been changed by the call to custom_fuzz */
-        /* TODO: Only do this when `mutated_buf` == `out_buf`? Branch vs Memcpy.
-         */
-        memcpy(out_buf, in_buf, len);
+        }
 
       }
 
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
index e540f54..68540dd 100644
--- a/src/afl-fuzz-python.c
+++ b/src/afl-fuzz-python.c
@@ -347,6 +347,12 @@
 
   }
 
+  if (py_functions[PY_FUNC_FUZZ_COUNT]) {
+
+    mutator->afl_custom_fuzz_count = fuzz_count_py;
+
+  }
+
   if (py_functions[PY_FUNC_POST_TRIM]) {
 
     mutator->afl_custom_post_trim = post_trim_py;
@@ -477,6 +483,44 @@
 
 }
 
+u32 fuzz_count_py(void *py_mutator, const u8 *buf, size_t buf_size) {
+
+  PyObject *py_args, *py_value;
+
+  py_args = PyTuple_New(1);
+  py_value = PyByteArray_FromStringAndSize(buf, buf_size);
+  if (!py_value) {
+
+    Py_DECREF(py_args);
+    FATAL("Failed to convert arguments");
+
+  }
+
+  PyTuple_SetItem(py_args, 0, py_value);
+
+  py_value = PyObject_CallObject(
+      ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_FUZZ_COUNT], py_args);
+  Py_DECREF(py_args);
+
+  if (py_value != NULL) {
+
+  #if PY_MAJOR_VERSION >= 3
+    u32 retcnt = (u32)PyLong_AsLong(py_value);
+  #else
+    u32 retcnt = PyInt_AsLong(py_value);
+  #endif
+    Py_DECREF(py_value);
+    return retcnt;
+
+  } else {
+
+    PyErr_Print();
+    FATAL("Call failed");
+
+  }
+
+}
+
 s32 post_trim_py(void *py_mutator, u8 success) {
 
   PyObject *py_args, *py_value;