aboutsummaryrefslogtreecommitdiff
path: root/include/afl-prealloc.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/afl-prealloc.h')
-rw-r--r--include/afl-prealloc.h101
1 files changed, 101 insertions, 0 deletions
diff --git a/include/afl-prealloc.h b/include/afl-prealloc.h
new file mode 100644
index 00000000..712cdec6
--- /dev/null
+++ b/include/afl-prealloc.h
@@ -0,0 +1,101 @@
+/* If we know we'll reuse small elements often, we'll just preallocate a buffer, then fall back to malloc */
+// TODO: Replace free status check with bitmask+CLZ
+
+#ifndef AFL_PREALLOC_H
+#define AFL_PREALLOC_H
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "debug.h"
+
+typedef enum prealloc_status {
+ PRE_STATUS_UNUSED = 0,/* free in buf */
+ PRE_STATUS_USED, /* used in buf */
+ PRE_STATUS_MALLOC /* system malloc */
+} pre_status_t;
+
+
+/* Adds the entry used for prealloc bookkeeping to this struct */
+
+#define PREALLOCABLE ;pre_status_t pre_status; /* prealloc status of this instance */
+
+
+/* allocate an element of type *el_ptr, to this variable.
+ Uses (and reuses) the given prealloc_buf before hitting libc's malloc.
+ prealloc_buf must be the pointer to an array with type `type`.
+ `type` must be a struct with uses PREALLOCABLE (a pre_status_t pre_status member).
+ prealloc_size must be the array size.
+ prealloc_counter must be a variable initialized with 0 (of any name).
+ */
+
+#define PRE_ALLOC(el_ptr, prealloc_buf, prealloc_size, prealloc_counter) do { \
+ \
+ if ((prealloc_counter) >= (prealloc_size)) { \
+ \
+ el_ptr = malloc(sizeof(*el_ptr)); \
+ el_ptr->pre_status = PRE_STATUS_MALLOC; \
+ \
+ } else { \
+ \
+ /* Find one of our preallocated elements */ \
+ u32 i; \
+ for (i = 0; i < (prealloc_size); i++) { \
+ \
+ el_ptr = &((prealloc_buf)[i]); \
+ if (el_ptr->pre_status == PRE_STATUS_UNUSED) { \
+ \
+ (prealloc_counter)++; \
+ el_ptr->pre_status = PRE_STATUS_USED; \
+ break; \
+ \
+ } \
+ } \
+ } \
+ \
+ if(!el_ptr) { \
+ FATAL("BUG in list.h -> no element found or allocated!"); \
+ } \
+} while(0);
+
+
+/* Take a chosen (free) element from the prealloc_buf directly */
+
+#define PRE_ALLOC_FORCE(el_ptr, prealloc_counter) do { \
+ if ((el_ptr)->pre_status != PRE_STATUS_UNUSED) { \
+ FATAL("PRE_ALLOC_FORCE element already allocated"); \
+ } \
+ (el_ptr)->pre_status = PRE_STATUS_USED; \
+ (prealloc_counter)++; \
+} while(0);
+
+
+/* free an preallocated element */
+
+#define PRE_FREE(el_ptr, prealloc_counter) do { \
+ \
+ switch ((el_ptr)->pre_status) { \
+ \
+ case PRE_STATUS_USED: { \
+ (el_ptr)->pre_status = PRE_STATUS_UNUSED; \
+ (prealloc_counter)--; \
+ if ((prealloc_counter) < 0) { \
+ FATAL("Inconsistent data in PRE_FREE"); \
+ } \
+ break; \
+ } \
+ case PRE_STATUS_MALLOC: { \
+ (el_ptr)->pre_status = PRE_STATUS_UNUSED; \
+ free((el_ptr)); \
+ break; \
+ } \
+ default: { \
+ FATAL("Double Free Detected"); \
+ break; \
+ } \
+ \
+ } \
+} while(0);
+
+#endif