xref: /aosp_15_r20/external/AFLplusplus/include/afl-prealloc.h (revision 08b48e0b10e97b33e7b60c5b6e2243bd915777f2)
1 /*
2    american fuzzy lop++ - prealloc a buffer to reuse small elements often
3    ----------------------------------------------------------------------
4 
5    Originally written by Michal Zalewski
6 
7    Now maintained by Marc Heuse <[email protected]>,
8                      Heiko Eißfeldt <[email protected]>,
9                      Andrea Fioraldi <[email protected]>,
10                      Dominik Maier <[email protected]>
11 
12    Copyright 2016, 2017 Google Inc. All rights reserved.
13    Copyright 2019-2024 AFLplusplus Project. All rights reserved.
14 
15    Licensed under the Apache License, Version 2.0 (the "License");
16    you may not use this file except in compliance with the License.
17    You may obtain a copy of the License at:
18 
19      https://www.apache.org/licenses/LICENSE-2.0
20 
21  */
22 
23 /* If we know we'll reuse small elements often, we'll just preallocate a buffer,
24  * then fall back to malloc */
25 // TODO: Replace free status check with bitmask+CLZ
26 
27 #ifndef AFL_PREALLOC_H
28 #define AFL_PREALLOC_H
29 
30 #include <stdio.h>
31 #include <stdbool.h>
32 #include <string.h>
33 
34 #include "debug.h"
35 #include "alloc-inl.h"
36 
37 typedef enum prealloc_status {
38 
39   PRE_STATUS_UNUSED = 0,                                     /* free in buf */
40   PRE_STATUS_USED,                                           /* used in buf */
41   PRE_STATUS_MALLOC                                        /* system malloc */
42 
43 } pre_status_t;
44 
45 /* Adds the entry used for prealloc bookkeeping to this struct */
46 
47 /* prealloc status of this instance */
48 #define PREALLOCABLE pre_status_t pre_status
49 
50 /* allocate an element of type *el_ptr, to this variable.
51     Uses (and reuses) the given prealloc_buf before hitting libc's malloc.
52     prealloc_buf must be the pointer to an array with type `type`.
53     `type` must be a struct with uses PREALLOCABLE (a pre_status_t pre_status
54    member). prealloc_size must be the array size. prealloc_counter must be a
55    variable initialized with 0 (of any name).
56     */
57 
58 #define PRE_ALLOC(el_ptr, prealloc_buf, prealloc_size, prealloc_counter)       \
59   do {                                                                         \
60                                                                                \
61     if ((prealloc_counter) >= (prealloc_size)) {                               \
62                                                                                \
63       el_ptr = (element_t *)malloc(sizeof(*el_ptr));                           \
64       if (!el_ptr) { FATAL("error in list.h -> out of memory for element!"); } \
65       el_ptr->pre_status = PRE_STATUS_MALLOC;                                  \
66                                                                                \
67     } else {                                                                   \
68                                                                                \
69       /* Find one of our preallocated elements */                              \
70       u32 i;                                                                   \
71       for (i = 0; i < (prealloc_size); i++) {                                  \
72                                                                                \
73         el_ptr = &((prealloc_buf)[i]);                                         \
74         if (el_ptr->pre_status == PRE_STATUS_UNUSED) {                         \
75                                                                                \
76           (prealloc_counter)++;                                                \
77           el_ptr->pre_status = PRE_STATUS_USED;                                \
78           break;                                                               \
79                                                                                \
80         }                                                                      \
81                                                                                \
82       }                                                                        \
83                                                                                \
84     }                                                                          \
85                                                                                \
86     if (!el_ptr) { FATAL("BUG in list.h -> no element found or allocated!"); } \
87                                                                                \
88   } while (0);
89 
90 /* Take a chosen (free) element from the prealloc_buf directly */
91 
92 #define PRE_ALLOC_FORCE(el_ptr, prealloc_counter)         \
93   do {                                                    \
94                                                           \
95     if ((el_ptr)->pre_status != PRE_STATUS_UNUSED) {      \
96                                                           \
97       FATAL("PRE_ALLOC_FORCE element already allocated"); \
98                                                           \
99     }                                                     \
100     (el_ptr)->pre_status = PRE_STATUS_USED;               \
101     (prealloc_counter)++;                                 \
102                                                           \
103   } while (0);
104 
105 /* free an preallocated element */
106 
107 #define PRE_FREE(el_ptr, prealloc_counter)        \
108   do {                                            \
109                                                   \
110     switch ((el_ptr)->pre_status) {               \
111                                                   \
112       case PRE_STATUS_USED: {                     \
113                                                   \
114         (el_ptr)->pre_status = PRE_STATUS_UNUSED; \
115         (prealloc_counter)--;                     \
116         if ((prealloc_counter) < 0) {             \
117                                                   \
118           FATAL("Inconsistent data in PRE_FREE"); \
119                                                   \
120         }                                         \
121         break;                                    \
122                                                   \
123       }                                           \
124       case PRE_STATUS_MALLOC: {                   \
125                                                   \
126         (el_ptr)->pre_status = PRE_STATUS_UNUSED; \
127         DFL_ck_free((el_ptr));                    \
128         break;                                    \
129                                                   \
130       }                                           \
131       default: {                                  \
132                                                   \
133         FATAL("Double Free Detected");            \
134         break;                                    \
135                                                   \
136       }                                           \
137                                                   \
138     }                                             \
139                                                   \
140   } while (0);
141 
142 #endif
143 
144