about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDominik Maier <domenukk@gmail.com>2020-03-23 18:18:54 +0100
committerDominik Maier <domenukk@gmail.com>2020-03-23 18:18:54 +0100
commit77b81e7361f7286cc3e0174b87ae5facb9f1290d (patch)
tree1289a776f96b7af6fed7b1c61509368de14aeb46
parent83f925ccc9c871998f9d7a905387fd83f8e3f4af (diff)
downloadafl++-77b81e7361f7286cc3e0174b87ae5facb9f1290d.tar.gz
custom mutators might work again like this
-rw-r--r--examples/custom_mutators/custom_mutator_helpers.h74
-rw-r--r--examples/custom_mutators/example.c76
-rw-r--r--include/afl-fuzz.h84
-rw-r--r--src/afl-fuzz-mutators.c80
-rw-r--r--src/afl-fuzz-python.c240
5 files changed, 330 insertions, 224 deletions
diff --git a/examples/custom_mutators/custom_mutator_helpers.h b/examples/custom_mutators/custom_mutator_helpers.h
index 53ecf960..844ccf94 100644
--- a/examples/custom_mutators/custom_mutator_helpers.h
+++ b/examples/custom_mutators/custom_mutator_helpers.h
@@ -5,7 +5,9 @@
 #include "types.h"
 #include <stdlib.h>
 
-#define LIMIT_RAND(limit) (rand() % (limit))
+#define RAND_BELOW(limit) (rand() % (limit))
+
+typedef struct{} afl_t;
 
 static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
 
@@ -13,13 +15,13 @@ static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
   static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
   static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
 
-  switch (LIMIT_RAND(12)) {
+  switch (RAND_BELOW(12)) {
 
     case 0: {
 
       /* Flip a single bit somewhere. Spooky! */
 
-      s32 bit_idx = ((LIMIT_RAND(end - begin) + begin) << 3) + LIMIT_RAND(8);
+      s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8);
 
       out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7);
 
@@ -31,8 +33,8 @@ static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
 
       /* Set byte to interesting value. */
 
-      u8 val = interesting_8[LIMIT_RAND(sizeof(interesting_8))];
-      out_buf[(LIMIT_RAND(end - begin) + begin)] = val;
+      u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))];
+      out_buf[(RAND_BELOW(end - begin) + begin)] = val;
 
       break;
 
@@ -44,19 +46,19 @@ static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
 
       if (end - begin < 2) break;
 
-      s32 byte_idx = (LIMIT_RAND(end - begin) + begin);
+      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
 
       if (byte_idx >= end - 1) break;
 
-      switch (LIMIT_RAND(2)) {
+      switch (RAND_BELOW(2)) {
 
         case 0:
           *(u16 *)(out_buf + byte_idx) =
-              interesting_16[LIMIT_RAND(sizeof(interesting_16) >> 1)];
+              interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)];
           break;
         case 1:
           *(u16 *)(out_buf + byte_idx) =
-              SWAP16(interesting_16[LIMIT_RAND(sizeof(interesting_16) >> 1)]);
+              SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]);
           break;
 
       }
@@ -71,19 +73,19 @@ static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
 
       if (end - begin < 4) break;
 
-      s32 byte_idx = (LIMIT_RAND(end - begin) + begin);
+      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
 
       if (byte_idx >= end - 3) break;
 
-      switch (LIMIT_RAND(2)) {
+      switch (RAND_BELOW(2)) {
 
         case 0:
           *(u32 *)(out_buf + byte_idx) =
-              interesting_32[LIMIT_RAND(sizeof(interesting_32) >> 2)];
+              interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
           break;
         case 1:
           *(u32 *)(out_buf + byte_idx) =
-              SWAP32(interesting_32[LIMIT_RAND(sizeof(interesting_32) >> 2)]);
+              SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
           break;
 
       }
@@ -98,19 +100,19 @@ static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
 
       if (end - begin < 8) break;
 
-      s32 byte_idx = (LIMIT_RAND(end - begin) + begin);
+      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
 
       if (byte_idx >= end - 7) break;
 
-      switch (LIMIT_RAND(2)) {
+      switch (RAND_BELOW(2)) {
 
         case 0:
           *(u64 *)(out_buf + byte_idx) =
-              (s64)interesting_32[LIMIT_RAND(sizeof(interesting_32) >> 2)];
+              (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
           break;
         case 1:
           *(u64 *)(out_buf + byte_idx) =
-              SWAP64((s64)interesting_32[LIMIT_RAND(sizeof(interesting_32) >> 2)]);
+              SWAP64((s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
           break;
 
       }
@@ -123,7 +125,7 @@ static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
 
       /* Randomly subtract from byte. */
 
-      out_buf[(LIMIT_RAND(end - begin) + begin)] -= 1 + LIMIT_RAND(ARITH_MAX);
+      out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX);
 
       break;
 
@@ -133,7 +135,7 @@ static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
 
       /* Randomly add to byte. */
 
-      out_buf[(LIMIT_RAND(end - begin) + begin)] += 1 + LIMIT_RAND(ARITH_MAX);
+      out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX);
 
       break;
 
@@ -145,17 +147,17 @@ static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
 
       if (end - begin < 2) break;
 
-      s32 byte_idx = (LIMIT_RAND(end - begin) + begin);
+      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
 
       if (byte_idx >= end - 1) break;
 
-      if (LIMIT_RAND(2)) {
+      if (RAND_BELOW(2)) {
 
-        *(u16 *)(out_buf + byte_idx) -= 1 + LIMIT_RAND(ARITH_MAX);
+        *(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
 
       } else {
 
-        u16 num = 1 + LIMIT_RAND(ARITH_MAX);
+        u16 num = 1 + RAND_BELOW(ARITH_MAX);
 
         *(u16 *)(out_buf + byte_idx) =
             SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num);
@@ -172,17 +174,17 @@ static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
 
       if (end - begin < 2) break;
 
-      s32 byte_idx = (LIMIT_RAND(end - begin) + begin);
+      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
 
       if (byte_idx >= end - 1) break;
 
-      if (LIMIT_RAND(2)) {
+      if (RAND_BELOW(2)) {
 
-        *(u16 *)(out_buf + byte_idx) += 1 + LIMIT_RAND(ARITH_MAX);
+        *(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
 
       } else {
 
-        u16 num = 1 + LIMIT_RAND(ARITH_MAX);
+        u16 num = 1 + RAND_BELOW(ARITH_MAX);
 
         *(u16 *)(out_buf + byte_idx) =
             SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num);
@@ -199,17 +201,17 @@ static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
 
       if (end - begin < 4) break;
 
-      s32 byte_idx = (LIMIT_RAND(end - begin) + begin);
+      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
 
       if (byte_idx >= end - 3) break;
 
-      if (LIMIT_RAND(2)) {
+      if (RAND_BELOW(2)) {
 
-        *(u32 *)(out_buf + byte_idx) -= 1 + LIMIT_RAND(ARITH_MAX);
+        *(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
 
       } else {
 
-        u32 num = 1 + LIMIT_RAND(ARITH_MAX);
+        u32 num = 1 + RAND_BELOW(ARITH_MAX);
 
         *(u32 *)(out_buf + byte_idx) =
             SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num);
@@ -226,17 +228,17 @@ static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
 
       if (end - begin < 4) break;
 
-      s32 byte_idx = (LIMIT_RAND(end - begin) + begin);
+      s32 byte_idx = (RAND_BELOW(end - begin) + begin);
 
       if (byte_idx >= end - 3) break;
 
-      if (LIMIT_RAND(2)) {
+      if (RAND_BELOW(2)) {
 
-        *(u32 *)(out_buf + byte_idx) += 1 + LIMIT_RAND(ARITH_MAX);
+        *(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
 
       } else {
 
-        u32 num = 1 + LIMIT_RAND(ARITH_MAX);
+        u32 num = 1 + RAND_BELOW(ARITH_MAX);
 
         *(u32 *)(out_buf + byte_idx) =
             SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num);
@@ -253,7 +255,7 @@ static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
          why not. We use XOR with 1-255 to eliminate the
          possibility of a no-op. */
 
-      out_buf[(LIMIT_RAND(end - begin) + begin)] ^= 1 + LIMIT_RAND(255);
+      out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255);
 
       break;
 
diff --git a/examples/custom_mutators/example.c b/examples/custom_mutators/example.c
index 2787e218..560a5919 100644
--- a/examples/custom_mutators/example.c
+++ b/examples/custom_mutators/example.c
@@ -3,6 +3,7 @@
   Written by Khaled Yakdan <yakdan@code-intelligence.de>
              Andrea Fioraldi <andreafioraldi@gmail.com>
              Shengtuo Hu <h1994st@gmail.com>
+             Dominik Maier <mail@dmnk.co>
 */
 
 // You need to use -I /path/to/AFLplusplus/include
@@ -12,6 +13,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#define DATA_SIZE (100)
+
 static const char *commands[] = {
 
     "GET",
@@ -20,12 +23,36 @@ static const char *commands[] = {
 
 };
 
-static size_t data_size = 100;
 
-void afl_custom_init(unsigned int seed) {
+typedef struct my_mutator {
+
+  afl_t *afl;
+  // any additional data here!
+
+} my_mutator_t;
+
+/**
+ * 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!
+ *         Returns NULL on error.
+ */
+my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
 
   srand(seed); // needed also by surgical_havoc_mutate()
 
+  my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
+  if (!data) {
+    perror("afl_custom_init alloc");
+    return NULL;
+  }
+  data->afl = afl;
+
+  return data;
+
 }
 
 /**
@@ -33,6 +60,7 @@ void afl_custom_init(unsigned int seed) {
  *
  * (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[in] add_buf Buffer containing the additional test case
@@ -41,13 +69,14 @@ void afl_custom_init(unsigned int seed) {
  *     produce data larger than max_size.
  * @return Size of the mutated output.
  */
-size_t afl_custom_fuzz(uint8_t **buf, size_t buf_size, uint8_t *add_buf,
+size_t afl_custom_fuzz(my_mutator_t *data, uint8_t **buf, size_t buf_size,
+                       uint8_t *add_buf,
                        size_t add_buf_size,  // add_buf can be NULL
                        size_t max_size) {
 
   // Make sure that the packet size does not exceed the maximum size expected by
   // the fuzzer
-  size_t mutated_size = data_size <= max_size ? data_size : max_size;
+  size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size;
 
   if (mutated_size > buf_size) *buf = realloc(*buf, mutated_size);
 
@@ -59,10 +88,10 @@ size_t afl_custom_fuzz(uint8_t **buf, size_t buf_size, uint8_t *add_buf,
   // Mutate the payload of the packet
   int i;
   for (i = 0; i < 8; ++i) {
-  
+
     // Randomly perform one of the (no len modification) havoc mutations
     surgical_havoc_mutate(mutated_out, 3, mutated_size);
-  
+
   }
 
   return mutated_size;
@@ -76,6 +105,7 @@ size_t afl_custom_fuzz(uint8_t **buf, size_t buf_size, uint8_t *add_buf,
  * (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
@@ -83,7 +113,7 @@ size_t afl_custom_fuzz(uint8_t **buf, size_t buf_size, uint8_t *add_buf,
  *     will release the memory after saving the test case.
  * @return Size of the output buffer after processing
  */
-size_t afl_custom_pre_save(uint8_t *buf, size_t buf_size, uint8_t **out_buf) {
+size_t afl_custom_pre_save(my_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf) {
 
   size_t out_buf_size;
 
@@ -118,11 +148,12 @@ static int      cur_step;
  *
  * (Optional)
  *
+ * @param data pointer returned in afl_custom_init for this fuzz case
  * @param buf Buffer containing the test case
  * @param buf_size Size of the test case
  * @return The amount of possible iteration steps to trim the input
  */
-int afl_custom_init_trim(uint8_t *buf, size_t buf_size) {
+int afl_custom_init_trim(my_mutator_t *data, uint8_t *buf, size_t buf_size) {
 
   // We simply trim once
   trimmming_steps = 1;
@@ -146,12 +177,13 @@ int afl_custom_init_trim(uint8_t *buf, size_t buf_size) {
  *
  * (Optional)
  *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
  * @param[out] out_buf Pointer to the buffer containing the trimmed test case.
  *     External library should allocate memory for out_buf. AFL++ will release
  *     the memory after saving the test case.
  * @param[out] out_buf_size Pointer to the size of the trimmed test case
  */
-void afl_custom_trim(uint8_t **out_buf, size_t *out_buf_size) {
+void afl_custom_trim(my_mutator_t *data, uint8_t **out_buf, size_t *out_buf_size) {
 
   *out_buf_size = trim_buf_size - 1;
 
@@ -169,11 +201,12 @@ void afl_custom_trim(uint8_t **out_buf, size_t *out_buf_size) {
  *
  * (Optional)
  *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
  * @param success Indicates if the last trim operation was successful.
  * @return The next trim iteration index (from 0 to the maximum amount of
  *     steps returned in init_trim)
  */
-int afl_custom_post_trim(int success) {
+int afl_custom_post_trim(my_mutator_t *data, int success) {
 
   if (success) {
 
@@ -192,6 +225,7 @@ int afl_custom_post_trim(int success) {
  *
  * (Optional)
  *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
  * @param[inout] buf Pointer to the input data to be mutated and the mutated
  *     output
  * @param[in] buf_size Size of input data
@@ -199,7 +233,7 @@ int afl_custom_post_trim(int success) {
  *     not produce data larger than max_size.
  * @return Size of the mutated output.
  */
-size_t afl_custom_havoc_mutation(uint8_t **buf, size_t buf_size,
+size_t afl_custom_havoc_mutation(my_mutator_t *data, uint8_t **buf, size_t buf_size,
                                  size_t max_size) {
 
   if (buf_size == 0) {
@@ -223,9 +257,10 @@ size_t afl_custom_havoc_mutation(uint8_t **buf, size_t buf_size,
  *
  * (Optional)
  *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
  * @return The probability (0-100).
  */
-uint8_t afl_custom_havoc_mutation_probability(void) {
+uint8_t afl_custom_havoc_mutation_probability(my_mutator_t *data) {
 
   return 5;  // 5 %
 
@@ -236,11 +271,12 @@ uint8_t afl_custom_havoc_mutation_probability(void) {
  *
  * (Optional)
  *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
  * @param filename File name of the test case in the queue entry
  * @return Return True(1) if the fuzzer will fuzz the queue entry, and
  *     False(0) otherwise.
  */
-uint8_t afl_custom_queue_get(const uint8_t *filename) {
+uint8_t afl_custom_queue_get(my_mutator_t *data, const uint8_t *filename) {
 
   return 1;
 
@@ -252,13 +288,25 @@ uint8_t afl_custom_queue_get(const uint8_t *filename) {
  *
  * (Optional)
  *
+ * @param data pointer returned in afl_custom_init for this fuzz case
  * @param filename_new_queue File name of the new queue entry
  * @param filename_orig_queue File name of the original queue entry
  */
-void afl_custom_queue_new_entry(const uint8_t *filename_new_queue,
+void afl_custom_queue_new_entry(my_mutator_t *data, const uint8_t *filename_new_queue,
                                 const uint8_t *filename_orig_queue) {
 
   /* Additional analysis on the original or new test case */
 
 }
 
+/**
+ * Deinitialize everything
+ *
+ * @param data The data ptr from afl_custom_init
+ */
+void afl_custom_deinit(my_mutator_t *data) {
+
+  free(data);
+
+}
+
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 1a621625..7dddefb0 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -281,10 +281,20 @@ enum {
   /* 07 */ PY_FUNC_HAVOC_MUTATION_PROBABILITY,
   /* 08 */ PY_FUNC_QUEUE_GET,
   /* 09 */ PY_FUNC_QUEUE_NEW_ENTRY,
+  /* 10 */ PY_FUNC_DEINIT,
   PY_FUNC_COUNT
 
 };
 
+typedef struct py_mutator {
+
+  PyObject *py_module;
+  PyObject *py_functions[PY_FUNC_COUNT];
+  void *afl_state;
+  void *py_data;
+
+} py_mutator_t;
+
 #endif
 
 typedef struct MOpt_globals {
@@ -540,6 +550,9 @@ typedef struct afl_state {
 
   /* Custom mutators */
   struct custom_mutator *mutator;
+#ifdef USE_PYTHON
+  struct custom_mutator *py_mutator;
+#endif
 
   /* cmplog forkserver ids */
   s32 cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd;
@@ -548,12 +561,6 @@ typedef struct afl_state {
   u8 describe_op_buf_256[256]; /* describe_op will use this to return a string
                                   up to 256 */
 
-#ifdef USE_PYTHON
-  /* Python Mutators */
-  PyObject *py_module;
-  PyObject *py_functions[PY_FUNC_COUNT];
-#endif
-
 #ifdef _AFL_DOCUMENT_MUTATIONS
   u8  do_document;
   u32 document_counter;
@@ -585,22 +592,25 @@ struct custom_mutator {
   const char *name;
   void *      dh;
 
+  void *data;    /* custom mutator data ptr */
+
   /* hooks for the custom mutator function */
 
   /**
    * Initialize the custom mutator.
    *
-   * (Optional)
-   *
+   * @param afl AFL instance.
    * @param seed Seed used for the mutation.
+   * @return pointer to internal data or NULL on error
    */
-  void (*afl_custom_init)(afl_state_t *afl, unsigned int seed);
+  void *(*afl_custom_init)(afl_state_t *afl, unsigned int seed);
 
   /**
    * Perform custom mutations on a given input
    *
    * (Optional for now. Required in the future)
    *
+   * @param data pointer returned in afl_custom_init for this fuzz case
    * @param[inout] buf Pointer to the input data to be mutated and the mutated
    *     output
    * @param[in] buf_size Size of the input/output data
@@ -610,7 +620,7 @@ struct custom_mutator {
    * not produce data larger than max_size.
    * @return Size of the mutated output.
    */
-  size_t (*afl_custom_fuzz)(afl_state_t *afl, u8 **buf, size_t buf_size,
+  size_t (*afl_custom_fuzz)(void *data, u8 **buf, size_t buf_size,
                             u8 *add_buf, size_t add_buf_size, size_t max_size);
 
   /**
@@ -620,6 +630,7 @@ struct custom_mutator {
    * (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 of storing the test case after
@@ -627,7 +638,7 @@ struct custom_mutator {
    *     will release the memory after saving the test case.
    * @return Size of the output buffer after processing
    */
-  size_t (*afl_custom_pre_save)(afl_state_t *afl, u8 *buf, size_t buf_size,
+  size_t (*afl_custom_pre_save)(void *data, u8 *buf, size_t buf_size,
                                 u8 **out_buf);
 
   /**
@@ -646,11 +657,12 @@ struct custom_mutator {
    *
    * (Optional)
    *
+   * @param data pointer returned in afl_custom_init for this fuzz case
    * @param buf Buffer containing the test case
    * @param buf_size Size of the test case
    * @return The amount of possible iteration steps to trim the input
    */
-  u32 (*afl_custom_init_trim)(afl_state_t *afl, u8 *buf, size_t buf_size);
+  u32 (*afl_custom_init_trim)(void *data, u8 *buf, size_t buf_size);
 
   /**
    * This method is called for each trimming operation. It doesn't have any
@@ -663,12 +675,13 @@ struct custom_mutator {
    *
    * (Optional)
    *
+   * @param data pointer returned in afl_custom_init for this fuzz case
    * @param[out] out_buf Pointer to the buffer containing the trimmed test case.
    *     External library should allocate memory for out_buf. AFL++ will release
    *     the memory after saving the test case.
    * @param[out] out_buf_size Pointer to the size of the trimmed test case
    */
-  void (*afl_custom_trim)(afl_state_t *afl, u8 **out_buf, size_t *out_buf_size);
+  void (*afl_custom_trim)(void *data, u8 **out_buf, size_t *out_buf_size);
 
   /**
    * This method is called after each trim operation to inform you if your
@@ -677,11 +690,12 @@ struct custom_mutator {
    *
    * (Optional)
    *
+   * @param data pointer returned in afl_custom_init for this fuzz case
    * @param success Indicates if the last trim operation was successful.
    * @return The next trim iteration index (from 0 to the maximum amount of
    *     steps returned in init_trim)
    */
-  u32 (*afl_custom_post_trim)(afl_state_t *afl, u8 success);
+  u32 (*afl_custom_post_trim)(void *data, u8 success);
 
   /**
    * Perform a single custom mutation on a given input.
@@ -689,6 +703,7 @@ struct custom_mutator {
    *
    * (Optional)
    *
+   * @param data pointer returned in afl_custom_init for this fuzz case
    * @param[inout] buf Pointer to the input data to be mutated and the mutated
    *     output
    * @param[in] buf_size Size of input data
@@ -696,7 +711,7 @@ struct custom_mutator {
    *     not produce data larger than max_size.
    * @return Size of the mutated output.
    */
-  size_t (*afl_custom_havoc_mutation)(afl_state_t *afl, u8 **buf,
+  size_t (*afl_custom_havoc_mutation)(void *data, u8 **buf,
                                       size_t buf_size, size_t max_size);
 
   /**
@@ -705,20 +720,22 @@ struct custom_mutator {
    *
    * (Optional)
    *
+   * @param data pointer returned in afl_custom_init for this fuzz case
    * @return The probability (0-100).
    */
-  u8 (*afl_custom_havoc_mutation_probability)(afl_state_t *afl);
+  u8 (*afl_custom_havoc_mutation_probability)(void *data);
 
   /**
    * Determine whether the fuzzer should fuzz the current queue entry or not.
    *
    * (Optional)
    *
+   * @param data pointer returned in afl_custom_init for this fuzz case
    * @param filename File name of the test case in the queue entry
    * @return Return True(1) if the fuzzer will fuzz the queue entry, and
    *     False(0) otherwise.
    */
-  u8 (*afl_custom_queue_get)(afl_state_t *afl, const u8 *filename);
+  u8 (*afl_custom_queue_get)(void *data, const u8 *filename);
 
   /**
    * Allow for additional analysis (e.g. calling a different tool that does a
@@ -726,13 +743,20 @@ struct custom_mutator {
    *
    * (Optional)
    *
+   * @param data pointer returned in afl_custom_init for this fuzz case
    * @param filename_new_queue File name of the new queue entry
    * @param filename_orig_queue File name of the original queue entry. This
    *     argument can be NULL while initializing the fuzzer
    */
-  void (*afl_custom_queue_new_entry)(afl_state_t *afl,
+  void (*afl_custom_queue_new_entry)(void *data,
                                      const u8 *   filename_new_queue,
                                      const u8 *   filename_orig_queue);
+  /**
+   * Deinitialize the custom mutator.
+   *
+   * @param data pointer returned in afl_custom_init for this fuzz case
+   */
+  void (*afl_custom_deinit)(void *data);
 
 };
 
@@ -750,19 +774,17 @@ u8   trim_case_custom(afl_state_t *, struct queue_entry *q, u8 *in_buf);
 /* Python */
 #ifdef USE_PYTHON
 
-int  init_py_module(afl_state_t *, u8 *);
-void finalize_py_module(afl_state_t *);
-
-void   init_py(afl_state_t *, unsigned int);
-size_t fuzz_py(afl_state_t *, u8 **, size_t, u8 *, size_t, size_t);
-size_t pre_save_py(afl_state_t *, u8 *, size_t, u8 **);
-u32    init_trim_py(afl_state_t *, u8 *, size_t);
-u32    post_trim_py(afl_state_t *, u8);
-void   trim_py(afl_state_t *, u8 **, size_t *);
-size_t havoc_mutation_py(afl_state_t *, u8 **, size_t, size_t);
-u8     havoc_mutation_probability_py(afl_state_t *);
-u8     queue_get_py(afl_state_t *, const u8 *);
-void   queue_new_entry_py(afl_state_t *, const u8 *, const u8 *);
+void finalize_py_module(void *);
+
+size_t pre_save_py(void *, u8 *, size_t, u8 **);
+u32    init_trim_py(void *, u8 *, size_t);
+u32    post_trim_py(void *, u8);
+void   trim_py(void *, u8 **, size_t *);
+size_t havoc_mutation_py(void *, u8 **, size_t, size_t);
+u8     havoc_mutation_probability_py(void *);
+u8     queue_get_py(void *, const u8 *);
+void   queue_new_entry_py(void *, const u8 *, const u8 *);
+void   deinit_py(void *);
 
 #endif
 
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index c158aa6f..0ded4ba1 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -27,7 +27,7 @@
 
 void load_custom_mutator(afl_state_t *, const char *);
 #ifdef USE_PYTHON
-void load_custom_mutator_py(afl_state_t *, const char *);
+void load_custom_mutator_py(afl_state_t *, char *);
 #endif
 
 void setup_custom_mutator(afl_state_t *afl) {
@@ -59,10 +59,7 @@ void setup_custom_mutator(afl_state_t *afl) {
       FATAL(
           "MOpt and Python mutator are mutually exclusive. We accept pull "
           "requests that integrates MOpt with the optional mutators "
-          "(custom/radamsa/redquenn/...).");
-
-    if (init_py_module(afl, module_name))
-      FATAL("Failed to initialize Python module");
+          "(custom/radamsa/redqueen/...).");
 
     load_custom_mutator_py(afl, module_name);
 
@@ -79,18 +76,13 @@ void destroy_custom_mutator(afl_state_t *afl) {
 
   if (afl->mutator) {
 
+    afl->mutator->afl_custom_deinit(afl->mutator->data);
+
     if (afl->mutator->dh)
       dlclose(afl->mutator->dh);
-    else {
-
-      /* Python mutator */
-#ifdef USE_PYTHON
-      finalize_py_module(afl);
-#endif
-
-    }
 
     ck_free(afl->mutator);
+    afl->mutator = NULL;
 
   }
 
@@ -109,10 +101,13 @@ void load_custom_mutator(afl_state_t *afl, const char *fn) {
   afl->mutator->dh = dh;
 
   /* Mutator */
-  /* "afl_custom_init", optional for backward compatibility */
+  /* "afl_custom_init", required */
   afl->mutator->afl_custom_init = dlsym(dh, "afl_custom_init");
-  if (!afl->mutator->afl_custom_init)
-    WARNF("Symbol 'afl_custom_init' not found.");
+  if (!afl->mutator->afl_custom_init) FATAL("Symbol 'afl_custom_init' not found.");
+
+  /* "afl_custom_deinit", required */
+  afl->mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit");
+  if (!afl->mutator->afl_custom_deinit) FATAL("Symbol 'afl_custom_deinit' not found.");
 
   /* "afl_custom_fuzz" or "afl_custom_mutator", required */
   afl->mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz");
@@ -203,7 +198,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
 
   /* Initialize trimming in the custom mutator */
   afl->stage_cur = 0;
-  afl->stage_max = afl->mutator->afl_custom_init_trim(afl, in_buf, q->len);
+  afl->stage_max = afl->mutator->afl_custom_init_trim(afl->mutator->data, in_buf, q->len);
 
   if (afl->not_on_tty && afl->debug)
     SAYF("[Custom Trimming] START: Max %d iterations, %u bytes", afl->stage_max,
@@ -309,54 +304,3 @@ abort_trimming:
   return fault;
 
 }
-
-#ifdef USE_PYTHON
-void load_custom_mutator_py(afl_state_t *afl, const char *module_name) {
-
-  PyObject **py_functions = afl->py_functions;
-
-  afl->mutator = ck_alloc(sizeof(struct custom_mutator));
-
-  afl->mutator->name = module_name;
-  ACTF("Loading Python mutator library from '%s'...", module_name);
-
-  if (py_functions[PY_FUNC_INIT]) afl->mutator->afl_custom_init = init_py;
-
-  /* "afl_custom_fuzz" should not be NULL, but the interface of Python mutator
-     is quite different from the custom mutator. */
-  afl->mutator->afl_custom_fuzz = fuzz_py;
-
-  if (py_functions[PY_FUNC_PRE_SAVE])
-    afl->mutator->afl_custom_pre_save = pre_save_py;
-
-  if (py_functions[PY_FUNC_INIT_TRIM])
-    afl->mutator->afl_custom_init_trim = init_trim_py;
-
-  if (py_functions[PY_FUNC_POST_TRIM])
-    afl->mutator->afl_custom_post_trim = post_trim_py;
-
-  if (py_functions[PY_FUNC_TRIM]) afl->mutator->afl_custom_trim = trim_py;
-
-  if (py_functions[PY_FUNC_HAVOC_MUTATION])
-    afl->mutator->afl_custom_havoc_mutation = havoc_mutation_py;
-
-  if (py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY])
-    afl->mutator->afl_custom_havoc_mutation_probability =
-        havoc_mutation_probability_py;
-
-  if (py_functions[PY_FUNC_QUEUE_GET])
-    afl->mutator->afl_custom_queue_get = queue_get_py;
-
-  if (py_functions[PY_FUNC_QUEUE_NEW_ENTRY])
-    afl->mutator->afl_custom_queue_new_entry = queue_new_entry_py;
-
-  OKF("Python mutator '%s' installed successfully.", module_name);
-
-  /* Initialize the custom mutator */
-  if (afl->mutator->afl_custom_init)
-    afl->mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF));
-
-}
-
-#endif
-
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
index 595c1ed0..d3027d2b 100644
--- a/src/afl-fuzz-python.c
+++ b/src/afl-fuzz-python.c
@@ -28,9 +28,84 @@
 /* Python stuff */
 #ifdef USE_PYTHON
 
-int init_py_module(afl_state_t *afl, u8 *module_name) {
+static void *unsupported(afl_state_t *afl, unsigned int seed) {
+  FATAL("Python Mutator cannot be called twice yet");
+  return NULL;
+}
+
+size_t fuzz_py(void *py_mutator, u8 **buf, size_t buf_size, u8 *add_buf,
+               size_t add_buf_size, size_t max_size) {
+
+  size_t    mutated_size;
+  PyObject *py_args, *py_value;
+  py_args = PyTuple_New(3);
+
+  /* buf */
+  py_value = PyByteArray_FromStringAndSize(*buf, buf_size);
+  if (!py_value) {
+
+    Py_DECREF(py_args);
+    FATAL("Failed to convert arguments");
+
+  }
+
+  PyTuple_SetItem(py_args, 0, py_value);
+
+  /* add_buf */
+  py_value = PyByteArray_FromStringAndSize(add_buf, add_buf_size);
+  if (!py_value) {
+
+    Py_DECREF(py_args);
+    FATAL("Failed to convert arguments");
+
+  }
+
+  PyTuple_SetItem(py_args, 1, py_value);
+
+  /* max_size */
+#if PY_MAJOR_VERSION >= 3
+  py_value = PyLong_FromLong(max_size);
+#else
+  py_value = PyInt_FromLong(max_size);
+#endif
+  if (!py_value) {
+
+    Py_DECREF(py_args);
+    FATAL("Failed to convert arguments");
+
+  }
+
+  PyTuple_SetItem(py_args, 2, py_value);
+
+  py_value = PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_FUZZ], py_args);
+
+  Py_DECREF(py_args);
+
+  if (py_value != NULL) {
+
+    mutated_size = PyByteArray_Size(py_value);
+    if (buf_size < mutated_size) *buf = ck_realloc(*buf, mutated_size);
+
+    memcpy(*buf, PyByteArray_AsString(py_value), mutated_size);
+    Py_DECREF(py_value);
+    return mutated_size;
+
+  } else {
+
+    PyErr_Print();
+    FATAL("Call failed");
+
+  }
+
+}
 
-  if (!module_name) return 1;
+
+static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
+
+  if (!module_name) return NULL;
+
+  py_mutator_t *py = calloc(1, sizeof(py_mutator_t));
+  if (!py) PFATAL("Could not allocate memory for python mutator!");
 
   Py_Initialize();
 
@@ -40,17 +115,18 @@ int init_py_module(afl_state_t *afl, u8 *module_name) {
   PyObject *py_name = PyString_FromString(module_name);
 #endif
 
-  afl->py_module = PyImport_Import(py_name);
+  py->py_module = PyImport_Import(py_name);
   Py_DECREF(py_name);
 
-  PyObject * py_module = afl->py_module;
-  PyObject **py_functions = afl->py_functions;
+  PyObject * py_module = py->py_module;
+  PyObject **py_functions = py->py_functions;
 
-  if (afl->py_module != NULL) {
+  if (py_module != NULL) {
 
     u8 py_notrim = 0, py_idx;
-    py_functions[PY_FUNC_INIT] = PyObject_GetAttrString(afl->py_module, "init");
-    py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(afl->py_module, "fuzz");
+    py_functions[PY_FUNC_INIT] = PyObject_GetAttrString(py_module, "init");
+    py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit");
+    py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz");
     py_functions[PY_FUNC_PRE_SAVE] =
         PyObject_GetAttrString(py_module, "pre_save");
     py_functions[PY_FUNC_INIT_TRIM] =
@@ -96,7 +172,7 @@ int init_py_module(afl_state_t *afl, u8 *module_name) {
                   "Cannot find/call function with index %d in external "
                   "Python module.\n",
                   py_idx);
-          return 1;
+          return NULL;
 
         }
 
@@ -119,23 +195,27 @@ int init_py_module(afl_state_t *afl, u8 *module_name) {
 
     PyErr_Print();
     fprintf(stderr, "Failed to load \"%s\"\n", module_name);
-    return 1;
+    return NULL;
 
   }
 
-  return 0;
+  return py;
 
 }
 
-void finalize_py_module(afl_state_t *afl) {
+void finalize_py_module(void *py_mutator) {
+
+  py_mutator_t *py = (py_mutator_t *)py_mutator;
 
-  if (afl->py_module != NULL) {
+  if (py->py_module != NULL) {
+
+    deinit_py(py_mutator);
 
     u32 i;
     for (i = 0; i < PY_FUNC_COUNT; ++i)
-      Py_XDECREF(afl->py_functions[i]);
+      Py_XDECREF(py->py_functions[i]);
 
-    Py_DECREF(afl->py_module);
+    Py_DECREF(py->py_module);
 
   }
 
@@ -143,7 +223,7 @@ void finalize_py_module(afl_state_t *afl) {
 
 }
 
-void init_py(afl_state_t *afl, unsigned int seed) {
+static void init_py(afl_state_t *afl, py_mutator_t *py_mutator, unsigned int seed) {
 
   PyObject *py_args, *py_value;
 
@@ -158,14 +238,13 @@ void init_py(afl_state_t *afl, unsigned int seed) {
   if (!py_value) {
 
     Py_DECREF(py_args);
-    fprintf(stderr, "Cannot convert argument\n");
-    return;
+    FATAL("Cannot convert argument in python init.");
 
   }
 
   PyTuple_SetItem(py_args, 0, py_value);
 
-  py_value = PyObject_CallObject(afl->py_functions[PY_FUNC_INIT], py_args);
+  py_value = PyObject_CallObject(py_mutator->py_functions[PY_FUNC_INIT], py_args);
 
   Py_DECREF(py_args);
 
@@ -173,79 +252,90 @@ void init_py(afl_state_t *afl, unsigned int seed) {
 
     PyErr_Print();
     fprintf(stderr, "Call failed\n");
-    return;
+    FATAL("Custom py mutator INIT failed.");
 
   }
 
 }
 
-size_t fuzz_py(afl_state_t *afl, u8 **buf, size_t buf_size, u8 *add_buf,
-               size_t add_buf_size, size_t max_size) {
+void deinit_py(void *py_mutator) {
 
-  size_t    mutated_size;
   PyObject *py_args, *py_value;
-  py_args = PyTuple_New(3);
 
-  /* buf */
-  py_value = PyByteArray_FromStringAndSize(*buf, buf_size);
-  if (!py_value) {
+  py_args = PyTuple_New(0);
+  py_value = PyObject_CallObject(
+      ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_DEINIT], py_args);
+  Py_DECREF(py_args);
 
-    Py_DECREF(py_args);
-    FATAL("Failed to convert arguments");
+  if (py_value != NULL) {
+
+    Py_DECREF(py_value);
+
+  } else {
+
+    PyErr_Print();
+    FATAL("Call failed");
 
   }
 
-  PyTuple_SetItem(py_args, 0, py_value);
+}
 
-  /* add_buf */
-  py_value = PyByteArray_FromStringAndSize(add_buf, add_buf_size);
-  if (!py_value) {
+void load_custom_mutator_py(afl_state_t *afl, char *module_name) {
 
-    Py_DECREF(py_args);
-    FATAL("Failed to convert arguments");
+  afl->mutator = ck_alloc(sizeof(struct custom_mutator));
 
+  afl->mutator->name = module_name;
+  ACTF("Loading Python mutator library from '%s'...", module_name);
+
+  py_mutator_t *py_mutator;
+  py_mutator = init_py_module(afl, module_name);
+  if (!py_mutator) {
+    FATAL("Failed to load python mutator.");
   }
 
-  PyTuple_SetItem(py_args, 1, py_value);
+  PyObject **py_functions = py_mutator->py_functions;
 
-  /* max_size */
-#if PY_MAJOR_VERSION >= 3
-  py_value = PyLong_FromLong(max_size);
-#else
-  py_value = PyInt_FromLong(max_size);
-#endif
-  if (!py_value) {
+  if (py_functions[PY_FUNC_INIT]) afl->mutator->afl_custom_init = unsupported;
 
-    Py_DECREF(py_args);
-    FATAL("Failed to convert arguments");
+  if (py_functions[PY_FUNC_DEINIT]) afl->mutator->afl_custom_deinit = deinit_py;
 
-  }
+  /* "afl_custom_fuzz" should not be NULL, but the interface of Python mutator
+     is quite different from the custom mutator. */
+  afl->mutator->afl_custom_fuzz = fuzz_py;
 
-  PyTuple_SetItem(py_args, 2, py_value);
+  if (py_functions[PY_FUNC_PRE_SAVE])
+    afl->mutator->afl_custom_pre_save = pre_save_py;
 
-  py_value = PyObject_CallObject(afl->py_functions[PY_FUNC_FUZZ], py_args);
+  if (py_functions[PY_FUNC_INIT_TRIM])
+    afl->mutator->afl_custom_init_trim = init_trim_py;
 
-  Py_DECREF(py_args);
+  if (py_functions[PY_FUNC_POST_TRIM])
+    afl->mutator->afl_custom_post_trim = post_trim_py;
 
-  if (py_value != NULL) {
+  if (py_functions[PY_FUNC_TRIM]) afl->mutator->afl_custom_trim = trim_py;
 
-    mutated_size = PyByteArray_Size(py_value);
-    if (buf_size < mutated_size) *buf = ck_realloc(*buf, mutated_size);
+  if (py_functions[PY_FUNC_HAVOC_MUTATION])
+    afl->mutator->afl_custom_havoc_mutation = havoc_mutation_py;
 
-    memcpy(*buf, PyByteArray_AsString(py_value), mutated_size);
-    Py_DECREF(py_value);
-    return mutated_size;
+  if (py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY])
+    afl->mutator->afl_custom_havoc_mutation_probability =
+        havoc_mutation_probability_py;
 
-  } else {
+  if (py_functions[PY_FUNC_QUEUE_GET])
+    afl->mutator->afl_custom_queue_get = queue_get_py;
 
-    PyErr_Print();
-    FATAL("Call failed");
+  if (py_functions[PY_FUNC_QUEUE_NEW_ENTRY])
+    afl->mutator->afl_custom_queue_new_entry = queue_new_entry_py;
 
-  }
+  OKF("Python mutator '%s' installed successfully.", module_name);
+
+  /* Initialize the custom mutator */
+  init_py(afl, py_mutator, rand_below(afl, 0xFFFFFFFF));
 
 }
 
-size_t pre_save_py(afl_state_t *afl, u8 *buf, size_t buf_size, u8 **out_buf) {
+
+size_t pre_save_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf) {
 
   size_t    out_buf_size;
   PyObject *py_args, *py_value;
@@ -260,7 +350,7 @@ size_t pre_save_py(afl_state_t *afl, u8 *buf, size_t buf_size, u8 **out_buf) {
 
   PyTuple_SetItem(py_args, 0, py_value);
 
-  py_value = PyObject_CallObject(afl->py_functions[PY_FUNC_PRE_SAVE], py_args);
+  py_value = PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_PRE_SAVE], py_args);
 
   Py_DECREF(py_args);
 
@@ -281,7 +371,7 @@ size_t pre_save_py(afl_state_t *afl, u8 *buf, size_t buf_size, u8 **out_buf) {
 
 }
 
-u32 init_trim_py(afl_state_t *afl, u8 *buf, size_t buf_size) {
+u32 init_trim_py(void *py_mutator, u8 *buf, size_t buf_size) {
 
   PyObject *py_args, *py_value;
 
@@ -296,7 +386,7 @@ u32 init_trim_py(afl_state_t *afl, u8 *buf, size_t buf_size) {
 
   PyTuple_SetItem(py_args, 0, py_value);
 
-  py_value = PyObject_CallObject(afl->py_functions[PY_FUNC_INIT_TRIM], py_args);
+  py_value = PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_INIT_TRIM], py_args);
   Py_DECREF(py_args);
 
   if (py_value != NULL) {
@@ -318,7 +408,7 @@ u32 init_trim_py(afl_state_t *afl, u8 *buf, size_t buf_size) {
 
 }
 
-u32 post_trim_py(afl_state_t *afl, u8 success) {
+u32 post_trim_py(void *py_mutator, u8 success) {
 
   PyObject *py_args, *py_value;
 
@@ -334,7 +424,7 @@ u32 post_trim_py(afl_state_t *afl, u8 success) {
 
   PyTuple_SetItem(py_args, 0, py_value);
 
-  py_value = PyObject_CallObject(afl->py_functions[PY_FUNC_POST_TRIM], py_args);
+  py_value = PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_POST_TRIM], py_args);
   Py_DECREF(py_args);
 
   if (py_value != NULL) {
@@ -356,12 +446,12 @@ u32 post_trim_py(afl_state_t *afl, u8 success) {
 
 }
 
-void trim_py(afl_state_t *afl, u8 **out_buf, size_t *out_buf_size) {
+void trim_py(void *py_mutator, u8 **out_buf, size_t *out_buf_size) {
 
   PyObject *py_args, *py_value;
 
   py_args = PyTuple_New(0);
-  py_value = PyObject_CallObject(afl->py_functions[PY_FUNC_TRIM], py_args);
+  py_value = PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_TRIM], py_args);
   Py_DECREF(py_args);
 
   if (py_value != NULL) {
@@ -380,7 +470,7 @@ void trim_py(afl_state_t *afl, u8 **out_buf, size_t *out_buf_size) {
 
 }
 
-size_t havoc_mutation_py(afl_state_t *afl, u8 **buf, size_t buf_size,
+size_t havoc_mutation_py(void *py_mutator, u8 **buf, size_t buf_size,
                          size_t max_size) {
 
   size_t    mutated_size;
@@ -414,7 +504,7 @@ size_t havoc_mutation_py(afl_state_t *afl, u8 **buf, size_t buf_size,
   PyTuple_SetItem(py_args, 1, py_value);
 
   py_value =
-      PyObject_CallObject(afl->py_functions[PY_FUNC_HAVOC_MUTATION], py_args);
+      PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_HAVOC_MUTATION], py_args);
 
   Py_DECREF(py_args);
 
@@ -437,13 +527,13 @@ size_t havoc_mutation_py(afl_state_t *afl, u8 **buf, size_t buf_size,
 
 }
 
-u8 havoc_mutation_probability_py(afl_state_t *afl) {
+u8 havoc_mutation_probability_py(void *py_mutator) {
 
   PyObject *py_args, *py_value;
 
   py_args = PyTuple_New(0);
   py_value = PyObject_CallObject(
-      afl->py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY], py_args);
+      ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY], py_args);
   Py_DECREF(py_args);
 
   if (py_value != NULL) {
@@ -461,7 +551,7 @@ u8 havoc_mutation_probability_py(afl_state_t *afl) {
 
 }
 
-u8 queue_get_py(afl_state_t *afl, const u8 *filename) {
+u8 queue_get_py(void *py_mutator, const u8 *filename) {
 
   PyObject *py_args, *py_value;
 
@@ -483,7 +573,7 @@ u8 queue_get_py(afl_state_t *afl, const u8 *filename) {
   PyTuple_SetItem(py_args, 0, py_value);
 
   // Call Python function
-  py_value = PyObject_CallObject(afl->py_functions[PY_FUNC_QUEUE_GET], py_args);
+  py_value = PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_QUEUE_GET], py_args);
   Py_DECREF(py_args);
 
   if (py_value != NULL) {
@@ -509,7 +599,7 @@ u8 queue_get_py(afl_state_t *afl, const u8 *filename) {
 
 }
 
-void queue_new_entry_py(afl_state_t *afl, const u8 *filename_new_queue,
+void queue_new_entry_py(void *py_mutator, const u8 *filename_new_queue,
                         const u8 *filename_orig_queue) {
 
   PyObject *py_args, *py_value;
@@ -553,7 +643,7 @@ void queue_new_entry_py(afl_state_t *afl, const u8 *filename_new_queue,
 
   // Call
   py_value =
-      PyObject_CallObject(afl->py_functions[PY_FUNC_QUEUE_NEW_ENTRY], py_args);
+      PyObject_CallObject(((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_QUEUE_NEW_ENTRY], py_args);
   Py_DECREF(py_args);
 
   if (py_value == NULL) {