• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <mh@mh-sec.de>,
8                       Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
9                       Andrea Fioraldi <andreafioraldi@gmail.com>,
10                       Dominik Maier <mail@dmnk.co>
11  
12     Copyright 2016, 2017 Google Inc. All rights reserved.
13     Copyright 2019-2022 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