about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--custom_mutators/examples/custom_mutator_helpers.h342
-rw-r--r--custom_mutators/examples/custom_send.c8
-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
-rw-r--r--docs/Changelog.md1
7 files changed, 73 insertions, 499 deletions
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 7de72819..9cc4b160 100644
--- a/custom_mutators/examples/custom_send.c
+++ b/custom_mutators/examples/custom_send.c
@@ -10,21 +10,21 @@
 //   afl-fuzz -i in -o out -- ./test-instr -f /tmp/foo
 //
 
-#include "custom_mutator_helpers.h"
-
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
 #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 e680ec8e..42c7469c 100644
--- a/custom_mutators/examples/example.c
+++ b/custom_mutators/examples/example.c
@@ -7,7 +7,7 @@
 */
 
 // You need to use -I/path/to/AFLplusplus/include -I.
-#include "custom_mutator_helpers.h"
+#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,31 +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);
-
-  }
-
-  if (max_size > mutated_size) { mutated_size = max_size; }
-
-  *out_buf = mutated_out;
+  *out_buf = data->mutated_out;
   return mutated_size;
 
 }
@@ -144,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;
 
@@ -197,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;
@@ -284,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;
@@ -371,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 3cb018a6..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!
-     We use afl_realloc because it is effective.
-     You can also work within in_buf, and assign it to *out_buf. */
-
-  *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/docs/Changelog.md b/docs/Changelog.md
index 9f4a8653..3337feb9 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -30,6 +30,7 @@
   - unicorn_mode:
     - updated and minor issues fixed
   - new custom module: autotoken, a grammar free fuzzer for text inputs
+  - fixed custom mutator C examples
   - better sanitizer default options support for all tools
   - more minor fixes and cross-platform support