about summary refs log tree commit diff
path: root/custom_mutators
diff options
context:
space:
mode:
Diffstat (limited to 'custom_mutators')
-rw-r--r--custom_mutators/README.md41
-rw-r--r--custom_mutators/atnwalk/Makefile7
-rw-r--r--custom_mutators/atnwalk/README.md43
-rw-r--r--custom_mutators/atnwalk/atnwalk.c539
-rw-r--r--custom_mutators/autotokens/Makefile26
-rw-r--r--custom_mutators/autotokens/README34
-rw-r--r--custom_mutators/autotokens/autotokens.cpp1101
-rw-r--r--custom_mutators/examples/custom_mutator_helpers.h342
-rw-r--r--custom_mutators/examples/custom_send.c17
-rw-r--r--custom_mutators/examples/example.c116
-rw-r--r--custom_mutators/examples/post_library_gif.so.c53
-rw-r--r--custom_mutators/examples/post_library_png.so.c24
-rw-r--r--custom_mutators/examples/simple_example.c28
-rwxr-xr-xcustom_mutators/gramatron/build_gramatron_mutator.sh2
-rwxr-xr-xcustom_mutators/grammar_mutator/build_grammar_mutator.sh2
-rw-r--r--custom_mutators/honggfuzz/custom_mutator_helpers.h22
-rw-r--r--custom_mutators/honggfuzz/honggfuzz.c18
-rw-r--r--custom_mutators/honggfuzz/mangle.c1181
-rw-r--r--custom_mutators/libafl_base/Cargo.toml2
-rw-r--r--custom_mutators/libafl_base/src/lib.rs36
l---------custom_mutators/radamsa/custom_mutator_helpers.h1
-rw-r--r--custom_mutators/radamsa/radamsa-mutator.c11
-rw-r--r--custom_mutators/rust/custom_mutator-sys/Cargo.toml6
-rw-r--r--custom_mutators/rust/custom_mutator-sys/build.rs4
-rw-r--r--custom_mutators/rust/custom_mutator-sys/src/lib.rs2
-rw-r--r--custom_mutators/rust/custom_mutator/Cargo.toml2
-rw-r--r--custom_mutators/rust/custom_mutator/src/lib.rs109
-rw-r--r--custom_mutators/rust/example/Cargo.toml2
-rw-r--r--custom_mutators/rust/example_lain/Cargo.toml2
29 files changed, 2632 insertions, 1141 deletions
diff --git a/custom_mutators/README.md b/custom_mutators/README.md
index 0289e150..a5a572c0 100644
--- a/custom_mutators/README.md
+++ b/custom_mutators/README.md
@@ -11,7 +11,30 @@ The `./examples` folder contains examples for custom mutators in python and C.
 
 In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`.
 
-## The AFL++ Grammar Mutator
+## Production-Ready Custom Mutators
+
+This directory holds ready to use custom mutators.
+Just type "make" in the individual subdirectories.
+
+Use with e.g.
+
+`AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/radamsa/radamsa-mutator.so afl-fuzz ....`
+
+and add `AFL_CUSTOM_MUTATOR_ONLY=1` if you only want to use the custom mutator.
+
+Multiple custom mutators can be used by separating their paths with `:` in the environment variable.
+
+### The AFL++ grammar agnostic grammar mutator
+
+In `./autotokens` you find a token-level fuzzer that does not need to know
+anything about the grammar of an input as long as it is in ascii and allows
+whitespace.
+It is very fast and effective.
+
+If you are looking for an example of how to effectively create a custom
+mutator take a look at this one.
+
+### The AFL++ Grammar Mutator
 
 If you use git to clone AFL++, then the following will incorporate our
 excellent grammar custom mutator:
@@ -24,18 +47,18 @@ Read the README in the [Grammar-Mutator] repository on how to use it.
 
 [Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator
 
-## Production-Ready Custom Mutators
-
-This directory holds ready to use custom mutators.
-Just type "make" in the individual subdirectories.
+Note that this custom mutator is not very good though!
 
-Use with e.g.
+### Other Mutators
 
-`AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/radamsa/radamsa-mutator.so afl-fuzz ....`
+atnwalk and gramatron are grammar custom mutators. Example grammars are
+provided.
 
-and add `AFL_CUSTOM_MUTATOR_ONLY=1` if you only want to use the custom mutator.
+honggfuzz, libfuzzer and  libafl are partial implementations based on the
+mutator implementations of the respective fuzzers. 
+More for playing than serious usage.
 
-Multiple custom mutators can be used by separating their paths with `:` in the environment variable.
+radamsa is slow and not very good.
 
 ## 3rd Party Custom Mutators
 
diff --git a/custom_mutators/atnwalk/Makefile b/custom_mutators/atnwalk/Makefile
new file mode 100644
index 00000000..bf83cae5
--- /dev/null
+++ b/custom_mutators/atnwalk/Makefile
@@ -0,0 +1,7 @@
+all:	atnwalk.so
+
+atnwalk.so:	atnwalk.c
+	$(CC) -I ../../include/ -shared -fPIC -O3 -o atnwalk.so atnwalk.c
+
+clean:
+	rm -f *.so *.o *~ core
diff --git a/custom_mutators/atnwalk/README.md b/custom_mutators/atnwalk/README.md
new file mode 100644
index 00000000..730349a3
--- /dev/null
+++ b/custom_mutators/atnwalk/README.md
@@ -0,0 +1,43 @@
+# ATNwalk: Grammar-Based Fuzzing using Only Bit-Mutations
+
+This is a custom mutator integration of ATNwalk that works by communicating via UNIX domain sockets.
+
+Refer to [https://github.com/atnwalk/testbed](https://github.com/atnwalk/testbed) for detailed instructions on how to get ATNwalk running.
+
+## Build
+
+Just type `make` to build `atnwalk.so`.
+
+## Run
+
+**NOTE:** The commands below just demonstrate an example how running ATNwalk looks like and require a working [testbed](https://github.com/atnwalk/testbed)
+
+```bash
+# create the required a random seed first
+mkdir -p ~/campaign/example/seeds
+cd ~/campaign/example/seeds
+head -c1 /dev/urandom | ~/atnwalk/build/javascript/bin/decode -wb > seed.decoded 2> seed.encoded
+
+# create the required atnwalk directory and copy the seed
+cd ../
+mkdir -p atnwalk/in
+cp ./seeds/seed.encoded atnwalk/in/seed
+cd atnwalk
+
+# assign to a single core when benchmarking it, change the CPU number as required
+CPU_ID=0
+
+# start the ATNwalk server
+nohup taskset -c ${CPU_ID} ${HOME}/atnwalk/build/javascript/bin/server 100 > server.log 2>&1 &
+
+# start AFL++ with ATNwalk
+AFL_SKIP_CPUFREQ=1 \
+  AFL_DISABLE_TRIM=1 \
+  AFL_CUSTOM_MUTATOR_ONLY=1 \
+  AFL_CUSTOM_MUTATOR_LIBRARY=${HOME}/AFLplusplus/custom_mutators/atnwalk/atnwalk.so \
+  AFL_POST_PROCESS_KEEP_ORIGINAL=1 \
+  ~/AFLplusplus/afl-fuzz -t 100 -i in/ -o out -b ${CPU_ID} -- ~/jerryscript/build/bin/jerry
+
+# make sure to kill the ATNwalk server process after you're done
+kill "$(cat atnwalk.pid)"
+```
diff --git a/custom_mutators/atnwalk/atnwalk.c b/custom_mutators/atnwalk/atnwalk.c
new file mode 100644
index 00000000..c3a2cd95
--- /dev/null
+++ b/custom_mutators/atnwalk/atnwalk.c
@@ -0,0 +1,539 @@
+#include "afl-fuzz.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#define BUF_SIZE_INIT 4096
+#define SOCKET_NAME "./atnwalk.socket"
+
+// how many errors (e.g. timeouts) to tolerate until moving on to the next queue
+// entry
+#define ATNWALK_ERRORS_MAX 1
+
+// how many execution timeouts to tolerate until moving on to the next queue
+// entry
+#define EXEC_TIMEOUT_MAX 2
+
+// handshake constants
+const uint8_t SERVER_ARE_YOU_ALIVE = 213;
+const uint8_t SERVER_YES_I_AM_ALIVE = 42;
+
+// control bits
+const uint8_t SERVER_CROSSOVER_BIT = 0b00000001;
+const uint8_t SERVER_MUTATE_BIT = 0b00000010;
+const uint8_t SERVER_DECODE_BIT = 0b00000100;
+const uint8_t SERVER_ENCODE_BIT = 0b00001000;
+
+typedef struct atnwalk_mutator {
+
+  afl_state_t *afl;
+  uint8_t      atnwalk_error_count;
+  uint64_t     prev_timeouts;
+  uint32_t     prev_hits;
+  uint32_t     stage_havoc_cur;
+  uint32_t     stage_havoc_max;
+  uint32_t     stage_splice_cur;
+  uint32_t     stage_splice_max;
+  uint8_t     *fuzz_buf;
+  size_t       fuzz_size;
+  uint8_t     *post_process_buf;
+  size_t       post_process_size;
+
+} atnwalk_mutator_t;
+
+int read_all(int fd, uint8_t *buf, size_t buf_size) {
+
+  int    n;
+  size_t offset = 0;
+  while (offset < buf_size) {
+
+    n = read(fd, buf + offset, buf_size - offset);
+    if (n == -1) { return 0; }
+    offset += n;
+
+  }
+
+  return 1;
+
+}
+
+int write_all(int fd, uint8_t *buf, size_t buf_size) {
+
+  int    n;
+  size_t offset = 0;
+  while (offset < buf_size) {
+
+    n = write(fd, buf + offset, buf_size - offset);
+    if (n == -1) { return 0; }
+    offset += n;
+
+  }
+
+  return 1;
+
+}
+
+void put_uint32(uint8_t *buf, uint32_t val) {
+
+  buf[0] = (uint8_t)(val >> 24);
+  buf[1] = (uint8_t)((val & 0x00ff0000) >> 16);
+  buf[2] = (uint8_t)((val & 0x0000ff00) >> 8);
+  buf[3] = (uint8_t)(val & 0x000000ff);
+
+}
+
+uint32_t to_uint32(uint8_t *buf) {
+
+  uint32_t val = 0;
+  val |= (((uint32_t)buf[0]) << 24);
+  val |= (((uint32_t)buf[1]) << 16);
+  val |= (((uint32_t)buf[2]) << 8);
+  val |= ((uint32_t)buf[3]);
+  return val;
+
+}
+
+void put_uint64(uint8_t *buf, uint64_t val) {
+
+  buf[0] = (uint8_t)(val >> 56);
+  buf[1] = (uint8_t)((val & 0x00ff000000000000) >> 48);
+  buf[2] = (uint8_t)((val & 0x0000ff0000000000) >> 40);
+  buf[3] = (uint8_t)((val & 0x000000ff00000000) >> 32);
+  buf[4] = (uint8_t)((val & 0x00000000ff000000) >> 24);
+  buf[5] = (uint8_t)((val & 0x0000000000ff0000) >> 16);
+  buf[6] = (uint8_t)((val & 0x000000000000ff00) >> 8);
+  buf[7] = (uint8_t)(val & 0x00000000000000ff);
+
+}
+
+/**
+ * Initialize this custom mutator
+ *
+ * @param[in] afl a pointer to the internal state object. Can be ignored for
+ * now.
+ * @param[in] seed A seed for this mutator - the same seed should always mutate
+ * in the same way.
+ * @return Pointer to the data object this custom mutator instance should use.
+ *         There may be multiple instances of this mutator in one afl-fuzz run!
+ *         Return NULL on error.
+ */
+atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
+
+  srand(seed);
+  atnwalk_mutator_t *data =
+      (atnwalk_mutator_t *)malloc(sizeof(atnwalk_mutator_t));
+  if (!data) {
+
+    perror("afl_custom_init alloc");
+    return NULL;
+
+  }
+
+  data->afl = afl;
+  data->prev_hits = 0;
+  data->fuzz_buf = (uint8_t *)malloc(BUF_SIZE_INIT);
+  data->fuzz_size = BUF_SIZE_INIT;
+  data->post_process_buf = (uint8_t *)malloc(BUF_SIZE_INIT);
+  data->post_process_size = BUF_SIZE_INIT;
+  return data;
+
+}
+
+unsigned int afl_custom_fuzz_count(atnwalk_mutator_t   *data,
+                                   const unsigned char *buf, size_t buf_size) {
+
+  // afl_custom_fuzz_count is called exactly once before entering the
+  // 'stage-loop' for the current queue entry thus, we use it to reset the error
+  // count and to initialize stage variables (somewhat not intended by the API,
+  // but still better than rewriting the whole thing to have a custom mutator
+  // stage)
+  data->atnwalk_error_count = 0;
+  data->prev_timeouts = data->afl->total_tmouts;
+
+  // it might happen that on the last execution of the splice stage a new path
+  // is found we need to fix that here and count it
+  if (data->prev_hits) {
+
+    data->afl->stage_finds[STAGE_SPLICE] +=
+        data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
+
+  }
+
+  data->prev_hits = data->afl->queued_items + data->afl->saved_crashes;
+  data->stage_havoc_cur = 0;
+  data->stage_splice_cur = 0;
+
+  // 50% havoc, 50% splice
+  data->stage_havoc_max = data->afl->stage_max >> 1;
+  if (data->stage_havoc_max < HAVOC_MIN) { data->stage_havoc_max = HAVOC_MIN; }
+  data->stage_splice_max = data->stage_havoc_max;
+  return data->stage_havoc_max + data->stage_splice_max;
+
+}
+
+size_t fail_fatal(int fd_socket, uint8_t **out_buf) {
+
+  if (fd_socket != -1) { close(fd_socket); }
+  *out_buf = NULL;
+  return 0;
+
+}
+
+size_t fail_gracefully(int fd_socket, atnwalk_mutator_t *data, uint8_t *buf,
+                       size_t buf_size, uint8_t **out_buf) {
+
+  if (fd_socket != -1) { close(fd_socket); }
+  data->atnwalk_error_count++;
+  if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) {
+
+    data->afl->stage_max = data->afl->stage_cur;
+
+  }
+
+  *out_buf = buf;
+  return buf_size;
+
+}
+
+/**
+ * Perform custom mutations on a given input
+ *
+ * (Optional for now. Required in the future)
+ *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
+ * @param[in] buf Pointer to input data to be mutated
+ * @param[in] buf_size Size of input data
+ * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on
+ * error.
+ * @param[in] add_buf Buffer containing the additional test case
+ * @param[in] add_buf_size Size of the additional test case
+ * @param[in] max_size Maximum size of the mutated output. The mutation must not
+ *     produce data larger than max_size.
+ * @return Size of the mutated output.
+ */
+size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size,
+                       uint8_t **out_buf, uint8_t *add_buf, size_t add_buf_size,
+                       size_t max_size) {
+
+  struct sockaddr_un addr;
+  int                fd_socket;
+  uint8_t            ctrl_buf[8];
+  uint8_t            wanted;
+
+  // let's display what's going on in a nice way
+  if (data->stage_havoc_cur == 0) {
+
+    data->afl->stage_name = (uint8_t *)"atnwalk - havoc";
+
+  }
+
+  if (data->stage_havoc_cur == data->stage_havoc_max) {
+
+    data->afl->stage_name = (uint8_t *)"atnwalk - splice";
+
+  }
+
+  // increase the respective havoc or splice counters
+  if (data->stage_havoc_cur < data->stage_havoc_max) {
+
+    data->stage_havoc_cur++;
+    data->afl->stage_cycles[STAGE_HAVOC]++;
+
+  } else {
+
+    // if there is nothing to splice, continue with havoc and skip splicing this
+    // time
+    if (data->afl->ready_for_splicing_count < 1) {
+
+      data->stage_havoc_max = data->afl->stage_max;
+      data->stage_havoc_cur++;
+      data->afl->stage_cycles[STAGE_HAVOC]++;
+
+    } else {
+
+      data->stage_splice_cur++;
+      data->afl->stage_cycles[STAGE_SPLICE]++;
+
+    }
+
+  }
+
+  // keep track of found new corpus seeds per stage
+  if (data->afl->queued_items + data->afl->saved_crashes > data->prev_hits) {
+
+    if (data->stage_splice_cur <= 1) {
+
+      data->afl->stage_finds[STAGE_HAVOC] +=
+          data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
+
+    } else {
+
+      data->afl->stage_finds[STAGE_SPLICE] +=
+          data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
+
+    }
+
+  }
+
+  data->prev_hits = data->afl->queued_items + data->afl->saved_crashes;
+
+  // check whether this input produces a lot of timeouts, if it does then
+  // abandon this queue entry
+  if (data->afl->total_tmouts - data->prev_timeouts >= EXEC_TIMEOUT_MAX) {
+
+    data->afl->stage_max = data->afl->stage_cur;
+    return fail_gracefully(-1, data, buf, buf_size, out_buf);
+
+  }
+
+  // initialize the socket
+  fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
+  if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); }
+  memset(&addr, 0, sizeof(addr));
+  addr.sun_family = AF_UNIX;
+  strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
+  if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
+
+    return fail_fatal(fd_socket, out_buf);
+
+  }
+
+  // ask whether the server is alive
+  ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
+  if (!write_all(fd_socket, ctrl_buf, 1)) {
+
+    return fail_fatal(fd_socket, out_buf);
+
+  }
+
+  // see whether the server replies as expected
+  if (!read_all(fd_socket, ctrl_buf, 1) ||
+      ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
+
+    return fail_fatal(fd_socket, out_buf);
+
+  }
+
+  // tell the server what we want to do
+  wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT;
+
+  // perform a crossover if we are splicing
+  if (data->stage_splice_cur > 0) { wanted |= SERVER_CROSSOVER_BIT; }
+
+  // tell the server what we want and how much data will be sent
+  ctrl_buf[0] = wanted;
+  put_uint32(ctrl_buf + 1, (uint32_t)buf_size);
+  if (!write_all(fd_socket, ctrl_buf, 5)) {
+
+    return fail_fatal(fd_socket, out_buf);
+
+  }
+
+  // send the data to mutate and encode
+  if (!write_all(fd_socket, buf, buf_size)) {
+
+    return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+  }
+
+  if (wanted & SERVER_CROSSOVER_BIT) {
+
+    // since we requested crossover, we will first tell how much additional data
+    // is to be expected
+    put_uint32(ctrl_buf, (uint32_t)add_buf_size);
+    if (!write_all(fd_socket, ctrl_buf, 4)) {
+
+      return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+    }
+
+    // send the additional data for crossover
+    if (!write_all(fd_socket, add_buf, add_buf_size)) {
+
+      return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+    }
+
+    // lastly, a seed is required for crossover so send one
+    put_uint64(ctrl_buf, (uint64_t)rand());
+    if (!write_all(fd_socket, ctrl_buf, 8)) {
+
+      return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+    }
+
+  }
+
+  // since we requested mutation, we need to provide a seed for that
+  put_uint64(ctrl_buf, (uint64_t)rand());
+  if (!write_all(fd_socket, ctrl_buf, 8)) {
+
+    return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+  }
+
+  // obtain the required buffer size for the data that will be returned
+  if (!read_all(fd_socket, ctrl_buf, 4)) {
+
+    return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+  }
+
+  size_t new_size = (size_t)to_uint32(ctrl_buf);
+
+  // if the data is too large then we ignore this round
+  if (new_size > max_size) {
+
+    return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+  }
+
+  if (new_size > buf_size) {
+
+    // buf is too small, need to use data->fuzz_buf, let's see whether we need
+    // to reallocate
+    if (new_size > data->fuzz_size) {
+
+      data->fuzz_size = new_size << 1;
+      data->fuzz_buf = (uint8_t *)realloc(data->fuzz_buf, data->fuzz_size);
+
+    }
+
+    *out_buf = data->fuzz_buf;
+
+  } else {
+
+    // new_size fits into buf, so re-use it
+    *out_buf = buf;
+
+  }
+
+  // obtain the encoded data
+  if (!read_all(fd_socket, *out_buf, new_size)) {
+
+    return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+  }
+
+  close(fd_socket);
+  return new_size;
+
+}
+
+/**
+ * A post-processing function to use right before AFL writes the test case to
+ * disk in order to execute the target.
+ *
+ * (Optional) If this functionality is not needed, simply don't define this
+ * function.
+ *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
+ * @param[in] buf Buffer containing the test case to be executed
+ * @param[in] buf_size Size of the test case
+ * @param[out] out_buf Pointer to the buffer containing the test case after
+ *     processing. External library should allocate memory for out_buf.
+ *     The buf pointer may be reused (up to the given buf_size);
+ * @return Size of the output buffer after processing or the needed amount.
+ *     A return of 0 indicates an error.
+ */
+size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf,
+                               size_t buf_size, uint8_t **out_buf) {
+
+  struct sockaddr_un addr;
+  int                fd_socket;
+  uint8_t            ctrl_buf[8];
+
+  // initialize the socket
+  fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
+  if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); }
+  memset(&addr, 0, sizeof(addr));
+  addr.sun_family = AF_UNIX;
+  strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
+  if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
+
+    return fail_fatal(fd_socket, out_buf);
+
+  }
+
+  // ask whether the server is alive
+  ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
+  if (!write_all(fd_socket, ctrl_buf, 1)) {
+
+    return fail_fatal(fd_socket, out_buf);
+
+  }
+
+  // see whether the server replies as expected
+  if (!read_all(fd_socket, ctrl_buf, 1) ||
+      ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
+
+    return fail_fatal(fd_socket, out_buf);
+
+  }
+
+  // tell the server what we want and how much data will be sent
+  ctrl_buf[0] = SERVER_DECODE_BIT;
+  put_uint32(ctrl_buf + 1, (uint32_t)buf_size);
+  if (!write_all(fd_socket, ctrl_buf, 5)) {
+
+    return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+  }
+
+  // send the data to decode
+  if (!write_all(fd_socket, buf, buf_size)) {
+
+    return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+  }
+
+  // obtain the required buffer size for the data that will be returned
+  if (!read_all(fd_socket, ctrl_buf, 4)) {
+
+    return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+  }
+
+  size_t new_size = (size_t)to_uint32(ctrl_buf);
+
+  // need to use data->post_process_buf, let's see whether we need to reallocate
+  if (new_size > data->post_process_size) {
+
+    data->post_process_size = new_size << 1;
+    data->post_process_buf =
+        (uint8_t *)realloc(data->post_process_buf, data->post_process_size);
+
+  }
+
+  *out_buf = data->post_process_buf;
+
+  // obtain the decoded data
+  if (!read_all(fd_socket, *out_buf, new_size)) {
+
+    return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+  }
+
+  close(fd_socket);
+  return new_size;
+
+}
+
+/**
+ * Deinitialize everything
+ *
+ * @param data The data ptr from afl_custom_init
+ */
+void afl_custom_deinit(atnwalk_mutator_t *data) {
+
+  free(data->fuzz_buf);
+  free(data->post_process_buf);
+  free(data);
+
+}
+
diff --git a/custom_mutators/autotokens/Makefile b/custom_mutators/autotokens/Makefile
new file mode 100644
index 00000000..0daba17d
--- /dev/null
+++ b/custom_mutators/autotokens/Makefile
@@ -0,0 +1,26 @@
+ifdef debug
+	CPPLAGS += -fsanitize=address
+	CXXFLAGS += -Wall
+	CC := clang
+	CXX := clang++
+endif
+ifdef DEBUG
+	CPPFLAGS += -fsanitize=address
+	CXXFLAGS += -Wall
+	CC := clang
+	CXX := clang++
+endif
+
+all:	autotokens.so
+
+afl-fuzz-queue.o:	../../src/afl-fuzz-queue.c
+	$(CC) -D_STANDALONE_MODULE=1 -I../../include -g -O3 $(CPPFLAGS) -fPIC -c -o ./afl-fuzz-queue.o ../../src/afl-fuzz-queue.c
+
+afl-common.o:	../../src/afl-common.c
+	$(CC) -I../../include -g -O3 $(CPPFLAGS) -DBIN_PATH=\"dummy\" -Wno-pointer-sign -fPIC -c -o ./afl-common.o ../../src/afl-common.c
+
+autotokens.so:	afl-fuzz-queue.o afl-common.o autotokens.cpp
+	$(CXX) -Wno-deprecated -g -O3 $(CXXFLAGS) $(CPPFLAGS) -shared -fPIC -o autotokens.so -I../../include autotokens.cpp  ./afl-fuzz-queue.o ../../src/afl-performance.o ./afl-common.o
+
+clean:
+	rm -f autotokens.so *.o *~ core
diff --git a/custom_mutators/autotokens/README b/custom_mutators/autotokens/README
new file mode 100644
index 00000000..cca168fd
--- /dev/null
+++ b/custom_mutators/autotokens/README
@@ -0,0 +1,34 @@
+# Autotokens
+
+This implements an improved autotoken grammar fuzzing idea presented in
+[Token-Level Fuzzing][https://www.usenix.org/system/files/sec21-salls.pdf].
+It is a grammar fuzzer without actually knowing the grammar, but only works
+with text based inputs.
+
+It is recommended to run with together in an instance with `CMPLOG`.
+
+If you have a dictionary (`-x`) this improves this custom grammar mutator.
+
+If **not** running with `CMPLOG`, it is possible to set
+`AFL_CUSTOM_MUTATOR_ONLY` to concentrate on grammar bug classes.
+
+Do **not** set `AFL_DISABLE_TRIM` with this custom mutator!
+
+## Configuration via environment variables
+
+`AUTOTOKENS_ONLY_FAV` - only use this mutator on favorite queue items
+`AUTOTOKENS_COMMENT` - what character or string starts a comment which will be
+                       removed. Default: `/* ... */`
+`AUTOTOKENS_FUZZ_COUNT_SHIFT` - reduce the number of fuzzing performed, shifting
+                                the value by this number, e.g. 1.
+`AUTOTOKENS_AUTO_DISABLE` - disable this module if the seeds are not ascii
+                            (or no input and no (ascii) dictionary)
+`AUTOTOKENS_LEARN_DICT` - learn from dictionaries?
+                          0 = none
+                          1 = only -x or autodict
+                          2 = -x, autodict and `CMPLOG`
+`AUTOTOKENS_CHANGE_MIN` - minimum number of mutations (1-256, default 8)
+`AUTOTOKENS_CHANGE_MAX` - maximum number of mutations (1-4096, default 64)
+`AUTOTOKENS_CREATE_FROM_THIN_AIR` - if only one small start file is present and
+                                    a dictionary loaded then create one initial
+                                    structure based on the dictionary.
diff --git a/custom_mutators/autotokens/autotokens.cpp b/custom_mutators/autotokens/autotokens.cpp
new file mode 100644
index 00000000..8135aba1
--- /dev/null
+++ b/custom_mutators/autotokens/autotokens.cpp
@@ -0,0 +1,1101 @@
+/*
+   token level fuzzing custom mutator for afl++
+   (c) by Marc Heuse <mh@mh-sec.de>
+   License: Apache 2.0
+*/
+
+extern "C" {
+
+#include "afl-fuzz.h"
+
+}
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <iostream>
+#include <fstream>
+#include <unordered_map>
+#include <vector>
+#include <regex>
+
+#define AUTOTOKENS_DEBUG 0
+#define AUTOTOKENS_ONLY_FAV 0
+#define AUTOTOKENS_CHANGE_MIN 8
+#define AUTOTOKENS_CHANGE_MAX 64
+#define AUTOTOKENS_SIZE_MIN 8
+#define AUTOTOKENS_SIZE_MAX 65535
+#define AUTOTOKENS_SPLICE_MIN 4
+#define AUTOTOKENS_SPLICE_MAX 64
+#define AUTOTOKENS_CREATE_FROM_THIN_AIR 0
+#define AUTOTOKENS_FUZZ_COUNT_SHIFT 0
+#define AUTOTOKENS_AUTO_DISABLE 0
+// 0 = no learning, 1 only from -x dict/autodict, 2 also from cmplog
+#define AUTOTOKENS_LEARN_DICT 1
+#ifndef AUTOTOKENS_SPLICE_DISABLE
+  #define AUTOTOKENS_SPLICE_DISABLE 0
+#endif
+#ifndef AFL_TXT_MAX_LEN
+  #define AFL_TXT_MAX_LEN 65535
+#endif
+
+#if AUTOTOKENS_SPLICE_MIN >= AUTOTOKENS_SIZE_MIN
+  #error SPLICE_MIN must be lower than SIZE_MIN
+#endif
+
+using namespace std;
+
+typedef struct my_mutator {
+
+  afl_state *afl;
+
+} my_mutator_t;
+
+#undef DEBUGF
+#define DEBUGF \
+  if (unlikely(debug)) fprintf
+#define IFDEBUG if (unlikely(debug))
+
+static afl_state *afl_ptr;
+static int        module_disabled = 0;
+static int        auto_disable = AUTOTOKENS_AUTO_DISABLE;
+static int        debug = AUTOTOKENS_DEBUG;
+static int        only_fav = AUTOTOKENS_ONLY_FAV;
+static int        learn_dictionary_tokens = AUTOTOKENS_LEARN_DICT;
+static int        fuzz_count_shift = AUTOTOKENS_FUZZ_COUNT_SHIFT;
+static int        create_from_thin_air = AUTOTOKENS_CREATE_FROM_THIN_AIR;
+static int        change_min = AUTOTOKENS_CHANGE_MIN;
+static int        change_max = AUTOTOKENS_CHANGE_MAX;
+static u32        current_id;
+static u32        valid_structures;
+static u32        whitespace_ids;
+static u32        extras_cnt, a_extras_cnt;
+static u64        all_spaces, all_tabs, all_lf, all_ws;
+static u64        all_structure_items;
+static u64        fuzz_count;
+static unordered_map<string, vector<u32> *> file_mapping;
+static unordered_map<u32, vector<u32> *>    id_mapping;
+static unordered_map<string, u32>           token_to_id;
+static unordered_map<u32, string>           id_to_token;
+static string                               output;
+static regex                               *regex_comment_custom;
+// multiline requires g++-11 libs :(
+static regex regex_comment_star(
+    "/\\*([:print:]|\n)*?\\*/",
+    regex_constants::optimize /* | regex_constants::multiline */);
+static regex        regex_word("[A-Za-z0-9_$.-]+", regex::optimize);
+static regex        regex_whitespace(R"([ \t]+)", regex::optimize);
+static vector<u32> *s;  // the structure of the currently selected input
+
+// FUNCTIONS
+
+/* This function is called once after everything is set up but before
+   any fuzzing attempt has been performed.
+   This is called in afl_custom_queue_get() */
+static void first_run(void *data) {
+
+  (void)(data);
+
+  /* For auto-loading this module we check here if we can analyze from the
+     input if the inputs look like text inputs and disable the module if
+     not. */
+
+  if (afl_ptr->custom_only || !auto_disable) { return; }
+
+  if (unlikely(afl_ptr->active_items == 1 &&
+               afl_ptr->queue_cur->len < AFL_TXT_MIN_LEN)) {
+
+    if (afl_ptr->extras_cnt > 8) {
+
+      u32 valid = 0;
+
+      while (extras_cnt < afl_ptr->extras_cnt) {
+
+        u32 ok = 1, l = afl_ptr->extras[extras_cnt].len;
+        u8 *buf, *ptr = afl_ptr->extras[extras_cnt].data;
+
+        for (u32 i = 0; i < l; ++i) {
+
+          if (!isascii((int)ptr[i]) && !isprint((int)ptr[i])) {
+
+            ok = 0;
+            break;
+
+          }
+
+        }
+
+        if (ok) {
+
+          buf = (u8 *)malloc(afl_ptr->extras[extras_cnt].len + 1);
+          memcpy(buf, afl_ptr->extras[extras_cnt].data,
+                 afl_ptr->extras[extras_cnt].len);
+          buf[afl_ptr->extras[extras_cnt].len] = 0;
+          token_to_id[(char *)buf] = current_id;
+          id_to_token[current_id] = (char *)buf;
+          ++current_id;
+          ++valid;
+
+        }
+
+        ++extras_cnt;
+
+      }
+
+      if ((valid * 100) / afl_ptr->extras_cnt <= 70) { module_disabled = 1; }
+
+      DEBUGF(stderr, "DICT: total %u, valid %u, %u <= 70 == disable\n",
+             afl_ptr->extras_cnt, valid,
+             (u32)((valid * 100) / afl_ptr->extras_cnt));
+
+    } else {
+
+      module_disabled = 1;
+
+    }
+
+    return;
+
+  }
+
+  u32 is_ascii = 0, valid = 0;
+
+  for (u32 i = 0; i < afl_ptr->queued_items; ++i) {
+
+    struct queue_entry *q;
+
+    q = afl_ptr->queue_buf[i];
+
+    if (!q->disabled && q->len >= AUTOTOKENS_SIZE_MIN &&
+        q->len <= AFL_TXT_MAX_LEN) {
+
+      ++valid;
+      u8 *input = queue_testcase_get(afl_ptr, q);
+
+      u32 valid_chars = 0;
+      for (u32 i = 0; i < q->len; ++i) {
+
+        if (isascii((int)input[i]) || isprint((int)input[i])) { ++valid_chars; }
+
+      }
+
+      // we want at least 99% of text characters ...
+      if (((q->len * AFL_TXT_MIN_PERCENT) / 100) <= valid_chars) {
+
+        ++is_ascii;
+        q->is_ascii = 1;
+
+      }
+
+    }
+
+  }
+
+  if ((is_ascii * 100) / valid <= 70) { module_disabled = 1; }
+
+  DEBUGF(stderr, "seeds: total %u, valid %u, ascii %u, %u <= 70 == disabled\n",
+         afl_ptr->active_items, valid, is_ascii,
+         (u32)((is_ascii * 100) / valid));
+
+}
+
+static u32 good_whitespace_or_singleval() {
+
+  u32 i = rand_below(afl_ptr, current_id);
+  if (id_to_token[i].size() == 1) { return i; }
+  i = rand_below(afl_ptr, all_ws);
+  if (i < all_spaces) {
+
+    return 0;
+
+  } else if (i < all_tabs) {
+
+    return 1;
+
+  } else
+
+    return 2;  // linefeed
+
+}
+
+extern "C" u32 afl_custom_fuzz_count(void *data, const u8 *buf,
+                                     size_t buf_size) {
+
+  (void)(data);
+
+  if (s == NULL) return 0;
+
+  u32 shift = unlikely(afl_ptr->custom_only) ? 7 : 8;
+  u32 stage_max = (u32)((HAVOC_CYCLES * afl_ptr->queue_cur->perf_score) /
+                        afl_ptr->havoc_div) >>
+                  shift;
+  if (fuzz_count_shift) { stage_max >>= (u32)fuzz_count_shift; };
+  DEBUGF(stderr, "fuzz count: %u\n", stage_max);
+
+  return stage_max;
+
+}
+
+extern "C" size_t afl_custom_fuzz(my_mutator_t *data, u8 *buf, size_t buf_size,
+                                  u8 **out_buf, u8 *add_buf,
+                                  size_t add_buf_size, size_t max_size) {
+
+  (void)(data);
+
+  if (unlikely(s == NULL)) {
+
+    *out_buf = NULL;
+    return 0;
+
+  }
+
+  vector<u32> m = *s;  // copy of the structure we will modify
+  u32         i, m_size = (u32)m.size();
+
+  u32 rounds =
+      MIN(change_max,
+          MAX(change_min,
+              MIN(m_size >> 3, HAVOC_CYCLES * afl_ptr->queue_cur->perf_score *
+                                   afl_ptr->havoc_div / 256)));
+  // DEBUGF(stderr, "structure size: %lu, rounds: %u \n", m.size(), rounds);
+
+#if AUTOTOKENS_SPLICE_DISABLE == 1
+  #define AUTOTOKENS_MUT_MAX 18
+#else
+  #define AUTOTOKENS_MUT_MAX 27
+#endif
+
+  u32 max_rand = AUTOTOKENS_MUT_MAX, new_item, pos;
+
+  for (i = 0; i < rounds; ++i) {
+
+    switch (rand_below(afl_ptr, max_rand)) {
+
+      /* CHANGE/MUTATE single item */
+      case 0 ... 9: {
+
+        pos = rand_below(afl_ptr, m_size);
+        u32 cur_item = m[pos];
+        do {
+
+          new_item = rand_below(afl_ptr, current_id);
+
+        } while (unlikely(
+
+            new_item == cur_item ||
+            ((whitespace_ids < new_item && whitespace_ids >= cur_item) ||
+             (whitespace_ids >= new_item && whitespace_ids < cur_item))));
+
+        // DEBUGF(stderr, "MUT: %u -> %u\n", cur_item, new_item);
+        m[pos] = new_item;
+        break;
+
+      }
+
+      /* INSERT (m_size +1 so we insert also after last place) */
+      case 10 ... 13: {
+
+        do {
+
+          new_item = rand_below(afl_ptr, current_id);
+
+        } while (unlikely(new_item >= whitespace_ids));
+
+        u32 pos = rand_below(afl_ptr, m_size + 1);
+        m.insert(m.begin() + pos, new_item);
+        ++m_size;
+        // DEBUGF(stderr, "INS: %u at %u\n", new_item, pos);
+
+        break;
+
+      }
+
+#if AUTOTOKENS_SPLICE_DISABLE != 1
+      /* SPLICING */
+      case 14 ... 22: {
+
+        u32  strategy = rand_below(afl_ptr, 4), dst_off, n;
+        auto src = id_mapping[rand_below(afl_ptr, valid_structures)];
+        u32  src_size = src->size();
+        u32  src_off = rand_below(afl_ptr, src_size - AUTOTOKENS_SPLICE_MIN);
+        u32  rand_r = 1 + MAX(AUTOTOKENS_SPLICE_MIN,
+                              MIN(AUTOTOKENS_SPLICE_MAX, src_size - src_off));
+
+        switch (strategy) {
+
+          // insert
+          case 0: {
+
+            dst_off = rand_below(afl_ptr, m_size);
+            n = AUTOTOKENS_SPLICE_MIN +
+                rand_below(afl_ptr, MIN(AUTOTOKENS_SPLICE_MAX,
+                                        rand_r - AUTOTOKENS_SPLICE_MIN));
+            m.insert(m.begin() + dst_off, src->begin() + src_off,
+                     src->begin() + src_off + n);
+            m_size += n;
+            // DEBUGF(stderr, "SPLICE-INS: %u at %u\n", n, dst_off);
+
+            break;
+
+          }
+
+          // overwrite
+          default: {
+
+            dst_off = rand_below(afl_ptr, m_size - AUTOTOKENS_SPLICE_MIN);
+            n = AUTOTOKENS_SPLICE_MIN +
+                rand_below(
+                    afl_ptr,
+                    MIN(AUTOTOKENS_SPLICE_MAX - AUTOTOKENS_SPLICE_MIN,
+                        MIN(m_size - dst_off - AUTOTOKENS_SPLICE_MIN,
+                            src_size - src_off - AUTOTOKENS_SPLICE_MIN)));
+
+            copy(src->begin() + src_off, src->begin() + src_off + n,
+                 m.begin() + dst_off);
+
+            // DEBUGF(stderr, "SPLICE-MUT: %u at %u\n", n, dst_off);
+            break;
+
+          }
+
+        }
+
+        break;
+
+      }
+
+#endif
+
+      /* ERASE - only if large enough */
+      default: {
+
+        if (m_size > 8) {
+
+          do {
+
+            pos = rand_below(afl_ptr, m_size);
+
+          } while (unlikely(m[pos] < whitespace_ids));
+
+          m.erase(m.begin() + pos);
+          --m_size;
+
+        } else {
+
+          // if the data is already too small do not try to make it smaller
+          // again this run.
+
+          max_rand -= 4;
+
+        }
+
+        break;
+
+      }
+
+    }
+
+  }
+
+  /* Now we create the output */
+
+  output = "";
+  u32 prev_size = 1, was_whitespace = 1;
+
+  for (i = 0; i < m_size; ++i) {
+
+    if (likely(i + 1 < m_size)) {
+
+      u32 this_size = id_to_token[m[i]].size();
+      u32 is_whitespace = m[i] < whitespace_ids;
+
+      /* The output we are generating might need repairing.
+         General rule: two items that have a size larger than 2 are strings
+         or identifizers and need a whitespace or an item of length 1 in
+         between. */
+      if (unlikely(!(prev_size == 1 || was_whitespace || this_size == 1 ||
+                     is_whitespace))) {
+
+        output += id_to_token[good_whitespace_or_singleval()];
+
+      }
+
+      prev_size = this_size;
+      was_whitespace = is_whitespace;
+
+    }
+
+    output += id_to_token[m[i]];
+
+  }
+
+  u32 mutated_size = (u32)output.size();
+  u8 *mutated_out = (u8 *)output.data();
+
+  if (unlikely(mutated_size > max_size)) { mutated_size = max_size; }
+
+  /*
+  IFDEBUG {
+
+    DEBUGF(stderr, "MUTATED to %u bytes:\n", mutated_size);
+    fwrite(output.data(), 1, mutated_size, stderr);
+    DEBUGF(stderr, "\n---\n");
+
+  }
+
+  */
+
+  *out_buf = mutated_out;
+  ++fuzz_count;
+  return mutated_size;
+
+}
+
+/* I get f*cking stack overflow using C++ regex with a regex of
+   "\"[[:print:]]*?\"" if this matches a long string even with regex::optimize
+   enabled :-( */
+static u8 my_search_string(string::const_iterator  cur,
+                           string::const_iterator  ende,
+                           string::const_iterator *match_begin,
+                           string::const_iterator *match_end) {
+
+  string::const_iterator start = cur, found_begin;
+  u8                     quote_type = 0;
+
+  while (cur < ende) {
+
+    switch (*cur) {
+
+      case '"': {
+
+        if (cur == start || *(cur - 1) != '\\') {
+
+          if (!quote_type) {
+
+            found_begin = cur;
+            quote_type = 1;
+
+          } else if (quote_type == 1) {
+
+            *match_begin = found_begin;
+            *match_end = cur + 1;
+            return 1;
+
+          }
+
+        }
+
+        break;
+
+      }
+
+      case '\'': {
+
+        if (cur == start || *(cur - 1) != '\\') {
+
+          if (!quote_type) {
+
+            found_begin = cur;
+            quote_type = 2;
+
+          } else if (quote_type == 2) {
+
+            *match_begin = found_begin;
+            *match_end = cur + 1;
+            return 1;
+
+          }
+
+        }
+
+        break;
+
+      }
+
+      case '\n':
+      case '\r':
+      case 0: {
+
+        quote_type = 0;
+        break;
+
+      }
+
+      default:
+        if (unlikely(quote_type && !isprint(*cur))) { quote_type = 0; }
+        break;
+
+    }
+
+    ++cur;
+
+  }
+
+  return 0;
+
+}
+
+/* We are not using afl_custom_queue_new_entry() because not every corpus entry
+   will be necessarily fuzzed with this custom mutator.
+   So we use afl_custom_queue_get() instead. */
+
+extern "C" unsigned char afl_custom_queue_get(void                *data,
+                                              const unsigned char *filename) {
+
+  static int learn_state = 0;
+  static int is_first_run = 1;
+  (void)(data);
+
+  if (unlikely(is_first_run)) {
+
+    is_first_run = 0;
+    first_run(data);
+
+    if (module_disabled) {
+
+      WARNF("Autotokens custom module is disabled.");
+
+    } else if (auto_disable) {
+
+      OKF("Autotokens custom module is enabled.");
+
+    }
+
+  }
+
+  if (likely(module_disabled) ||
+      (unlikely(!afl_ptr->custom_only) && !create_from_thin_air &&
+       ((afl_ptr->shm.cmplog_mode && !afl_ptr->queue_cur->is_ascii) ||
+        (only_fav && !afl_ptr->queue_cur->favored)))) {
+
+    s = NULL;
+    DEBUGF(stderr,
+           "cmplog not ascii or only_fav and not favorite or disabled\n");
+    return 1;
+
+  }
+
+  // check if there are new dictionary entries and add them to the tokens
+  if (unlikely(learn_state < learn_dictionary_tokens) &&
+      likely(valid_structures || create_from_thin_air)) {
+
+    if (unlikely(!learn_state)) { learn_state = 1; }
+
+    while (extras_cnt < afl_ptr->extras_cnt) {
+
+      u32 ok = 1, l = afl_ptr->extras[extras_cnt].len;
+      u8 *buf, *ptr = afl_ptr->extras[extras_cnt].data;
+
+      for (u32 i = 0; i < l; ++i) {
+
+        if (!isascii((int)ptr[i]) && !isprint((int)ptr[i])) {
+
+          ok = 0;
+          break;
+
+        }
+
+      }
+
+      if (ok) {
+
+        buf = (u8 *)malloc(afl_ptr->extras[extras_cnt].len + 1);
+        memcpy(buf, afl_ptr->extras[extras_cnt].data,
+               afl_ptr->extras[extras_cnt].len);
+        buf[afl_ptr->extras[extras_cnt].len] = 0;
+        token_to_id[(char *)buf] = current_id;
+        id_to_token[current_id] = (char *)buf;
+        ++current_id;
+
+      }
+
+      ++extras_cnt;
+
+    }
+
+    while (a_extras_cnt < afl_ptr->a_extras_cnt) {
+
+      u32 ok = 1, l = afl_ptr->a_extras[a_extras_cnt].len;
+      u8 *ptr = afl_ptr->a_extras[a_extras_cnt].data;
+
+      for (u32 i = 0; i < l; ++i) {
+
+        if (!isascii((int)ptr[i]) && !isprint((int)ptr[i])) {
+
+          ok = 0;
+          break;
+
+        }
+
+      }
+
+      if (ok) {
+
+        token_to_id[(char *)ptr] = current_id;
+        id_to_token[current_id] = (char *)ptr;
+        ++current_id;
+
+      }
+
+      ++a_extras_cnt;
+
+    }
+
+  }
+
+  vector<u32> *structure = NULL;
+  string       fn = (char *)filename;
+  auto         entry = file_mapping.find(fn);
+
+  // if there is only one active queue item at start and it is very small
+  // the we create once a structure randomly.
+  if (unlikely(create_from_thin_air)) {
+
+    if (current_id > whitespace_ids + 6 && afl_ptr->active_items == 1 &&
+        afl_ptr->queue_cur->len < AFL_TXT_MIN_LEN) {
+
+      DEBUGF(stderr, "Creating an entry from thin air...\n");
+      structure = new vector<u32>();
+      u32 item, prev, cnt = current_id >> 1;
+      structure->reserve(cnt + 4);
+      for (u32 i = 0; i < cnt; i++) {
+
+        item = rand_below(afl_ptr, current_id);
+        if (i && id_to_token[item].length() > 1 &&
+            id_to_token[prev].length() > 1) {
+
+          structure->push_back(good_whitespace_or_singleval());
+
+        }
+
+        structure->push_back(item);
+        prev = item;
+
+      }
+
+      s = structure;
+      file_mapping[fn] = structure;
+      id_mapping[valid_structures] = structure;
+      ++valid_structures;
+      all_structure_items += structure->size();
+
+      return 1;
+
+    }
+
+    create_from_thin_air = 0;
+
+  }
+
+  if (entry == file_mapping.end()) {
+
+    // this input file was not analyzed for tokens yet, so let's do it!
+    size_t len = afl_ptr->queue_cur->len;
+
+    if (len < AFL_TXT_MIN_LEN) {
+
+      file_mapping[fn] = structure;  // NULL ptr so we don't read the file again
+      s = NULL;
+      DEBUGF(stderr, "Too short (%lu) %s\n", len, filename);
+      return 1;
+
+    } else if (len > AFL_TXT_MAX_LEN) {
+
+      file_mapping[fn] = structure;  // NULL ptr so we don't read the file again
+      s = NULL;
+      DEBUGF(stderr, "Too long (%lu) %s\n", len, filename);
+      return 1;
+
+    }
+
+    u8    *input_buf = queue_testcase_get(afl_ptr, afl_ptr->queue_cur);
+    string input((char *)input_buf, afl_ptr->queue_cur->len);
+
+    if (!afl_ptr->shm.cmplog_mode) {
+
+      // not running with CMPLOG? bad choice, but whatever ...
+      // we only want text inputs, so we have to check it ourselves.
+
+      u32 valid_chars = 0;
+      for (u32 i = 0; i < len; ++i) {
+
+        if (isascii((int)input[i]) || isprint((int)input[i])) { ++valid_chars; }
+
+      }
+
+      // we want at least 95% of text characters ...
+      if (((len * AFL_TXT_MIN_PERCENT) / 100) > valid_chars) {
+
+        file_mapping[fn] = NULL;
+        s = NULL;
+        DEBUGF(stderr, "Not text (%lu) %s\n", len, filename);
+        return 1;
+
+      }
+
+    }
+
+    // DEBUGF(stderr, "Read %lu bytes for %s\nBefore comment trim:\n%s\n",
+    // input.size(), filename, input.c_str());
+
+    if (regex_comment_custom) {
+
+      input = regex_replace(input, *regex_comment_custom, "$2");
+
+    } else {
+
+      input = regex_replace(input, regex_comment_star, "");
+
+    }
+
+    DEBUGF(stderr, "After replace %lu bytes for %s\n%s\n", input.size(),
+           filename, input.c_str());
+
+    u32  spaces = count(input.begin(), input.end(), ' ');
+    u32  tabs = count(input.begin(), input.end(), '\t');
+    u32  linefeeds = count(input.begin(), input.end(), '\n');
+    bool ends_with_linefeed = input[input.length() - 1] == '\n';
+
+    DEBUGF(stderr, "spaces=%u tabs=%u linefeeds=%u ends=%u\n", spaces, tabs,
+           linefeeds, ends_with_linefeed);
+
+    all_spaces += spaces;
+    all_tabs += tabs;
+    all_lf += linefeeds;
+    all_ws = all_spaces + all_tabs + all_lf;
+
+    // now extract all tokens
+    vector<string>         tokens;
+    string::const_iterator cur = input.begin(), ende = input.end(), found, prev,
+                           match_begin, match_end;
+
+    DEBUGF(stderr, "START!\n");
+
+    while (my_search_string(cur, ende, &match_begin, &match_end)) {
+
+      prev = cur;
+      found = match_begin;
+      cur = match_end;
+
+      IFDEBUG {
+
+        string foo(match_begin, match_end);
+        DEBUGF(stderr,
+               "string %s found at start %lu offset %lu continue at %lu\n",
+               foo.c_str(), prev - input.begin(), found - prev,
+               cur - input.begin());
+
+      }
+
+      if (prev < found) {  // there are items between search start and find
+        while (prev < found) {
+
+          if (isspace(*prev)) {
+
+            auto start = prev;
+            while (isspace(*prev)) {
+
+              ++prev;
+
+            }
+
+            tokens.push_back(std::string(start, prev));
+            DEBUGF(stderr, "WHITESPACE %ld \"%s\"\n", prev - start,
+                   tokens[tokens.size() - 1].c_str());
+
+          } else if (isalnum(*prev) || *prev == '$' || *prev == '_') {
+
+            auto start = prev;
+            while (isalnum(*prev) || *prev == '$' || *prev == '_' ||
+                   *prev == '.' || *prev == '/') {
+
+              ++prev;
+
+            }
+
+            tokens.push_back(string(start, prev));
+            DEBUGF(stderr, "IDENTIFIER %ld \"%s\"\n", prev - start,
+                   tokens[tokens.size() - 1].c_str());
+
+          } else {
+
+            tokens.push_back(string(prev, prev + 1));
+            DEBUGF(stderr, "OTHER \"%c\"\n", *prev);
+            ++prev;
+
+          }
+
+        }
+
+      }
+
+      tokens.push_back(string(match_begin, match_end));
+      DEBUGF(stderr, "TOK: %s\n", tokens[tokens.size() - 1].c_str());
+
+    }
+
+    DEBUGF(stderr, "AFTER all strings\n");
+
+    if (cur < ende) {
+
+      while (cur < ende) {
+
+        if (isspace(*cur)) {
+
+          auto start = cur;
+          while (isspace(*cur)) {
+
+            ++cur;
+
+          }
+
+          tokens.push_back(std::string(start, cur));
+          DEBUGF(stderr, "WHITESPACE %ld \"%s\"\n", cur - start,
+                 tokens[tokens.size() - 1].c_str());
+
+        } else if (isalnum(*cur) || *cur == '$' || *cur == '_') {
+
+          auto start = cur;
+          while (isalnum(*cur) || *cur == '$' || *cur == '_' || *cur == '.' ||
+                 *cur == '/') {
+
+            ++cur;
+
+          }
+
+          tokens.push_back(std::string(start, cur));
+          DEBUGF(stderr, "IDENTIFIER %ld \"%s\"\n", cur - start,
+                 tokens[tokens.size() - 1].c_str());
+
+        } else {
+
+          tokens.push_back(std::string(cur, cur + 1));
+          DEBUGF(stderr, "OTHER \"%c\"\n", *cur);
+          ++cur;
+
+        }
+
+      }
+
+    }
+
+    IFDEBUG {
+
+      DEBUGF(stderr, "DUMPING TOKENS:\n");
+      for (u32 i = 0; i < tokens.size(); ++i) {
+
+        DEBUGF(stderr, "%s", tokens[i].c_str());
+
+      }
+
+      DEBUGF(stderr, "---------------------------\n");
+
+    }
+
+    if (tokens.size() < AUTOTOKENS_SIZE_MIN) {
+
+      file_mapping[fn] = NULL;
+      s = NULL;
+      DEBUGF(stderr, "too few tokens\n");
+      return 1;
+
+    }
+
+    /* Now we transform the tokens into an ID list and saved that */
+
+    structure = new vector<u32>();
+    u32 id;
+
+    for (u32 i = 0; i < tokens.size(); ++i) {
+
+      if ((id = token_to_id[tokens[i]]) == 0) {
+
+        // First time we see this token, add it to the list
+        token_to_id[tokens[i]] = current_id;
+        id_to_token[current_id] = tokens[i];
+        structure->push_back(current_id);
+        ++current_id;
+
+      } else {
+
+        structure->push_back(id);
+
+      }
+
+    }
+
+    // save the token structure to the file mapping
+    file_mapping[fn] = structure;
+    id_mapping[valid_structures] = structure;
+    ++valid_structures;
+    s = structure;
+    all_structure_items += structure->size();
+
+    // we are done!
+    DEBUGF(stderr, "DONE! We have %lu tokens in the structure\n",
+           structure->size());
+
+  } else {
+
+    if (entry->second == NULL) {
+
+      DEBUGF(stderr, "Skipping %s\n", filename);
+      s = NULL;
+      return 1;
+
+    }
+
+    s = entry->second;
+    DEBUGF(stderr, "OK %s\n", filename);
+
+  }
+
+  return 1;  // we always fuzz unless non-ascii or too small
+
+}
+
+extern "C" my_mutator_t *afl_custom_init(afl_state *afl, unsigned int seed) {
+
+  (void)(seed);
+  my_mutator_t *data = (my_mutator_t *)calloc(1, sizeof(my_mutator_t));
+  if (!data) {
+
+    perror("afl_custom_init alloc");
+    return NULL;
+
+  }
+
+  if (getenv("AUTOTOKENS_DEBUG")) { debug = 1; }
+  if (getenv("AUTOTOKENS_AUTO_DISABLE")) { auto_disable = 1; }
+  if (getenv("AUTOTOKENS_ONLY_FAV")) { only_fav = 1; }
+  if (getenv("AUTOTOKENS_CREATE_FROM_THIN_AIR")) { create_from_thin_air = 1; }
+
+  if (getenv("AUTOTOKENS_LEARN_DICT")) {
+
+    learn_dictionary_tokens = atoi(getenv("AUTOTOKENS_LEARN_DICT"));
+    if (learn_dictionary_tokens < 0 || learn_dictionary_tokens > 2) {
+
+      learn_dictionary_tokens = AUTOTOKENS_LEARN_DICT;
+
+    }
+
+  }
+
+  if (getenv("AUTOTOKENS_FUZZ_COUNT_SHIFT")) {
+
+    fuzz_count_shift = atoi(getenv("AUTOTOKENS_FUZZ_COUNT_SHIFT"));
+    if (fuzz_count_shift < 0 || fuzz_count_shift > 16) { fuzz_count_shift = 0; }
+
+  }
+
+  if (getenv("AUTOTOKENS_CHANGE_MIN")) {
+
+    change_min = atoi(getenv("AUTOTOKENS_CHANGE_MIN"));
+    if (change_min < 1 || change_min > 256) {
+
+      change_min = AUTOTOKENS_CHANGE_MIN;
+
+    }
+
+  }
+
+  if (getenv("AUTOTOKENS_CHANGE_MAX")) {
+
+    change_max = atoi(getenv("AUTOTOKENS_CHANGE_MAX"));
+    if (change_max < 1 || change_max > 4096) {
+
+      change_max = AUTOTOKENS_CHANGE_MAX;
+
+    }
+
+  }
+
+  if (change_max < change_min) { change_max = change_min + 1; }
+
+  if (getenv("AUTOTOKENS_COMMENT")) {
+
+    char buf[256];
+    snprintf(buf, sizeof(buf), "(%s.*)([\r\n]?)", getenv("AUTOTOKENS_COMMENT"));
+    regex_comment_custom = new regex(buf, regex::optimize);
+
+  }
+
+  data->afl = afl_ptr = afl;
+
+  // set common whitespace tokens
+  // we deliberately do not put uncommon ones here to these will count as
+  // identifier tokens.
+  token_to_id[" "] = current_id;
+  id_to_token[current_id] = " ";
+  ++current_id;
+  token_to_id["\t"] = current_id;
+  id_to_token[current_id] = "\t";
+  ++current_id;
+  token_to_id["\n"] = current_id;
+  id_to_token[current_id] = "\n";
+  ++current_id;
+  token_to_id["\r\n"] = current_id;
+  id_to_token[current_id] = "\r\n";
+  ++current_id;
+  token_to_id[" \n"] = current_id;
+  id_to_token[current_id] = " \n";
+  ++current_id;
+  token_to_id["  "] = current_id;
+  id_to_token[current_id] = "  ";
+  ++current_id;
+  token_to_id["\t\t"] = current_id;
+  id_to_token[current_id] = "\t\t";
+  ++current_id;
+  token_to_id["\n\n"] = current_id;
+  id_to_token[current_id] = "\n\n";
+  ++current_id;
+  token_to_id["\r\n\r\n"] = current_id;
+  id_to_token[current_id] = "\r\n\r\n";
+  ++current_id;
+  token_to_id["    "] = current_id;
+  id_to_token[current_id] = "    ";
+  ++current_id;
+  token_to_id["\t\t\t\t"] = current_id;
+  id_to_token[current_id] = "\t\t\t\t";
+  ++current_id;
+  token_to_id["\n\n\n\n"] = current_id;
+  id_to_token[current_id] = "\n\n\n\n";
+  ++current_id;
+  whitespace_ids = current_id;
+  token_to_id["\""] = current_id;
+  id_to_token[current_id] = "\"";
+  ++current_id;
+  token_to_id["'"] = current_id;
+  id_to_token[current_id] = "'";
+  ++current_id;
+
+  return data;
+
+}
+
+extern "C" void afl_custom_splice_optout(my_mutator_t *data) {
+
+  (void)(data);
+
+}
+
+extern "C" void afl_custom_deinit(my_mutator_t *data) {
+
+  /* we use this to print statistics at exit :-)
+     needs to be stderr as stdout is filtered */
+
+  if (module_disabled) { return; }
+
+  fprintf(stderr,
+          "\n\nAutotoken mutator statistics:\n"
+          "  Number of all seen tokens:  %u\n"
+          "  Number of input structures: %u\n"
+          "  Number of all items in structures: %llu\n"
+          "  Number of total fuzzes: %llu\n\n",
+          current_id - 1, valid_structures, all_structure_items, fuzz_count);
+
+  free(data);
+
+}
+
diff --git a/custom_mutators/examples/custom_mutator_helpers.h b/custom_mutators/examples/custom_mutator_helpers.h
deleted file mode 100644
index 62e6efba..00000000
--- a/custom_mutators/examples/custom_mutator_helpers.h
+++ /dev/null
@@ -1,342 +0,0 @@
-#ifndef CUSTOM_MUTATOR_HELPERS
-#define CUSTOM_MUTATOR_HELPERS
-
-#include "config.h"
-#include "types.h"
-#include <stdlib.h>
-
-#define INITIAL_GROWTH_SIZE (64)
-
-#define RAND_BELOW(limit) (rand() % (limit))
-
-/* Use in a struct: creates a name_buf and a name_size variable. */
-#define BUF_VAR(type, name) \
-  type * name##_buf;        \
-  size_t name##_size;
-/* this fills in `&structptr->something_buf, &structptr->something_size`. */
-#define BUF_PARAMS(struct, name) \
-  (void **)&struct->name##_buf, &struct->name##_size
-
-typedef struct {
-
-} afl_t;
-
-static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
-
-  static s8  interesting_8[] = {INTERESTING_8};
-  static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
-  static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
-
-  switch (RAND_BELOW(12)) {
-
-    case 0: {
-
-      /* Flip a single bit somewhere. Spooky! */
-
-      s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8);
-
-      out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7);
-
-      break;
-
-    }
-
-    case 1: {
-
-      /* Set byte to interesting value. */
-
-      u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))];
-      out_buf[(RAND_BELOW(end - begin) + begin)] = val;
-
-      break;
-
-    }
-
-    case 2: {
-
-      /* Set word to interesting value, randomly choosing endian. */
-
-      if (end - begin < 2) break;
-
-      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
-      if (byte_idx >= end - 1) break;
-
-      switch (RAND_BELOW(2)) {
-
-        case 0:
-          *(u16 *)(out_buf + byte_idx) =
-              interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)];
-          break;
-        case 1:
-          *(u16 *)(out_buf + byte_idx) =
-              SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]);
-          break;
-
-      }
-
-      break;
-
-    }
-
-    case 3: {
-
-      /* Set dword to interesting value, randomly choosing endian. */
-
-      if (end - begin < 4) break;
-
-      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
-      if (byte_idx >= end - 3) break;
-
-      switch (RAND_BELOW(2)) {
-
-        case 0:
-          *(u32 *)(out_buf + byte_idx) =
-              interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
-          break;
-        case 1:
-          *(u32 *)(out_buf + byte_idx) =
-              SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
-          break;
-
-      }
-
-      break;
-
-    }
-
-    case 4: {
-
-      /* Set qword to interesting value, randomly choosing endian. */
-
-      if (end - begin < 8) break;
-
-      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
-      if (byte_idx >= end - 7) break;
-
-      switch (RAND_BELOW(2)) {
-
-        case 0:
-          *(u64 *)(out_buf + byte_idx) =
-              (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
-          break;
-        case 1:
-          *(u64 *)(out_buf + byte_idx) = SWAP64(
-              (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
-          break;
-
-      }
-
-      break;
-
-    }
-
-    case 5: {
-
-      /* Randomly subtract from byte. */
-
-      out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX);
-
-      break;
-
-    }
-
-    case 6: {
-
-      /* Randomly add to byte. */
-
-      out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX);
-
-      break;
-
-    }
-
-    case 7: {
-
-      /* Randomly subtract from word, random endian. */
-
-      if (end - begin < 2) break;
-
-      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
-      if (byte_idx >= end - 1) break;
-
-      if (RAND_BELOW(2)) {
-
-        *(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
-
-      } else {
-
-        u16 num = 1 + RAND_BELOW(ARITH_MAX);
-
-        *(u16 *)(out_buf + byte_idx) =
-            SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num);
-
-      }
-
-      break;
-
-    }
-
-    case 8: {
-
-      /* Randomly add to word, random endian. */
-
-      if (end - begin < 2) break;
-
-      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
-      if (byte_idx >= end - 1) break;
-
-      if (RAND_BELOW(2)) {
-
-        *(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
-
-      } else {
-
-        u16 num = 1 + RAND_BELOW(ARITH_MAX);
-
-        *(u16 *)(out_buf + byte_idx) =
-            SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num);
-
-      }
-
-      break;
-
-    }
-
-    case 9: {
-
-      /* Randomly subtract from dword, random endian. */
-
-      if (end - begin < 4) break;
-
-      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
-      if (byte_idx >= end - 3) break;
-
-      if (RAND_BELOW(2)) {
-
-        *(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
-
-      } else {
-
-        u32 num = 1 + RAND_BELOW(ARITH_MAX);
-
-        *(u32 *)(out_buf + byte_idx) =
-            SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num);
-
-      }
-
-      break;
-
-    }
-
-    case 10: {
-
-      /* Randomly add to dword, random endian. */
-
-      if (end - begin < 4) break;
-
-      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
-      if (byte_idx >= end - 3) break;
-
-      if (RAND_BELOW(2)) {
-
-        *(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
-
-      } else {
-
-        u32 num = 1 + RAND_BELOW(ARITH_MAX);
-
-        *(u32 *)(out_buf + byte_idx) =
-            SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num);
-
-      }
-
-      break;
-
-    }
-
-    case 11: {
-
-      /* Just set a random byte to a random value. Because,
-         why not. We use XOR with 1-255 to eliminate the
-         possibility of a no-op. */
-
-      out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255);
-
-      break;
-
-    }
-
-  }
-
-}
-
-/* This function calculates the next power of 2 greater or equal its argument.
- @return The rounded up power of 2 (if no overflow) or 0 on overflow.
-*/
-static inline size_t next_pow2(size_t in) {
-
-  if (in == 0 || in > (size_t)-1)
-    return 0;                  /* avoid undefined behaviour under-/overflow */
-  size_t out = in - 1;
-  out |= out >> 1;
-  out |= out >> 2;
-  out |= out >> 4;
-  out |= out >> 8;
-  out |= out >> 16;
-  return out + 1;
-
-}
-
-/* This function makes sure *size is > size_needed after call.
- It will realloc *buf otherwise.
- *size will grow exponentially as per:
- https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
- Will return NULL and free *buf if size_needed is <1 or realloc failed.
- @return For convenience, this function returns *buf.
- */
-static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) {
-
-  /* No need to realloc */
-  if (likely(size_needed && *size >= size_needed)) return *buf;
-
-  /* No initial size was set */
-  if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE;
-
-  /* grow exponentially */
-  size_t next_size = next_pow2(size_needed);
-
-  /* handle overflow */
-  if (!next_size) { next_size = size_needed; }
-
-  /* alloc */
-  *buf = realloc(*buf, next_size);
-  *size = *buf ? next_size : 0;
-
-  return *buf;
-
-}
-
-/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
-static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2,
-                                 size_t *size2) {
-
-  void * scratch_buf = *buf1;
-  size_t scratch_size = *size1;
-  *buf1 = *buf2;
-  *size1 = *size2;
-  *buf2 = scratch_buf;
-  *size2 = scratch_size;
-
-}
-
-#undef INITIAL_GROWTH_SIZE
-
-#endif
-
diff --git a/custom_mutators/examples/custom_send.c b/custom_mutators/examples/custom_send.c
index ffea927e..9cc4b160 100644
--- a/custom_mutators/examples/custom_send.c
+++ b/custom_mutators/examples/custom_send.c
@@ -1,9 +1,14 @@
+//
+// This is an example on how to use afl_custom_send
+// It writes each mutated data set to /tmp/foo
+// You can modify this to send to IPC, shared memory, etc.
+//
 // cc -O3 -fPIC -shared -g -o custom_send.so -I../../include custom_send.c
 // cd ../..
 // afl-cc -o test-instr test-instr.c
-// afl-fuzz -i in -o out -- ./test-instr -f /tmp/foo
-
-#include "custom_mutator_helpers.h"
+// AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/examples/custom_send.so \
+//   afl-fuzz -i in -o out -- ./test-instr -f /tmp/foo
+//
 
 #include <stdio.h>
 #include <stdint.h>
@@ -11,13 +16,15 @@
 #include <unistd.h>
 #include <fcntl.h>
 
+#include "afl-fuzz.h"
+
 typedef struct my_mutator {
 
-  afl_t *afl;
+  afl_state_t *afl;
 
 } my_mutator_t;
 
-my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
+my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
 
   my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
   if (!data) {
diff --git a/custom_mutators/examples/example.c b/custom_mutators/examples/example.c
index 3f299508..42c7469c 100644
--- a/custom_mutators/examples/example.c
+++ b/custom_mutators/examples/example.c
@@ -6,8 +6,8 @@
              Dominik Maier <mail@dmnk.co>
 */
 
-// You need to use -I /path/to/AFLplusplus/include
-#include "custom_mutator_helpers.h"
+// You need to use -I/path/to/AFLplusplus/include -I.
+#include "afl-fuzz.h"
 
 #include <stdint.h>
 #include <stdlib.h>
@@ -26,19 +26,14 @@ static const char *commands[] = {
 
 typedef struct my_mutator {
 
-  afl_t *afl;
+  afl_state_t *afl;
 
   // any additional data here!
   size_t trim_size_current;
   int    trimmming_steps;
   int    cur_step;
 
-  // Reused buffers:
-  BUF_VAR(u8, fuzz);
-  BUF_VAR(u8, data);
-  BUF_VAR(u8, havoc);
-  BUF_VAR(u8, trim);
-  BUF_VAR(u8, post_process);
+  u8 *mutated_out, *post_process_buf, *trim_buf;
 
 } my_mutator_t;
 
@@ -53,7 +48,7 @@ typedef struct my_mutator {
  *         There may be multiple instances of this mutator in one afl-fuzz run!
  *         Return NULL on error.
  */
-my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
+my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
 
   srand(seed);  // needed also by surgical_havoc_mutate()
 
@@ -65,6 +60,27 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
 
   }
 
+  if ((data->mutated_out = (u8 *)malloc(MAX_FILE)) == NULL) {
+
+    perror("afl_custom_init malloc");
+    return NULL;
+
+  }
+
+  if ((data->post_process_buf = (u8 *)malloc(MAX_FILE)) == NULL) {
+
+    perror("afl_custom_init malloc");
+    return NULL;
+
+  }
+
+  if ((data->trim_buf = (u8 *)malloc(MAX_FILE)) == NULL) {
+
+    perror("afl_custom_init malloc");
+    return NULL;
+
+  }
+
   data->afl = afl;
 
   return data;
@@ -96,29 +112,14 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
   // the fuzzer
   size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size;
 
-  // maybe_grow is optimized to be quick for reused buffers.
-  u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size);
-  if (!mutated_out) {
-
-    *out_buf = NULL;
-    perror("custom mutator allocation (maybe_grow)");
-    return 0;            /* afl-fuzz will very likely error out after this. */
-
-  }
+  memcpy(data->mutated_out, buf, buf_size);
 
   // Randomly select a command string to add as a header to the packet
-  memcpy(mutated_out, commands[rand() % 3], 3);
+  memcpy(data->mutated_out, commands[rand() % 3], 3);
 
-  // Mutate the payload of the packet
-  int i;
-  for (i = 0; i < 8; ++i) {
+  if (mutated_size > max_size) { mutated_size = max_size; }
 
-    // Randomly perform one of the (no len modification) havoc mutations
-    surgical_havoc_mutate(mutated_out, 3, mutated_size);
-
-  }
-
-  *out_buf = mutated_out;
+  *out_buf = data->mutated_out;
   return mutated_size;
 
 }
@@ -142,24 +143,16 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
 size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf,
                                size_t buf_size, uint8_t **out_buf) {
 
-  uint8_t *post_process_buf =
-      maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5);
-  if (!post_process_buf) {
+  if (buf_size + 5 > MAX_FILE) { buf_size = MAX_FILE - 5; }
 
-    perror("custom mutator realloc failed.");
-    *out_buf = NULL;
-    return 0;
-
-  }
+  memcpy(data->post_process_buf + 5, buf, buf_size);
+  data->post_process_buf[0] = 'A';
+  data->post_process_buf[1] = 'F';
+  data->post_process_buf[2] = 'L';
+  data->post_process_buf[3] = '+';
+  data->post_process_buf[4] = '+';
 
-  memcpy(post_process_buf + 5, buf, buf_size);
-  post_process_buf[0] = 'A';
-  post_process_buf[1] = 'F';
-  post_process_buf[2] = 'L';
-  post_process_buf[3] = '+';
-  post_process_buf[4] = '+';
-
-  *out_buf = post_process_buf;
+  *out_buf = data->post_process_buf;
 
   return buf_size + 5;
 
@@ -195,13 +188,6 @@ int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf,
 
   data->cur_step = 0;
 
-  if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) {
-
-    perror("init_trim grow");
-    return -1;
-
-  }
-
   memcpy(data->trim_buf, buf, buf_size);
 
   data->trim_size_current = buf_size;
@@ -282,27 +268,11 @@ int32_t afl_custom_post_trim(my_mutator_t *data, int success) {
 size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size,
                                  u8 **out_buf, size_t max_size) {
 
-  if (buf_size == 0) {
-
-    *out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1);
-    if (!*out_buf) {
-
-      perror("custom havoc: maybe_grow");
-      return 0;
-
-    }
+  *out_buf = buf;  // in-place mutation
 
-    **out_buf = rand() % 256;
-    buf_size = 1;
-
-  } else {
-
-    // We reuse buf here. It's legal and faster.
-    *out_buf = buf;
-
-  }
+  if (buf_size <= sizeof(size_t)) { return buf_size; }
 
-  size_t victim = rand() % buf_size;
+  size_t victim = rand() % (buf_size - sizeof(size_t));
   (*out_buf)[victim] += rand() % 10;
 
   return buf_size;
@@ -369,9 +339,7 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t  *data,
 void afl_custom_deinit(my_mutator_t *data) {
 
   free(data->post_process_buf);
-  free(data->havoc_buf);
-  free(data->data_buf);
-  free(data->fuzz_buf);
+  free(data->mutated_out);
   free(data->trim_buf);
   free(data);
 
diff --git a/custom_mutators/examples/post_library_gif.so.c b/custom_mutators/examples/post_library_gif.so.c
index 9cd224f4..6737c627 100644
--- a/custom_mutators/examples/post_library_gif.so.c
+++ b/custom_mutators/examples/post_library_gif.so.c
@@ -45,9 +45,8 @@
    1) If you don't want to modify the test case, simply set `*out_buf = in_buf`
       and return the original `len`.
 
-   NOTE: the following is currently NOT true, we abort in this case!
    2) If you want to skip this test case altogether and have AFL generate a
-      new one, return 0 or set `*out_buf = NULL`.
+      new one, return 0.
       Use this sparingly - it's faster than running the target program
       with patently useless inputs, but still wastes CPU time.
 
@@ -59,8 +58,6 @@
       Note that the buffer will *not* be freed for you. To avoid memory leaks,
       you need to free it or reuse it on subsequent calls (as shown below).
 
-      *** Feel free to reuse the original 'in_buf' BUFFER and return it. ***
-
     Alright. The example below shows a simple postprocessor that tries to make
     sure that all input files start with "GIF89a".
 
@@ -72,7 +69,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include "alloc-inl.h"
+#include "afl-fuzz.h"
 
 /* Header that must be present at the beginning of every test case: */
 
@@ -80,8 +77,7 @@
 
 typedef struct post_state {
 
-  unsigned char *buf;
-  size_t         size;
+  size_t size;
 
 } post_state_t;
 
@@ -95,15 +91,6 @@ void *afl_custom_init(void *afl) {
 
   }
 
-  state->buf = calloc(sizeof(unsigned char), 4096);
-  if (!state->buf) {
-
-    free(state);
-    perror("calloc");
-    return NULL;
-
-  }
-
   return state;
 
 }
@@ -113,6 +100,10 @@ void *afl_custom_init(void *afl) {
 size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
                                unsigned int len, unsigned char **out_buf) {
 
+  /* we do in-place modification as we do not increase the size */
+
+  *out_buf = in_buf;
+
   /* Skip execution altogether for buffers shorter than 6 bytes (just to
      show how it's done). We can trust len to be sane. */
 
@@ -120,34 +111,7 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
 
   /* Do nothing for buffers that already start with the expected header. */
 
-  if (!memcmp(in_buf, HEADER, strlen(HEADER))) {
-
-    *out_buf = in_buf;
-    return len;
-
-  }
-
-  /* Allocate memory for new buffer, reusing previous allocation if
-     possible. Note we have to use afl-fuzz's own realloc!
-     Note that you should only do this if you need to grow the buffer,
-     otherwise work with in_buf, and assign it to *out_buf instead. */
-
-  *out_buf = afl_realloc(out_buf, len);
-
-  /* If we're out of memory, the most graceful thing to do is to return the
-     original buffer and give up on modifying it. Let AFL handle OOM on its
-     own later on. */
-
-  if (!*out_buf) {
-
-    *out_buf = in_buf;
-    return len;
-
-  }
-
-  if (len > strlen(HEADER))
-    memcpy(*out_buf + strlen(HEADER), in_buf + strlen(HEADER),
-           len - strlen(HEADER));
+  if (!memcmp(in_buf, HEADER, strlen(HEADER))) { return len; }
 
   /* Insert the new header. */
 
@@ -162,7 +126,6 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
 /* Gets called afterwards */
 void afl_custom_deinit(post_state_t *data) {
 
-  free(data->buf);
   free(data);
 
 }
diff --git a/custom_mutators/examples/post_library_png.so.c b/custom_mutators/examples/post_library_png.so.c
index cd65b1bc..652da497 100644
--- a/custom_mutators/examples/post_library_png.so.c
+++ b/custom_mutators/examples/post_library_png.so.c
@@ -30,7 +30,7 @@
 #include <string.h>
 #include <zlib.h>
 #include <arpa/inet.h>
-#include "alloc-inl.h"
+#include "afl-fuzz.h"
 
 /* A macro to round an integer up to 4 kB. */
 
@@ -53,7 +53,7 @@ void *afl_custom_init(void *afl) {
 
   }
 
-  state->buf = calloc(sizeof(unsigned char), 4096);
+  state->buf = calloc(sizeof(unsigned char), MAX_FILE);
   if (!state->buf) {
 
     free(state);
@@ -80,21 +80,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
 
   }
 
-  /* This is not a good way to do it, if you do not need to grow the buffer
-     then just work with in_buf instead for speed reasons.
-     But we want to show how to grow a buffer, so this is how it's done: */
-
-  unsigned int   pos = 8;
-  unsigned char *new_buf = afl_realloc(out_buf, UP4K(len));
-
-  if (!new_buf) {
-
-    *out_buf = in_buf;
-    return len;
-
-  }
-
-  memcpy(new_buf, in_buf, len);
+  unsigned int pos = 8;
 
   /* Minimum size of a zero-length PNG chunk is 12 bytes; if we
      don't have that, we can bail out. */
@@ -124,7 +110,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
 
     if (real_cksum != file_cksum) {
 
-      *(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum;
+      *(uint32_t *)(data->buf + pos + 8 + chunk_len) = real_cksum;
 
     }
 
@@ -134,7 +120,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
 
   }
 
-  *out_buf = new_buf;
+  *out_buf = data->buf;
   return len;
 
 }
diff --git a/custom_mutators/examples/simple_example.c b/custom_mutators/examples/simple_example.c
index d888ec1f..2c0abe29 100644
--- a/custom_mutators/examples/simple_example.c
+++ b/custom_mutators/examples/simple_example.c
@@ -1,6 +1,6 @@
 // This simple example just creates random buffer <= 100 filled with 'A'
 // needs -I /path/to/AFLplusplus/include
-#include "custom_mutator_helpers.h"
+#include "afl-fuzz.h"
 
 #include <stdint.h>
 #include <stdlib.h>
@@ -13,14 +13,14 @@
 
 typedef struct my_mutator {
 
-  afl_t *afl;
+  afl_state_t *afl;
 
   // Reused buffers:
-  BUF_VAR(u8, fuzz);
+  u8 *fuzz_buf;
 
 } my_mutator_t;
 
-my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
+my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
 
   srand(seed);
   my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
@@ -31,6 +31,14 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
 
   }
 
+  data->fuzz_buf = (u8 *)malloc(MAX_FILE);
+  if (!data->fuzz_buf) {
+
+    perror("afl_custom_init malloc");
+    return NULL;
+
+  }
+
   data->afl = afl;
 
   return data;
@@ -44,18 +52,10 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
 
   int size = (rand() % 100) + 1;
   if (size > max_size) size = max_size;
-  u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size);
-  if (!mutated_out) {
-
-    *out_buf = NULL;
-    perror("custom mutator allocation (maybe_grow)");
-    return 0;            /* afl-fuzz will very likely error out after this. */
-
-  }
 
-  memset(mutated_out, _FIXED_CHAR, size);
+  memset(data->fuzz_buf, _FIXED_CHAR, size);
 
-  *out_buf = mutated_out;
+  *out_buf = data->fuzz_buf;
   return size;
 
 }
diff --git a/custom_mutators/gramatron/build_gramatron_mutator.sh b/custom_mutators/gramatron/build_gramatron_mutator.sh
index ff88ff26..c830329e 100755
--- a/custom_mutators/gramatron/build_gramatron_mutator.sh
+++ b/custom_mutators/gramatron/build_gramatron_mutator.sh
@@ -11,7 +11,7 @@
 # Adapted for AFLplusplus by Dominik Maier <mail@dmnk.co>
 #
 # Copyright 2017 Battelle Memorial Institute. All rights reserved.
-# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/custom_mutators/grammar_mutator/build_grammar_mutator.sh b/custom_mutators/grammar_mutator/build_grammar_mutator.sh
index 74cae8aa..593cd2dc 100755
--- a/custom_mutators/grammar_mutator/build_grammar_mutator.sh
+++ b/custom_mutators/grammar_mutator/build_grammar_mutator.sh
@@ -14,7 +14,7 @@
 #                                <andreafioraldi@gmail.com>
 #
 # Copyright 2017 Battelle Memorial Institute. All rights reserved.
-# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/custom_mutators/honggfuzz/custom_mutator_helpers.h b/custom_mutators/honggfuzz/custom_mutator_helpers.h
deleted file mode 100644
index 57754697..00000000
--- a/custom_mutators/honggfuzz/custom_mutator_helpers.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef CUSTOM_MUTATOR_HELPERS
-#define CUSTOM_MUTATOR_HELPERS
-
-#include "config.h"
-#include "types.h"
-#include "afl-fuzz.h"
-#include <stdlib.h>
-
-#define INITIAL_GROWTH_SIZE (64)
-
-/* Use in a struct: creates a name_buf and a name_size variable. */
-#define BUF_VAR(type, name) \
-  type * name##_buf;        \
-  size_t name##_size;
-/* this filles in `&structptr->something_buf, &structptr->something_size`. */
-#define BUF_PARAMS(struct, name) \
-  (void **)&struct->name##_buf, &struct->name##_size
-
-#undef INITIAL_GROWTH_SIZE
-
-#endif
-
diff --git a/custom_mutators/honggfuzz/honggfuzz.c b/custom_mutators/honggfuzz/honggfuzz.c
index d7b3c9c5..0dd59aee 100644
--- a/custom_mutators/honggfuzz/honggfuzz.c
+++ b/custom_mutators/honggfuzz/honggfuzz.c
@@ -3,14 +3,14 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "custom_mutator_helpers.h"
+#include "afl-fuzz.h"
 #include "mangle.h"
 
 #define NUMBER_OF_MUTATIONS 5
 
-uint8_t *         queue_input;
+uint8_t          *queue_input;
 size_t            queue_input_size;
-afl_state_t *     afl_struct;
+afl_state_t      *afl_struct;
 run_t             run;
 honggfuzz_t       global;
 struct _dynfile_t dynfile;
@@ -18,8 +18,8 @@ struct _dynfile_t dynfile;
 typedef struct my_mutator {
 
   afl_state_t *afl;
-  run_t *      run;
-  u8 *         mutator_buf;
+  run_t       *run;
+  u8          *mutator_buf;
   unsigned int seed;
   unsigned int extras_cnt, a_extras_cnt;
 
@@ -65,9 +65,9 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
 /* When a new queue entry is added we check if there are new dictionary
    entries to add to honggfuzz structure */
 
-uint8_t afl_custom_queue_new_entry(my_mutator_t * data,
-                                   const uint8_t *filename_new_queue,
-                                   const uint8_t *filename_orig_queue) {
+void afl_custom_queue_new_entry(my_mutator_t  *data,
+                                const uint8_t *filename_new_queue,
+                                const uint8_t *filename_orig_queue) {
 
   if (run.global->mutate.dictionaryCnt >= 1024) return;
 
@@ -97,7 +97,7 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t * data,
 
   }
 
-  return 0;
+  return;
 
 }
 
diff --git a/custom_mutators/honggfuzz/mangle.c b/custom_mutators/honggfuzz/mangle.c
index 637d428d..7b7ccb91 100644
--- a/custom_mutators/honggfuzz/mangle.c
+++ b/custom_mutators/honggfuzz/mangle.c
@@ -39,11 +39,16 @@
 #include "libhfcommon/log.h"
 #include "libhfcommon/util.h"
 
-static inline size_t mangle_LenLeft(run_t* run, size_t off) {
-    if (off >= run->dynfile->size) {
-        LOG_F("Offset is too large: off:%zu >= len:%zu", off, run->dynfile->size);
-    }
-    return (run->dynfile->size - off - 1);
+static inline size_t mangle_LenLeft(run_t *run, size_t off) {
+
+  if (off >= run->dynfile->size) {
+
+    LOG_F("Offset is too large: off:%zu >= len:%zu", off, run->dynfile->size);
+
+  }
+
+  return (run->dynfile->size - off - 1);
+
 }
 
 /*
@@ -51,196 +56,233 @@ static inline size_t mangle_LenLeft(run_t* run, size_t off) {
  * Based on an idea by https://twitter.com/gamozolabs
  */
 static inline size_t mangle_getLen(size_t max) {
-    if (max > _HF_INPUT_MAX_SIZE) {
-        LOG_F("max (%zu) > _HF_INPUT_MAX_SIZE (%zu)", max, (size_t)_HF_INPUT_MAX_SIZE);
-    }
-    if (max == 0) {
-        LOG_F("max == 0");
-    }
-    if (max == 1) {
-        return 1;
-    }
 
-    /* Give 50% chance the the uniform distribution */
-    if (util_rnd64() & 1) {
-        return (size_t)util_rndGet(1, max);
-    }
+  if (max > _HF_INPUT_MAX_SIZE) {
+
+    LOG_F("max (%zu) > _HF_INPUT_MAX_SIZE (%zu)", max,
+          (size_t)_HF_INPUT_MAX_SIZE);
+
+  }
+
+  if (max == 0) { LOG_F("max == 0"); }
+  if (max == 1) { return 1; }
+
+  /* Give 50% chance the the uniform distribution */
+  if (util_rnd64() & 1) { return (size_t)util_rndGet(1, max); }
+
+  /* effectively exprand() */
+  return (size_t)util_rndGet(1, util_rndGet(1, max));
 
-    /* effectively exprand() */
-    return (size_t)util_rndGet(1, util_rndGet(1, max));
 }
 
 /* Prefer smaller values here, so use mangle_getLen() */
-static inline size_t mangle_getOffSet(run_t* run) {
-    return mangle_getLen(run->dynfile->size) - 1;
+static inline size_t mangle_getOffSet(run_t *run) {
+
+  return mangle_getLen(run->dynfile->size) - 1;
+
 }
 
 /* Offset which can be equal to the file size */
-static inline size_t mangle_getOffSetPlus1(run_t* run) {
-    size_t reqlen = HF_MIN(run->dynfile->size + 1, _HF_INPUT_MAX_SIZE);
-    return mangle_getLen(reqlen) - 1;
+static inline size_t mangle_getOffSetPlus1(run_t *run) {
+
+  size_t reqlen = HF_MIN(run->dynfile->size + 1, _HF_INPUT_MAX_SIZE);
+  return mangle_getLen(reqlen) - 1;
+
 }
 
-static inline void mangle_Move(run_t* run, size_t off_from, size_t off_to, size_t len) {
-    if (off_from >= run->dynfile->size) {
-        return;
-    }
-    if (off_to >= run->dynfile->size) {
-        return;
-    }
-    if (off_from == off_to) {
-        return;
-    }
+static inline void mangle_Move(run_t *run, size_t off_from, size_t off_to,
+                               size_t len) {
+
+  if (off_from >= run->dynfile->size) { return; }
+  if (off_to >= run->dynfile->size) { return; }
+  if (off_from == off_to) { return; }
 
-    size_t len_from = run->dynfile->size - off_from;
-    len             = HF_MIN(len, len_from);
+  size_t len_from = run->dynfile->size - off_from;
+  len = HF_MIN(len, len_from);
 
-    size_t len_to = run->dynfile->size - off_to;
-    len           = HF_MIN(len, len_to);
+  size_t len_to = run->dynfile->size - off_to;
+  len = HF_MIN(len, len_to);
+
+  memmove(&run->dynfile->data[off_to], &run->dynfile->data[off_from], len);
 
-    memmove(&run->dynfile->data[off_to], &run->dynfile->data[off_from], len);
 }
 
-static inline void mangle_Overwrite(
-    run_t* run, size_t off, const uint8_t* src, size_t len, bool printable) {
-    if (len == 0) {
-        return;
-    }
-    size_t maxToCopy = run->dynfile->size - off;
-    if (len > maxToCopy) {
-        len = maxToCopy;
-    }
+static inline void mangle_Overwrite(run_t *run, size_t off, const uint8_t *src,
+                                    size_t len, bool printable) {
+
+  if (len == 0) { return; }
+  size_t maxToCopy = run->dynfile->size - off;
+  if (len > maxToCopy) { len = maxToCopy; }
+
+  memmove(&run->dynfile->data[off], src, len);
+  if (printable) { util_turnToPrintable(&run->dynfile->data[off], len); }
 
-    memmove(&run->dynfile->data[off], src, len);
-    if (printable) {
-        util_turnToPrintable(&run->dynfile->data[off], len);
-    }
 }
 
-static inline size_t mangle_Inflate(run_t* run, size_t off, size_t len, bool printable) {
-    if (run->dynfile->size >= run->global->mutate.maxInputSz) {
-        return 0;
-    }
-    if (len > (run->global->mutate.maxInputSz - run->dynfile->size)) {
-        len = run->global->mutate.maxInputSz - run->dynfile->size;
-    }
+static inline size_t mangle_Inflate(run_t *run, size_t off, size_t len,
+                                    bool printable) {
 
-    input_setSize(run, run->dynfile->size + len);
-    mangle_Move(run, off, off + len, run->dynfile->size);
-    if (printable) {
-        memset(&run->dynfile->data[off], ' ', len);
-    }
+  if (run->dynfile->size >= run->global->mutate.maxInputSz) { return 0; }
+  if (len > (run->global->mutate.maxInputSz - run->dynfile->size)) {
+
+    len = run->global->mutate.maxInputSz - run->dynfile->size;
+
+  }
+
+  input_setSize(run, run->dynfile->size + len);
+  mangle_Move(run, off, off + len, run->dynfile->size);
+  if (printable) { memset(&run->dynfile->data[off], ' ', len); }
+
+  return len;
 
-    return len;
 }
 
-static inline void mangle_Insert(
-    run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) {
-    len = mangle_Inflate(run, off, len, printable);
-    mangle_Overwrite(run, off, val, len, printable);
+static inline void mangle_Insert(run_t *run, size_t off, const uint8_t *val,
+                                 size_t len, bool printable) {
+
+  len = mangle_Inflate(run, off, len, printable);
+  mangle_Overwrite(run, off, val, len, printable);
+
 }
 
-static inline void mangle_UseValue(run_t* run, const uint8_t* val, size_t len, bool printable) {
-    if (util_rnd64() & 1) {
-        mangle_Overwrite(run, mangle_getOffSet(run), val, len, printable);
-    } else {
-        mangle_Insert(run, mangle_getOffSetPlus1(run), val, len, printable);
-    }
+static inline void mangle_UseValue(run_t *run, const uint8_t *val, size_t len,
+                                   bool printable) {
+
+  if (util_rnd64() & 1) {
+
+    mangle_Overwrite(run, mangle_getOffSet(run), val, len, printable);
+
+  } else {
+
+    mangle_Insert(run, mangle_getOffSetPlus1(run), val, len, printable);
+
+  }
+
 }
 
-static inline void mangle_UseValueAt(
-    run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) {
-    if (util_rnd64() & 1) {
-        mangle_Overwrite(run, off, val, len, printable);
-    } else {
-        mangle_Insert(run, off, val, len, printable);
-    }
+static inline void mangle_UseValueAt(run_t *run, size_t off, const uint8_t *val,
+                                     size_t len, bool printable) {
+
+  if (util_rnd64() & 1) {
+
+    mangle_Overwrite(run, off, val, len, printable);
+
+  } else {
+
+    mangle_Insert(run, off, val, len, printable);
+
+  }
+
 }
 
-static void mangle_MemSwap(run_t* run, bool printable HF_ATTR_UNUSED) {
-    /* No big deal if those two are overlapping */
-    size_t off1    = mangle_getOffSet(run);
-    size_t maxlen1 = run->dynfile->size - off1;
-    size_t off2    = mangle_getOffSet(run);
-    size_t maxlen2 = run->dynfile->size - off2;
-    size_t len     = mangle_getLen(HF_MIN(maxlen1, maxlen2));
+static void mangle_MemSwap(run_t *run, bool printable HF_ATTR_UNUSED) {
 
-    if (off1 == off2) {
-        return;
-    }
+  /* No big deal if those two are overlapping */
+  size_t off1 = mangle_getOffSet(run);
+  size_t maxlen1 = run->dynfile->size - off1;
+  size_t off2 = mangle_getOffSet(run);
+  size_t maxlen2 = run->dynfile->size - off2;
+  size_t len = mangle_getLen(HF_MIN(maxlen1, maxlen2));
+
+  if (off1 == off2) { return; }
+
+  for (size_t i = 0; i < (len / 2); i++) {
+
+    /*
+     * First - from the head, next from the tail. Don't worry about layout of
+     * the overlapping part - there's no good solution to that, and it can be
+     * left somewhat scrambled, while still preserving the entropy
+     */
+    const uint8_t tmp1 = run->dynfile->data[off2 + i];
+    run->dynfile->data[off2 + i] = run->dynfile->data[off1 + i];
+    run->dynfile->data[off1 + i] = tmp1;
+    const uint8_t tmp2 = run->dynfile->data[off2 + (len - 1) - i];
+    run->dynfile->data[off2 + (len - 1) - i] =
+        run->dynfile->data[off1 + (len - 1) - i];
+    run->dynfile->data[off1 + (len - 1) - i] = tmp2;
+
+  }
 
-    for (size_t i = 0; i < (len / 2); i++) {
-        /*
-         * First - from the head, next from the tail. Don't worry about layout of the overlapping
-         * part - there's no good solution to that, and it can be left somewhat scrambled,
-         * while still preserving the entropy
-         */
-        const uint8_t tmp1                       = run->dynfile->data[off2 + i];
-        run->dynfile->data[off2 + i]             = run->dynfile->data[off1 + i];
-        run->dynfile->data[off1 + i]             = tmp1;
-        const uint8_t tmp2                       = run->dynfile->data[off2 + (len - 1) - i];
-        run->dynfile->data[off2 + (len - 1) - i] = run->dynfile->data[off1 + (len - 1) - i];
-        run->dynfile->data[off1 + (len - 1) - i] = tmp2;
-    }
 }
 
-static void mangle_MemCopy(run_t* run, bool printable HF_ATTR_UNUSED) {
-    size_t off = mangle_getOffSet(run);
-    size_t len = mangle_getLen(run->dynfile->size - off);
+static void mangle_MemCopy(run_t *run, bool printable HF_ATTR_UNUSED) {
+
+  size_t off = mangle_getOffSet(run);
+  size_t len = mangle_getLen(run->dynfile->size - off);
 
-    /* Use a temp buf, as Insert/Inflate can change source bytes */
-    uint8_t* tmpbuf = (uint8_t*)util_Malloc(len);
-    defer {
-        free(tmpbuf);
-    };
-    memmove(tmpbuf, &run->dynfile->data[off], len);
+  /* Use a temp buf, as Insert/Inflate can change source bytes */
+  uint8_t *tmpbuf = (uint8_t *)util_Malloc(len);
+  defer {
+
+    free(tmpbuf);
+
+  };
+
+  memmove(tmpbuf, &run->dynfile->data[off], len);
+
+  mangle_UseValue(run, tmpbuf, len, printable);
 
-    mangle_UseValue(run, tmpbuf, len, printable);
 }
 
-static void mangle_Bytes(run_t* run, bool printable) {
-    uint16_t buf;
-    if (printable) {
-        util_rndBufPrintable((uint8_t*)&buf, sizeof(buf));
-    } else {
-        buf = util_rnd64();
-    }
+static void mangle_Bytes(run_t *run, bool printable) {
+
+  uint16_t buf;
+  if (printable) {
+
+    util_rndBufPrintable((uint8_t *)&buf, sizeof(buf));
+
+  } else {
+
+    buf = util_rnd64();
+
+  }
+
+  /* Overwrite with random 1-2-byte values */
+  size_t toCopy = util_rndGet(1, 2);
+  mangle_UseValue(run, (const uint8_t *)&buf, toCopy, printable);
 
-    /* Overwrite with random 1-2-byte values */
-    size_t toCopy = util_rndGet(1, 2);
-    mangle_UseValue(run, (const uint8_t*)&buf, toCopy, printable);
 }
 
-static void mangle_ByteRepeat(run_t* run, bool printable) {
-    size_t off     = mangle_getOffSet(run);
-    size_t destOff = off + 1;
-    size_t maxSz   = run->dynfile->size - destOff;
+static void mangle_ByteRepeat(run_t *run, bool printable) {
 
-    /* No space to repeat */
-    if (!maxSz) {
-        mangle_Bytes(run, printable);
-        return;
-    }
+  size_t off = mangle_getOffSet(run);
+  size_t destOff = off + 1;
+  size_t maxSz = run->dynfile->size - destOff;
+
+  /* No space to repeat */
+  if (!maxSz) {
+
+    mangle_Bytes(run, printable);
+    return;
+
+  }
+
+  size_t len = mangle_getLen(maxSz);
+  if (util_rnd64() & 0x1) {
+
+    len = mangle_Inflate(run, destOff, len, printable);
+
+  }
+
+  memset(&run->dynfile->data[destOff], run->dynfile->data[off], len);
 
-    size_t len = mangle_getLen(maxSz);
-    if (util_rnd64() & 0x1) {
-        len = mangle_Inflate(run, destOff, len, printable);
-    }
-    memset(&run->dynfile->data[destOff], run->dynfile->data[off], len);
 }
 
-static void mangle_Bit(run_t* run, bool printable) {
-    size_t off = mangle_getOffSet(run);
-    run->dynfile->data[off] ^= (uint8_t)(1U << util_rndGet(0, 7));
-    if (printable) {
-        util_turnToPrintable(&(run->dynfile->data[off]), 1);
-    }
+static void mangle_Bit(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+  run->dynfile->data[off] ^= (uint8_t)(1U << util_rndGet(0, 7));
+  if (printable) { util_turnToPrintable(&(run->dynfile->data[off]), 1); }
+
 }
 
 static const struct {
-    const uint8_t val[8];
-    const size_t  size;
+
+  const uint8_t val[8];
+  const size_t  size;
+
 } mangleMagicVals[] = {
+
     /* 1B - No endianness */
     {"\x00\x00\x00\x00\x00\x00\x00\x00", 1},
     {"\x01\x00\x00\x00\x00\x00\x00\x00", 1},
@@ -472,436 +514,543 @@ static const struct {
     {"\x00\x00\x00\x00\x00\x00\x00\x80", 8},
     {"\x01\x00\x00\x00\x00\x00\x00\x80", 8},
     {"\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
+
 };
 
-static void mangle_Magic(run_t* run, bool printable) {
-    uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleMagicVals) - 1);
-    mangle_UseValue(run, mangleMagicVals[choice].val, mangleMagicVals[choice].size, printable);
+static void mangle_Magic(run_t *run, bool printable) {
+
+  uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleMagicVals) - 1);
+  mangle_UseValue(run, mangleMagicVals[choice].val,
+                  mangleMagicVals[choice].size, printable);
+
 }
 
-static void mangle_StaticDict(run_t* run, bool printable) {
-    if (run->global->mutate.dictionaryCnt == 0) {
-        mangle_Bytes(run, printable);
-        return;
-    }
-    uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1);
-    mangle_UseValue(run, run->global->mutate.dictionary[choice].val,
-        run->global->mutate.dictionary[choice].len, printable);
+static void mangle_StaticDict(run_t *run, bool printable) {
+
+  if (run->global->mutate.dictionaryCnt == 0) {
+
+    mangle_Bytes(run, printable);
+    return;
+
+  }
+
+  uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1);
+  mangle_UseValue(run, run->global->mutate.dictionary[choice].val,
+                  run->global->mutate.dictionary[choice].len, printable);
+
 }
 
-static inline const uint8_t* mangle_FeedbackDict(run_t* run, size_t* len) {
-    if (!run->global->feedback.cmpFeedback) {
-        return NULL;
-    }
-    cmpfeedback_t* cmpf = run->global->feedback.cmpFeedbackMap;
-    uint32_t       cnt  = ATOMIC_GET(cmpf->cnt);
-    if (cnt == 0) {
-        return NULL;
-    }
-    if (cnt > ARRAYSIZE(cmpf->valArr)) {
-        cnt = ARRAYSIZE(cmpf->valArr);
-    }
-    uint32_t choice = util_rndGet(0, cnt - 1);
-    *len            = (size_t)ATOMIC_GET(cmpf->valArr[choice].len);
-    if (*len == 0) {
-        return NULL;
-    }
-    return cmpf->valArr[choice].val;
+static inline const uint8_t *mangle_FeedbackDict(run_t *run, size_t *len) {
+
+  if (!run->global->feedback.cmpFeedback) { return NULL; }
+  cmpfeedback_t *cmpf = run->global->feedback.cmpFeedbackMap;
+  uint32_t       cnt = ATOMIC_GET(cmpf->cnt);
+  if (cnt == 0) { return NULL; }
+  if (cnt > ARRAYSIZE(cmpf->valArr)) { cnt = ARRAYSIZE(cmpf->valArr); }
+  uint32_t choice = util_rndGet(0, cnt - 1);
+  *len = (size_t)ATOMIC_GET(cmpf->valArr[choice].len);
+  if (*len == 0) { return NULL; }
+  return cmpf->valArr[choice].val;
+
 }
 
-static void mangle_ConstFeedbackDict(run_t* run, bool printable) {
-    size_t         len;
-    const uint8_t* val = mangle_FeedbackDict(run, &len);
-    if (val == NULL) {
-        mangle_Bytes(run, printable);
-        return;
-    }
-    mangle_UseValue(run, val, len, printable);
+static void mangle_ConstFeedbackDict(run_t *run, bool printable) {
+
+  size_t         len;
+  const uint8_t *val = mangle_FeedbackDict(run, &len);
+  if (val == NULL) {
+
+    mangle_Bytes(run, printable);
+    return;
+
+  }
+
+  mangle_UseValue(run, val, len, printable);
+
 }
 
-static void mangle_MemSet(run_t* run, bool printable) {
-    size_t off = mangle_getOffSet(run);
-    size_t len = mangle_getLen(run->dynfile->size - off);
-    int    val = printable ? (int)util_rndPrintable() : (int)util_rndGet(0, UINT8_MAX);
+static void mangle_MemSet(run_t *run, bool printable) {
 
-    if (util_rnd64() & 1) {
-        len = mangle_Inflate(run, off, len, printable);
-    }
+  size_t off = mangle_getOffSet(run);
+  size_t len = mangle_getLen(run->dynfile->size - off);
+  int    val =
+      printable ? (int)util_rndPrintable() : (int)util_rndGet(0, UINT8_MAX);
+
+  if (util_rnd64() & 1) { len = mangle_Inflate(run, off, len, printable); }
+
+  memset(&run->dynfile->data[off], val, len);
 
-    memset(&run->dynfile->data[off], val, len);
 }
 
-static void mangle_MemClr(run_t* run, bool printable) {
-    size_t off = mangle_getOffSet(run);
-    size_t len = mangle_getLen(run->dynfile->size - off);
-    int    val = printable ? ' ' : 0;
+static void mangle_MemClr(run_t *run, bool printable) {
 
-    if (util_rnd64() & 1) {
-        len = mangle_Inflate(run, off, len, printable);
-    }
+  size_t off = mangle_getOffSet(run);
+  size_t len = mangle_getLen(run->dynfile->size - off);
+  int    val = printable ? ' ' : 0;
+
+  if (util_rnd64() & 1) { len = mangle_Inflate(run, off, len, printable); }
+
+  memset(&run->dynfile->data[off], val, len);
 
-    memset(&run->dynfile->data[off], val, len);
 }
 
-static void mangle_RandomBuf(run_t* run, bool printable) {
-    size_t off = mangle_getOffSet(run);
-    size_t len = mangle_getLen(run->dynfile->size - off);
+static void mangle_RandomBuf(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+  size_t len = mangle_getLen(run->dynfile->size - off);
+
+  if (util_rnd64() & 1) { len = mangle_Inflate(run, off, len, printable); }
+
+  if (printable) {
+
+    util_rndBufPrintable(&run->dynfile->data[off], len);
+
+  } else {
+
+    util_rndBuf(&run->dynfile->data[off], len);
+
+  }
+
+}
+
+static inline void mangle_AddSubWithRange(run_t *run, size_t off, size_t varLen,
+                                          uint64_t range, bool printable) {
+
+  int64_t delta = (int64_t)util_rndGet(0, range * 2) - (int64_t)range;
+
+  switch (varLen) {
+
+    case 1: {
+
+      run->dynfile->data[off] += delta;
+      break;
 
-    if (util_rnd64() & 1) {
-        len = mangle_Inflate(run, off, len, printable);
     }
 
-    if (printable) {
-        util_rndBufPrintable(&run->dynfile->data[off], len);
-    } else {
-        util_rndBuf(&run->dynfile->data[off], len);
+    case 2: {
+
+      int16_t val;
+      memcpy(&val, &run->dynfile->data[off], sizeof(val));
+      if (util_rnd64() & 0x1) {
+
+        val += delta;
+
+      } else {
+
+        /* Foreign endianess */
+        val = __builtin_bswap16(val);
+        val += delta;
+        val = __builtin_bswap16(val);
+
+      }
+
+      mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable);
+      break;
+
     }
-}
 
-static inline void mangle_AddSubWithRange(
-    run_t* run, size_t off, size_t varLen, uint64_t range, bool printable) {
-    int64_t delta = (int64_t)util_rndGet(0, range * 2) - (int64_t)range;
-
-    switch (varLen) {
-        case 1: {
-            run->dynfile->data[off] += delta;
-            break;
-        }
-        case 2: {
-            int16_t val;
-            memcpy(&val, &run->dynfile->data[off], sizeof(val));
-            if (util_rnd64() & 0x1) {
-                val += delta;
-            } else {
-                /* Foreign endianess */
-                val = __builtin_bswap16(val);
-                val += delta;
-                val = __builtin_bswap16(val);
-            }
-            mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
-            break;
-        }
-        case 4: {
-            int32_t val;
-            memcpy(&val, &run->dynfile->data[off], sizeof(val));
-            if (util_rnd64() & 0x1) {
-                val += delta;
-            } else {
-                /* Foreign endianess */
-                val = __builtin_bswap32(val);
-                val += delta;
-                val = __builtin_bswap32(val);
-            }
-            mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
-            break;
-        }
-        case 8: {
-            int64_t val;
-            memcpy(&val, &run->dynfile->data[off], sizeof(val));
-            if (util_rnd64() & 0x1) {
-                val += delta;
-            } else {
-                /* Foreign endianess */
-                val = __builtin_bswap64(val);
-                val += delta;
-                val = __builtin_bswap64(val);
-            }
-            mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
-            break;
-        }
-        default: {
-            LOG_F("Unknown variable length size: %zu", varLen);
-        }
+    case 4: {
+
+      int32_t val;
+      memcpy(&val, &run->dynfile->data[off], sizeof(val));
+      if (util_rnd64() & 0x1) {
+
+        val += delta;
+
+      } else {
+
+        /* Foreign endianess */
+        val = __builtin_bswap32(val);
+        val += delta;
+        val = __builtin_bswap32(val);
+
+      }
+
+      mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable);
+      break;
+
     }
-}
 
-static void mangle_AddSub(run_t* run, bool printable) {
-    size_t off = mangle_getOffSet(run);
+    case 8: {
+
+      int64_t val;
+      memcpy(&val, &run->dynfile->data[off], sizeof(val));
+      if (util_rnd64() & 0x1) {
+
+        val += delta;
+
+      } else {
+
+        /* Foreign endianess */
+        val = __builtin_bswap64(val);
+        val += delta;
+        val = __builtin_bswap64(val);
+
+      }
+
+      mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable);
+      break;
 
-    /* 1,2,4,8 */
-    size_t varLen = 1U << util_rndGet(0, 3);
-    if ((run->dynfile->size - off) < varLen) {
-        varLen = 1;
     }
 
-    uint64_t range;
-    switch (varLen) {
-        case 1:
-            range = 16;
-            break;
-        case 2:
-            range = 4096;
-            break;
-        case 4:
-            range = 1048576;
-            break;
-        case 8:
-            range = 268435456;
-            break;
-        default:
-            LOG_F("Invalid operand size: %zu", varLen);
+    default: {
+
+      LOG_F("Unknown variable length size: %zu", varLen);
+
     }
 
-    mangle_AddSubWithRange(run, off, varLen, range, printable);
+  }
+
 }
 
-static void mangle_IncByte(run_t* run, bool printable) {
-    size_t off = mangle_getOffSet(run);
-    if (printable) {
-        run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 1) % 95 + 32;
-    } else {
-        run->dynfile->data[off] += (uint8_t)1UL;
-    }
+static void mangle_AddSub(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+
+  /* 1,2,4,8 */
+  size_t varLen = 1U << util_rndGet(0, 3);
+  if ((run->dynfile->size - off) < varLen) { varLen = 1; }
+
+  uint64_t range;
+  switch (varLen) {
+
+    case 1:
+      range = 16;
+      break;
+    case 2:
+      range = 4096;
+      break;
+    case 4:
+      range = 1048576;
+      break;
+    case 8:
+      range = 268435456;
+      break;
+    default:
+      LOG_F("Invalid operand size: %zu", varLen);
+
+  }
+
+  mangle_AddSubWithRange(run, off, varLen, range, printable);
+
 }
 
-static void mangle_DecByte(run_t* run, bool printable) {
-    size_t off = mangle_getOffSet(run);
-    if (printable) {
-        run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 94) % 95 + 32;
-    } else {
-        run->dynfile->data[off] -= (uint8_t)1UL;
-    }
+static void mangle_IncByte(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+  if (printable) {
+
+    run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 1) % 95 + 32;
+
+  } else {
+
+    run->dynfile->data[off] += (uint8_t)1UL;
+
+  }
+
 }
 
-static void mangle_NegByte(run_t* run, bool printable) {
-    size_t off = mangle_getOffSet(run);
-    if (printable) {
-        run->dynfile->data[off] = 94 - (run->dynfile->data[off] - 32) + 32;
-    } else {
-        run->dynfile->data[off] = ~(run->dynfile->data[off]);
-    }
+static void mangle_DecByte(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+  if (printable) {
+
+    run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 94) % 95 + 32;
+
+  } else {
+
+    run->dynfile->data[off] -= (uint8_t)1UL;
+
+  }
+
 }
 
-static void mangle_Expand(run_t* run, bool printable) {
-    size_t off = mangle_getOffSet(run);
-    size_t len;
-    if (util_rnd64() % 16) {
-        len = mangle_getLen(HF_MIN(16, run->global->mutate.maxInputSz - off));
-    } else {
-        len = mangle_getLen(run->global->mutate.maxInputSz - off);
-    }
+static void mangle_NegByte(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+  if (printable) {
+
+    run->dynfile->data[off] = 94 - (run->dynfile->data[off] - 32) + 32;
+
+  } else {
+
+    run->dynfile->data[off] = ~(run->dynfile->data[off]);
+
+  }
 
-    mangle_Inflate(run, off, len, printable);
 }
 
-static void mangle_Shrink(run_t* run, bool printable HF_ATTR_UNUSED) {
-    if (run->dynfile->size <= 2U) {
-        return;
-    }
+static void mangle_Expand(run_t *run, bool printable) {
 
-    size_t off_start = mangle_getOffSet(run);
-    size_t len       = mangle_LenLeft(run, off_start);
-    if (len == 0) {
-        return;
-    }
-    if (util_rnd64() % 16) {
-        len = mangle_getLen(HF_MIN(16, len));
-    } else {
-        len = mangle_getLen(len);
-    }
-    size_t off_end     = off_start + len;
-    size_t len_to_move = run->dynfile->size - off_end;
+  size_t off = mangle_getOffSet(run);
+  size_t len;
+  if (util_rnd64() % 16) {
+
+    len = mangle_getLen(HF_MIN(16, run->global->mutate.maxInputSz - off));
+
+  } else {
+
+    len = mangle_getLen(run->global->mutate.maxInputSz - off);
+
+  }
+
+  mangle_Inflate(run, off, len, printable);
 
-    mangle_Move(run, off_end, off_start, len_to_move);
-    input_setSize(run, run->dynfile->size - len);
 }
-static void mangle_ASCIINum(run_t* run, bool printable) {
-    size_t len = util_rndGet(2, 8);
 
-    char buf[20];
-    snprintf(buf, sizeof(buf), "%-19" PRId64, (int64_t)util_rnd64());
+static void mangle_Shrink(run_t *run, bool printable HF_ATTR_UNUSED) {
+
+  if (run->dynfile->size <= 2U) { return; }
+
+  size_t off_start = mangle_getOffSet(run);
+  size_t len = mangle_LenLeft(run, off_start);
+  if (len == 0) { return; }
+  if (util_rnd64() % 16) {
+
+    len = mangle_getLen(HF_MIN(16, len));
+
+  } else {
+
+    len = mangle_getLen(len);
+
+  }
+
+  size_t off_end = off_start + len;
+  size_t len_to_move = run->dynfile->size - off_end;
+
+  mangle_Move(run, off_end, off_start, len_to_move);
+  input_setSize(run, run->dynfile->size - len);
 
-    mangle_UseValue(run, (const uint8_t*)buf, len, printable);
 }
 
-static void mangle_ASCIINumChange(run_t* run, bool printable) {
-    size_t off = mangle_getOffSet(run);
+static void mangle_ASCIINum(run_t *run, bool printable) {
 
-    /* Find a digit */
-    for (; off < run->dynfile->size; off++) {
-        if (isdigit(run->dynfile->data[off])) {
-            break;
-        }
-    }
-    size_t left = run->dynfile->size - off;
-    if (left == 0) {
-        return;
-    }
+  size_t len = util_rndGet(2, 8);
 
-    size_t   len = 0;
-    uint64_t val = 0;
-    /* 20 is maximum lenght of a string representing a 64-bit unsigned value */
-    for (len = 0; (len < 20) && (len < left); len++) {
-        char c = run->dynfile->data[off + len];
-        if (!isdigit(c)) {
-            break;
-        }
-        val *= 10;
-        val += (c - '0');
-    }
+  char buf[20];
+  snprintf(buf, sizeof(buf), "%-19" PRId64, (int64_t)util_rnd64());
 
-    switch (util_rndGet(0, 7)) {
-        case 0:
-            val++;
-            break;
-        case 1:
-            val--;
-            break;
-        case 2:
-            val *= 2;
-            break;
-        case 3:
-            val /= 2;
-            break;
-        case 4:
-            val = util_rnd64();
-            break;
-        case 5:
-            val += util_rndGet(1, 256);
-            break;
-        case 6:
-            val -= util_rndGet(1, 256);
-            break;
-        case 7:
-            val = ~(val);
-            break;
-        default:
-            LOG_F("Invalid choice");
-    };
-
-    char buf[20];
-    snprintf(buf, sizeof(buf), "%-19" PRIu64, val);
-
-    mangle_UseValueAt(run, off, (const uint8_t*)buf, len, printable);
-}
-
-static void mangle_Splice(run_t* run, bool printable) {
-    if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) {
-        mangle_Bytes(run, printable);
-        return;
-    }
+  mangle_UseValue(run, (const uint8_t *)buf, len, printable);
 
-    size_t         sz  = 0;
-    const uint8_t* buf = input_getRandomInputAsBuf(run, &sz);
-    if (!buf) {
-        LOG_E("input_getRandomInputAsBuf() returned no input");
-        mangle_Bytes(run, printable);
-        return;
-    }
-    if (!sz) {
-        mangle_Bytes(run, printable);
-        return;
-    }
+}
 
-    size_t remoteOff = mangle_getLen(sz) - 1;
-    size_t len       = mangle_getLen(sz - remoteOff);
-    mangle_UseValue(run, &buf[remoteOff], len, printable);
-}
-
-static void mangle_Resize(run_t* run, bool printable) {
-    ssize_t oldsz = run->dynfile->size;
-    ssize_t newsz = 0;
-
-    uint64_t choice = util_rndGet(0, 32);
-    switch (choice) {
-        case 0: /* Set new size arbitrarily */
-            newsz = (ssize_t)util_rndGet(1, run->global->mutate.maxInputSz);
-            break;
-        case 1 ... 4: /* Increase size by a small value */
-            newsz = oldsz + (ssize_t)util_rndGet(0, 8);
-            break;
-        case 5: /* Increase size by a larger value */
-            newsz = oldsz + (ssize_t)util_rndGet(9, 128);
-            break;
-        case 6 ... 9: /* Decrease size by a small value */
-            newsz = oldsz - (ssize_t)util_rndGet(0, 8);
-            break;
-        case 10: /* Decrease size by a larger value */
-            newsz = oldsz - (ssize_t)util_rndGet(9, 128);
-            break;
-        case 11 ... 32: /* Do nothing */
-            newsz = oldsz;
-            break;
-        default:
-            LOG_F("Illegal value from util_rndGet: %" PRIu64, choice);
-            break;
-    }
-    if (newsz < 1) {
-        newsz = 1;
-    }
-    if (newsz > (ssize_t)run->global->mutate.maxInputSz) {
-        newsz = run->global->mutate.maxInputSz;
-    }
+static void mangle_ASCIINumChange(run_t *run, bool printable) {
+
+  size_t off = mangle_getOffSet(run);
+
+  /* Find a digit */
+  for (; off < run->dynfile->size; off++) {
+
+    if (isdigit(run->dynfile->data[off])) { break; }
+
+  }
+
+  size_t left = run->dynfile->size - off;
+  if (left == 0) { return; }
+
+  size_t   len = 0;
+  uint64_t val = 0;
+  /* 20 is maximum lenght of a string representing a 64-bit unsigned value */
+  for (len = 0; (len < 20) && (len < left); len++) {
+
+    char c = run->dynfile->data[off + len];
+    if (!isdigit(c)) { break; }
+    val *= 10;
+    val += (c - '0');
+
+  }
+
+  switch (util_rndGet(0, 7)) {
+
+    case 0:
+      val++;
+      break;
+    case 1:
+      val--;
+      break;
+    case 2:
+      val *= 2;
+      break;
+    case 3:
+      val /= 2;
+      break;
+    case 4:
+      val = util_rnd64();
+      break;
+    case 5:
+      val += util_rndGet(1, 256);
+      break;
+    case 6:
+      val -= util_rndGet(1, 256);
+      break;
+    case 7:
+      val = ~(val);
+      break;
+    default:
+      LOG_F("Invalid choice");
+
+  };
+
+  char buf[20];
+  snprintf(buf, sizeof(buf), "%-19" PRIu64, val);
+
+  mangle_UseValueAt(run, off, (const uint8_t *)buf, len, printable);
 
-    input_setSize(run, (size_t)newsz);
-    if (newsz > oldsz) {
-        if (printable) {
-            memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz);
-        }
-    }
 }
 
-void mangle_mangleContent(run_t* run, int speed_factor) {
-    static void (*const mangleFuncs[])(run_t * run, bool printable) = {
-        mangle_Shrink,
-        mangle_Expand,
-        mangle_Bit,
-        mangle_IncByte,
-        mangle_DecByte,
-        mangle_NegByte,
-        mangle_AddSub,
-        mangle_MemSet,
-        mangle_MemClr,
-        mangle_MemSwap,
-        mangle_MemCopy,
-        mangle_Bytes,
-        mangle_ASCIINum,
-        mangle_ASCIINumChange,
-        mangle_ByteRepeat,
-        mangle_Magic,
-        mangle_StaticDict,
-        mangle_ConstFeedbackDict,
-        mangle_RandomBuf,
-        mangle_Splice,
-    };
-
-    if (run->mutationsPerRun == 0U) {
-        return;
-    }
-    if (run->dynfile->size == 0U) {
-        mangle_Resize(run, /* printable= */ run->global->cfg.only_printable);
+static void mangle_Splice(run_t *run, bool printable) {
+
+  if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) {
+
+    mangle_Bytes(run, printable);
+    return;
+
+  }
+
+  size_t         sz = 0;
+  const uint8_t *buf = input_getRandomInputAsBuf(run, &sz);
+  if (!buf) {
+
+    LOG_E("input_getRandomInputAsBuf() returned no input");
+    mangle_Bytes(run, printable);
+    return;
+
+  }
+
+  if (!sz) {
+
+    mangle_Bytes(run, printable);
+    return;
+
+  }
+
+  size_t remoteOff = mangle_getLen(sz) - 1;
+  size_t len = mangle_getLen(sz - remoteOff);
+  mangle_UseValue(run, &buf[remoteOff], len, printable);
+
+}
+
+static void mangle_Resize(run_t *run, bool printable) {
+
+  ssize_t oldsz = run->dynfile->size;
+  ssize_t newsz = 0;
+
+  uint64_t choice = util_rndGet(0, 32);
+  switch (choice) {
+
+    case 0:                                     /* Set new size arbitrarily */
+      newsz = (ssize_t)util_rndGet(1, run->global->mutate.maxInputSz);
+      break;
+    case 1 ... 4:                         /* Increase size by a small value */
+      newsz = oldsz + (ssize_t)util_rndGet(0, 8);
+      break;
+    case 5:                              /* Increase size by a larger value */
+      newsz = oldsz + (ssize_t)util_rndGet(9, 128);
+      break;
+    case 6 ... 9:                         /* Decrease size by a small value */
+      newsz = oldsz - (ssize_t)util_rndGet(0, 8);
+      break;
+    case 10:                             /* Decrease size by a larger value */
+      newsz = oldsz - (ssize_t)util_rndGet(9, 128);
+      break;
+    case 11 ... 32:                                           /* Do nothing */
+      newsz = oldsz;
+      break;
+    default:
+      LOG_F("Illegal value from util_rndGet: %" PRIu64, choice);
+      break;
+
+  }
+
+  if (newsz < 1) { newsz = 1; }
+  if (newsz > (ssize_t)run->global->mutate.maxInputSz) {
+
+    newsz = run->global->mutate.maxInputSz;
+
+  }
+
+  input_setSize(run, (size_t)newsz);
+  if (newsz > oldsz) {
+
+    if (printable) { memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz); }
+
+  }
+
+}
+
+void mangle_mangleContent(run_t *run, int speed_factor) {
+
+  static void (*const mangleFuncs[])(run_t * run, bool printable) = {
+
+      mangle_Shrink,    mangle_Expand,         mangle_Bit,
+      mangle_IncByte,   mangle_DecByte,        mangle_NegByte,
+      mangle_AddSub,    mangle_MemSet,         mangle_MemClr,
+      mangle_MemSwap,   mangle_MemCopy,        mangle_Bytes,
+      mangle_ASCIINum,  mangle_ASCIINumChange, mangle_ByteRepeat,
+      mangle_Magic,     mangle_StaticDict,     mangle_ConstFeedbackDict,
+      mangle_RandomBuf, mangle_Splice,
+
+  };
+
+  if (run->mutationsPerRun == 0U) { return; }
+  if (run->dynfile->size == 0U) {
+
+    mangle_Resize(run, /* printable= */ run->global->cfg.only_printable);
+
+  }
+
+  uint64_t changesCnt = run->global->mutate.mutationsPerRun;
+
+  if (speed_factor < 5) {
+
+    changesCnt = util_rndGet(1, run->global->mutate.mutationsPerRun);
+
+  } else if (speed_factor < 10) {
+
+    changesCnt = run->global->mutate.mutationsPerRun;
+
+  } else {
+
+    changesCnt = HF_MIN(speed_factor, 10);
+    changesCnt = HF_MAX(changesCnt, (run->global->mutate.mutationsPerRun * 5));
+
+  }
+
+  /* If last coverage acquisition was more than 5 secs ago, use splicing more
+   * frequently */
+  if ((time(NULL) - ATOMIC_GET(run->global->timing.lastCovUpdate)) > 5) {
+
+    if (util_rnd64() & 0x1) {
+
+      mangle_Splice(run, run->global->cfg.only_printable);
+
     }
 
-    uint64_t changesCnt = run->global->mutate.mutationsPerRun;
+  }
+
+  for (uint64_t x = 0; x < changesCnt; x++) {
+
+    if (run->global->feedback.cmpFeedback && (util_rnd64() & 0x1)) {
+
+      /*
+       * mangle_ConstFeedbackDict() is quite powerful if the dynamic feedback
+       * dictionary exists. If so, give it 50% chance of being used among all
+       * mangling functions.
+       */
+      mangle_ConstFeedbackDict(
+          run, /* printable= */ run->global->cfg.only_printable);
 
-    if (speed_factor < 5) {
-        changesCnt = util_rndGet(1, run->global->mutate.mutationsPerRun);
-    } else if (speed_factor < 10) {
-        changesCnt = run->global->mutate.mutationsPerRun;
     } else {
-        changesCnt = HF_MIN(speed_factor, 10);
-        changesCnt = HF_MAX(changesCnt, (run->global->mutate.mutationsPerRun * 5));
-    }
 
-    /* If last coverage acquisition was more than 5 secs ago, use splicing more frequently */
-    if ((time(NULL) - ATOMIC_GET(run->global->timing.lastCovUpdate)) > 5) {
-        if (util_rnd64() & 0x1) {
-            mangle_Splice(run, run->global->cfg.only_printable);
-        }
-    }
+      uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1);
+      mangleFuncs[choice](run,
+                          /* printable= */ run->global->cfg.only_printable);
 
-    for (uint64_t x = 0; x < changesCnt; x++) {
-        if (run->global->feedback.cmpFeedback && (util_rnd64() & 0x1)) {
-            /*
-             * mangle_ConstFeedbackDict() is quite powerful if the dynamic feedback dictionary
-             * exists. If so, give it 50% chance of being used among all mangling functions.
-             */
-            mangle_ConstFeedbackDict(run, /* printable= */ run->global->cfg.only_printable);
-        } else {
-            uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1);
-            mangleFuncs[choice](run, /* printable= */ run->global->cfg.only_printable);
-        }
     }
 
-    wmb();
+  }
+
+  wmb();
+
 }
+
diff --git a/custom_mutators/libafl_base/Cargo.toml b/custom_mutators/libafl_base/Cargo.toml
index 6e40fc39..ac6b0c8f 100644
--- a/custom_mutators/libafl_base/Cargo.toml
+++ b/custom_mutators/libafl_base/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "62614ce1016c86e3f00f35b56399292ceabd486b" }
+libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "266677bb88abe75165430f34e7de897c35560504" }
 custom_mutator = { path = "../rust/custom_mutator", features = ["afl_internals"] }
 serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
 
diff --git a/custom_mutators/libafl_base/src/lib.rs b/custom_mutators/libafl_base/src/lib.rs
index 6f2db8ca..bae11e1f 100644
--- a/custom_mutators/libafl_base/src/lib.rs
+++ b/custom_mutators/libafl_base/src/lib.rs
@@ -1,5 +1,4 @@
 #![cfg(unix)]
-#![allow(unused_variables)]
 
 use serde::{Deserialize, Deserializer, Serialize, Serializer};
 use std::{
@@ -18,10 +17,12 @@ use libafl::{
         scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
         Mutator,
     },
-    state::{HasCorpus, HasMaxSize, HasMetadata, HasRand, State},
+    prelude::UsesInput,
+    state::{HasCorpus, HasMaxSize, HasMetadata, HasRand, State, UsesState},
     Error,
 };
 
+#[allow(clippy::identity_op)]
 const MAX_FILE: usize = 1 * 1024 * 1024;
 
 static mut AFL: Option<&'static afl_state> = None;
@@ -64,24 +65,32 @@ impl<'de> Deserialize<'de> for AFLCorpus {
     }
 }
 
-impl Corpus<BytesInput> for AFLCorpus {
+impl UsesState for AFLCorpus {
+    type State = AFLState;
+}
+
+impl Corpus for AFLCorpus {
     #[inline]
     fn count(&self) -> usize {
         afl().queued_items as usize
     }
 
     #[inline]
-    fn add(&mut self, testcase: Testcase<BytesInput>) -> Result<usize, Error> {
+    fn add(&mut self, _testcase: Testcase<BytesInput>) -> Result<usize, Error> {
         unimplemented!();
     }
 
     #[inline]
-    fn replace(&mut self, idx: usize, testcase: Testcase<BytesInput>) -> Result<(), Error> {
+    fn replace(
+        &mut self,
+        _idx: usize,
+        _testcase: Testcase<BytesInput>,
+    ) -> Result<Testcase<Self::Input>, Error> {
         unimplemented!();
     }
 
     #[inline]
-    fn remove(&mut self, idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> {
+    fn remove(&mut self, _idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> {
         unimplemented!();
     }
 
@@ -92,7 +101,7 @@ impl Corpus<BytesInput> for AFLCorpus {
             entries.entry(idx).or_insert_with(|| {
                 let queue_buf = std::slice::from_raw_parts_mut(afl().queue_buf, self.count());
                 let entry = queue_buf[idx].as_mut().unwrap();
-                let fname = CStr::from_ptr((entry.fname as *mut i8).as_ref().unwrap())
+                let fname = CStr::from_ptr((entry.fname.cast::<i8>()).as_ref().unwrap())
                     .to_str()
                     .unwrap()
                     .to_owned();
@@ -127,9 +136,10 @@ pub struct AFLState {
 }
 
 impl AFLState {
+    #[must_use]
     pub fn new(seed: u32) -> Self {
         Self {
-            rand: StdRand::with_seed(seed as u64),
+            rand: StdRand::with_seed(u64::from(seed)),
             corpus: AFLCorpus::default(),
             metadata: SerdeAnyMap::new(),
             max_size: MAX_FILE,
@@ -153,7 +163,11 @@ impl HasRand for AFLState {
     }
 }
 
-impl HasCorpus<BytesInput> for AFLState {
+impl UsesInput for AFLState {
+    type Input = BytesInput;
+}
+
+impl HasCorpus for AFLState {
     type Corpus = AFLCorpus;
 
     #[inline]
@@ -208,7 +222,7 @@ impl CustomMutator for LibAFLBaseCustomMutator {
                 tokens.push(data.to_vec());
             }
             if !tokens.is_empty() {
-                state.add_metadata(Tokens::new(tokens));
+                state.add_metadata(Tokens::from(tokens));
             }
             Ok(Self {
                 state,
@@ -220,7 +234,7 @@ impl CustomMutator for LibAFLBaseCustomMutator {
     fn fuzz<'b, 's: 'b>(
         &'s mut self,
         buffer: &'b mut [u8],
-        add_buff: Option<&[u8]>,
+        _add_buff: Option<&[u8]>,
         max_size: usize,
     ) -> Result<Option<&'b [u8]>, Self::Error> {
         self.state.set_max_size(max_size);
diff --git a/custom_mutators/radamsa/custom_mutator_helpers.h b/custom_mutators/radamsa/custom_mutator_helpers.h
deleted file mode 120000
index f7532ef9..00000000
--- a/custom_mutators/radamsa/custom_mutator_helpers.h
+++ /dev/null
@@ -1 +0,0 @@
-../examples/custom_mutator_helpers.h
\ No newline at end of file
diff --git a/custom_mutators/radamsa/radamsa-mutator.c b/custom_mutators/radamsa/radamsa-mutator.c
index 624ace3d..466bb5c3 100644
--- a/custom_mutators/radamsa/radamsa-mutator.c
+++ b/custom_mutators/radamsa/radamsa-mutator.c
@@ -1,6 +1,5 @@
 // This simple example just creates random buffer <= 100 filled with 'A'
 // needs -I /path/to/AFLplusplus/include
-//#include "custom_mutator_helpers.h"
 
 #include <stdint.h>
 #include <stdlib.h>
@@ -8,19 +7,17 @@
 #include <stdio.h>
 
 #include "radamsa.h"
-#include "custom_mutator_helpers.h"
+#include "afl-fuzz.h"
 
 typedef struct my_mutator {
 
-  afl_t *afl;
-
-  u8 *mutator_buf;
-
+  afl_state_t *afl;
+  u8          *mutator_buf;
   unsigned int seed;
 
 } my_mutator_t;
 
-my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
+my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
 
   srand(seed);
   my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
diff --git a/custom_mutators/rust/custom_mutator-sys/Cargo.toml b/custom_mutators/rust/custom_mutator-sys/Cargo.toml
index 104f7df0..e38c972e 100644
--- a/custom_mutators/rust/custom_mutator-sys/Cargo.toml
+++ b/custom_mutators/rust/custom_mutator-sys/Cargo.toml
@@ -1,12 +1,12 @@
 [package]
 name = "custom_mutator-sys"
-version = "0.1.0"
+version = "0.1.1"
 authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
-edition = "2018"
+edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
 
 [build-dependencies]
-bindgen = "0.56"
+bindgen = "0.63"
diff --git a/custom_mutators/rust/custom_mutator-sys/build.rs b/custom_mutators/rust/custom_mutator-sys/build.rs
index 3c88a90d..ba4390ff 100644
--- a/custom_mutators/rust/custom_mutator-sys/build.rs
+++ b/custom_mutators/rust/custom_mutator-sys/build.rs
@@ -15,8 +15,8 @@ fn main() {
         // The input header we would like to generate
         // bindings for.
         .header("wrapper.h")
-        .whitelist_type("afl_state_t")
-        .blacklist_type(r"u\d+")
+        .allowlist_type("afl_state_t")
+        .blocklist_type(r"u\d+")
         .opaque_type(r"_.*")
         .opaque_type("FILE")
         .opaque_type("in_addr(_t)?")
diff --git a/custom_mutators/rust/custom_mutator-sys/src/lib.rs b/custom_mutators/rust/custom_mutator-sys/src/lib.rs
index a38a13a8..719ac994 100644
--- a/custom_mutators/rust/custom_mutator-sys/src/lib.rs
+++ b/custom_mutators/rust/custom_mutator-sys/src/lib.rs
@@ -1,5 +1,7 @@
 #![allow(non_upper_case_globals)]
 #![allow(non_camel_case_types)]
 #![allow(non_snake_case)]
+#![allow(clippy::too_many_lines)]
+#![allow(clippy::used_underscore_binding)]
 
 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
diff --git a/custom_mutators/rust/custom_mutator/Cargo.toml b/custom_mutators/rust/custom_mutator/Cargo.toml
index 2d3cdbfa..30f764dc 100644
--- a/custom_mutators/rust/custom_mutator/Cargo.toml
+++ b/custom_mutators/rust/custom_mutator/Cargo.toml
@@ -2,7 +2,7 @@
 name = "custom_mutator"
 version = "0.1.0"
 authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
-edition = "2018"
+edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
diff --git a/custom_mutators/rust/custom_mutator/src/lib.rs b/custom_mutators/rust/custom_mutator/src/lib.rs
index f872241e..3b635eb5 100644
--- a/custom_mutators/rust/custom_mutator/src/lib.rs
+++ b/custom_mutators/rust/custom_mutator/src/lib.rs
@@ -20,7 +20,7 @@
 //! This binding is panic-safe in that it will prevent panics from unwinding into AFL++. Any panic will `abort` at the boundary between the custom mutator and AFL++.
 //!
 //! # Access to AFL++ internals
-//! This crate has an optional feature "afl_internals", which gives access to AFL++'s internal state.
+//! This crate has an optional feature "`afl_internals`", which gives access to AFL++'s internal state.
 //! The state is passed to [`CustomMutator::init`], when the feature is activated.
 //!
 //! _This is completely unsafe and uses automatically generated types extracted from the AFL++ source._
@@ -115,7 +115,7 @@ pub mod wrappers {
     impl<M: RawCustomMutator> FFIContext<M> {
         fn from(ptr: *mut c_void) -> ManuallyDrop<Box<Self>> {
             assert!(!ptr.is_null());
-            ManuallyDrop::new(unsafe { Box::from_raw(ptr as *mut Self) })
+            ManuallyDrop::new(unsafe { Box::from_raw(ptr.cast::<Self>()) })
         }
 
         fn into_ptr(self: Box<Self>) -> *const c_void {
@@ -141,27 +141,28 @@ pub mod wrappers {
     }
 
     /// panic handler called for every panic
-    fn panic_handler(method: &str, panic_info: Box<dyn Any + Send + 'static>) -> ! {
+    fn panic_handler(method: &str, panic_info: &Box<dyn Any + Send + 'static>) -> ! {
         use std::ops::Deref;
-        let cause = panic_info
-            .downcast_ref::<String>()
-            .map(String::deref)
-            .unwrap_or_else(|| {
+        let cause = panic_info.downcast_ref::<String>().map_or_else(
+            || {
                 panic_info
                     .downcast_ref::<&str>()
                     .copied()
                     .unwrap_or("<cause unknown>")
-            });
-        eprintln!("A panic occurred at {}: {}", method, cause);
+            },
+            String::deref,
+        );
+        eprintln!("A panic occurred at {method}: {cause}");
         abort()
     }
 
     /// Internal function used in the macro
     #[cfg(not(feature = "afl_internals"))]
+    #[must_use]
     pub fn afl_custom_init_<M: RawCustomMutator>(seed: u32) -> *const c_void {
         match catch_unwind(|| FFIContext::<M>::new(seed).into_ptr()) {
             Ok(ret) => ret,
-            Err(err) => panic_handler("afl_custom_init", err),
+            Err(err) => panic_handler("afl_custom_init", &err),
         }
     }
 
@@ -176,7 +177,7 @@ pub mod wrappers {
             FFIContext::<M>::new(afl, seed).into_ptr()
         }) {
             Ok(ret) => ret,
-            Err(err) => panic_handler("afl_custom_init", err),
+            Err(err) => panic_handler("afl_custom_init", &err),
         }
     }
 
@@ -196,32 +197,27 @@ pub mod wrappers {
     ) -> usize {
         match catch_unwind(|| {
             let mut context = FFIContext::<M>::from(data);
-            if buf.is_null() {
-                panic!("null buf passed to afl_custom_fuzz")
-            }
-            if out_buf.is_null() {
-                panic!("null out_buf passed to afl_custom_fuzz")
-            }
+
+            assert!(!buf.is_null(), "null buf passed to afl_custom_fuzz");
+            assert!(!out_buf.is_null(), "null out_buf passed to afl_custom_fuzz");
+
             let buff_slice = slice::from_raw_parts_mut(buf, buf_size);
             let add_buff_slice = if add_buf.is_null() {
                 None
             } else {
                 Some(slice::from_raw_parts(add_buf, add_buf_size))
             };
-            match context.mutator.fuzz(buff_slice, add_buff_slice, max_size) {
-                Some(buffer) => {
-                    *out_buf = buffer.as_ptr();
-                    buffer.len()
-                }
-                None => {
-                    // return the input buffer with 0-length to let AFL skip this mutation attempt
-                    *out_buf = buf;
-                    0
-                }
+            if let Some(buffer) = context.mutator.fuzz(buff_slice, add_buff_slice, max_size) {
+                *out_buf = buffer.as_ptr();
+                buffer.len()
+            } else {
+                // return the input buffer with 0-length to let AFL skip this mutation attempt
+                *out_buf = buf;
+                0
             }
         }) {
             Ok(ret) => ret,
-            Err(err) => panic_handler("afl_custom_fuzz", err),
+            Err(err) => panic_handler("afl_custom_fuzz", &err),
         }
     }
 
@@ -237,9 +233,8 @@ pub mod wrappers {
     ) -> u32 {
         match catch_unwind(|| {
             let mut context = FFIContext::<M>::from(data);
-            if buf.is_null() {
-                panic!("null buf passed to afl_custom_fuzz")
-            }
+            assert!(!buf.is_null(), "null buf passed to afl_custom_fuzz");
+
             let buf_slice = slice::from_raw_parts(buf, buf_size);
             // see https://doc.rust-lang.org/nomicon/borrow-splitting.html
             let ctx = &mut **context;
@@ -247,37 +242,39 @@ pub mod wrappers {
             mutator.fuzz_count(buf_slice)
         }) {
             Ok(ret) => ret,
-            Err(err) => panic_handler("afl_custom_fuzz_count", err),
+            Err(err) => panic_handler("afl_custom_fuzz_count", &err),
         }
     }
 
     /// Internal function used in the macro
-    pub fn afl_custom_queue_new_entry_<M: RawCustomMutator>(
+    pub unsafe fn afl_custom_queue_new_entry_<M: RawCustomMutator>(
         data: *mut c_void,
         filename_new_queue: *const c_char,
         filename_orig_queue: *const c_char,
     ) -> bool {
         match catch_unwind(|| {
             let mut context = FFIContext::<M>::from(data);
-            if filename_new_queue.is_null() {
-                panic!("received null filename_new_queue in afl_custom_queue_new_entry");
-            }
+            assert!(
+                !filename_new_queue.is_null(),
+                "received null filename_new_queue in afl_custom_queue_new_entry"
+            );
+
             let filename_new_queue = Path::new(OsStr::from_bytes(
                 unsafe { CStr::from_ptr(filename_new_queue) }.to_bytes(),
             ));
-            let filename_orig_queue = if !filename_orig_queue.is_null() {
+            let filename_orig_queue = if filename_orig_queue.is_null() {
+                None
+            } else {
                 Some(Path::new(OsStr::from_bytes(
                     unsafe { CStr::from_ptr(filename_orig_queue) }.to_bytes(),
                 )))
-            } else {
-                None
             };
             context
                 .mutator
                 .queue_new_entry(filename_new_queue, filename_orig_queue)
         }) {
             Ok(ret) => ret,
-            Err(err) => panic_handler("afl_custom_queue_new_entry", err),
+            Err(err) => panic_handler("afl_custom_queue_new_entry", &err),
         }
     }
 
@@ -292,7 +289,7 @@ pub mod wrappers {
             ManuallyDrop::into_inner(FFIContext::<M>::from(data));
         }) {
             Ok(ret) => ret,
-            Err(err) => panic_handler("afl_custom_deinit", err),
+            Err(err) => panic_handler("afl_custom_deinit", &err),
         }
     }
 
@@ -306,13 +303,13 @@ pub mod wrappers {
                 buf.extend_from_slice(res.as_bytes());
                 buf.push(0);
                 // unwrapping here, as the error case should be extremely rare
-                CStr::from_bytes_with_nul(&buf).unwrap().as_ptr()
+                CStr::from_bytes_with_nul(buf).unwrap().as_ptr()
             } else {
                 null()
             }
         }) {
             Ok(ret) => ret,
-            Err(err) => panic_handler("afl_custom_introspection", err),
+            Err(err) => panic_handler("afl_custom_introspection", &err),
         }
     }
 
@@ -329,18 +326,18 @@ pub mod wrappers {
                 buf.extend_from_slice(res.as_bytes());
                 buf.push(0);
                 // unwrapping here, as the error case should be extremely rare
-                CStr::from_bytes_with_nul(&buf).unwrap().as_ptr()
+                CStr::from_bytes_with_nul(buf).unwrap().as_ptr()
             } else {
                 null()
             }
         }) {
             Ok(ret) => ret,
-            Err(err) => panic_handler("afl_custom_describe", err),
+            Err(err) => panic_handler("afl_custom_describe", &err),
         }
     }
 
     /// Internal function used in the macro
-    pub fn afl_custom_queue_get_<M: RawCustomMutator>(
+    pub unsafe fn afl_custom_queue_get_<M: RawCustomMutator>(
         data: *mut c_void,
         filename: *const c_char,
     ) -> u8 {
@@ -348,12 +345,12 @@ pub mod wrappers {
             let mut context = FFIContext::<M>::from(data);
             assert!(!filename.is_null());
 
-            context.mutator.queue_get(Path::new(OsStr::from_bytes(
+            u8::from(context.mutator.queue_get(Path::new(OsStr::from_bytes(
                 unsafe { CStr::from_ptr(filename) }.to_bytes(),
-            ))) as u8
+            ))))
         }) {
             Ok(ret) => ret,
-            Err(err) => panic_handler("afl_custom_queue_get", err),
+            Err(err) => panic_handler("afl_custom_queue_get", &err),
         }
     }
 }
@@ -373,7 +370,7 @@ macro_rules! _define_afl_custom_init {
     };
 }
 
-/// An exported macro to defined afl_custom_init meant for insternal usage
+/// An exported macro to defined `afl_custom_init` meant for internal usage
 #[cfg(not(feature = "afl_internals"))]
 #[macro_export]
 macro_rules! _define_afl_custom_init {
@@ -444,7 +441,7 @@ macro_rules! export_mutator {
         }
 
         #[no_mangle]
-        pub extern "C" fn afl_custom_queue_new_entry(
+        pub unsafe extern "C" fn afl_custom_queue_new_entry(
             data: *mut ::std::os::raw::c_void,
             filename_new_queue: *const ::std::os::raw::c_char,
             filename_orig_queue: *const ::std::os::raw::c_char,
@@ -457,7 +454,7 @@ macro_rules! export_mutator {
         }
 
         #[no_mangle]
-        pub extern "C" fn afl_custom_queue_get(
+        pub unsafe extern "C" fn afl_custom_queue_get(
             data: *mut ::std::os::raw::c_void,
             filename: *const ::std::os::raw::c_char,
         ) -> u8 {
@@ -520,9 +517,10 @@ mod sanity_test {
     export_mutator!(ExampleMutator);
 }
 
-#[allow(unused_variables)]
 /// A custom mutator.
 /// [`CustomMutator::handle_error`] will be called in case any method returns an [`Result::Err`].
+#[allow(unused_variables)]
+#[allow(clippy::missing_errors_doc)]
 pub trait CustomMutator {
     /// The error type. All methods must return the same error type.
     type Error: Debug;
@@ -537,7 +535,7 @@ pub trait CustomMutator {
             .map(|v| !v.is_empty())
             .unwrap_or(false)
         {
-            eprintln!("Error in custom mutator: {:?}", err)
+            eprintln!("Error in custom mutator: {err:?}");
         }
     }
 
@@ -759,8 +757,7 @@ mod truncate_test {
             let actual_output = truncate_str_unicode_safe(input, *max_len);
             assert_eq!(
                 &actual_output, expected_output,
-                "{:#?} truncated to {} bytes should be {:#?}, but is {:#?}",
-                input, max_len, expected_output, actual_output
+                "{input:#?} truncated to {max_len} bytes should be {expected_output:#?}, but is {actual_output:#?}"
             );
         }
     }
diff --git a/custom_mutators/rust/example/Cargo.toml b/custom_mutators/rust/example/Cargo.toml
index 070d23b1..9d53ebe5 100644
--- a/custom_mutators/rust/example/Cargo.toml
+++ b/custom_mutators/rust/example/Cargo.toml
@@ -2,7 +2,7 @@
 name = "example_mutator"
 version = "0.1.0"
 authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
-edition = "2018"
+edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
diff --git a/custom_mutators/rust/example_lain/Cargo.toml b/custom_mutators/rust/example_lain/Cargo.toml
index 29d606a4..c52bf86f 100644
--- a/custom_mutators/rust/example_lain/Cargo.toml
+++ b/custom_mutators/rust/example_lain/Cargo.toml
@@ -2,7 +2,7 @@
 name = "example_lain"
 version = "0.1.0"
 authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
-edition = "2018"
+edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html