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