1 /* 2 * Boilerplate code used for testing extent hooks via interception and 3 * passthrough. 4 */ 5 6 static void *extent_alloc_hook(extent_hooks_t *extent_hooks, void *new_addr, 7 size_t size, size_t alignment, bool *zero, bool *commit, 8 unsigned arena_ind); 9 static bool extent_dalloc_hook(extent_hooks_t *extent_hooks, void *addr, 10 size_t size, bool committed, unsigned arena_ind); 11 static void extent_destroy_hook(extent_hooks_t *extent_hooks, void *addr, 12 size_t size, bool committed, unsigned arena_ind); 13 static bool extent_commit_hook(extent_hooks_t *extent_hooks, void *addr, 14 size_t size, size_t offset, size_t length, unsigned arena_ind); 15 static bool extent_decommit_hook(extent_hooks_t *extent_hooks, void *addr, 16 size_t size, size_t offset, size_t length, unsigned arena_ind); 17 static bool extent_purge_lazy_hook(extent_hooks_t *extent_hooks, void *addr, 18 size_t size, size_t offset, size_t length, unsigned arena_ind); 19 static bool extent_purge_forced_hook(extent_hooks_t *extent_hooks, 20 void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); 21 static bool extent_split_hook(extent_hooks_t *extent_hooks, void *addr, 22 size_t size, size_t size_a, size_t size_b, bool committed, 23 unsigned arena_ind); 24 static bool extent_merge_hook(extent_hooks_t *extent_hooks, void *addr_a, 25 size_t size_a, void *addr_b, size_t size_b, bool committed, 26 unsigned arena_ind); 27 28 static extent_hooks_t *default_hooks; 29 static extent_hooks_t hooks = { 30 extent_alloc_hook, 31 extent_dalloc_hook, 32 extent_destroy_hook, 33 extent_commit_hook, 34 extent_decommit_hook, 35 extent_purge_lazy_hook, 36 extent_purge_forced_hook, 37 extent_split_hook, 38 extent_merge_hook 39 }; 40 41 /* Control whether hook functions pass calls through to default hooks. */ 42 static bool try_alloc = true; 43 static bool try_dalloc = true; 44 static bool try_destroy = true; 45 static bool try_commit = true; 46 static bool try_decommit = true; 47 static bool try_purge_lazy = true; 48 static bool try_purge_forced = true; 49 static bool try_split = true; 50 static bool try_merge = true; 51 52 /* Set to false prior to operations, then introspect after operations. */ 53 static bool called_alloc; 54 static bool called_dalloc; 55 static bool called_destroy; 56 static bool called_commit; 57 static bool called_decommit; 58 static bool called_purge_lazy; 59 static bool called_purge_forced; 60 static bool called_split; 61 static bool called_merge; 62 63 /* Set to false prior to operations, then introspect after operations. */ 64 static bool did_alloc; 65 static bool did_dalloc; 66 static bool did_destroy; 67 static bool did_commit; 68 static bool did_decommit; 69 static bool did_purge_lazy; 70 static bool did_purge_forced; 71 static bool did_split; 72 static bool did_merge; 73 74 #if 0 75 # define TRACE_HOOK(fmt, ...) malloc_printf(fmt, __VA_ARGS__) 76 #else 77 # define TRACE_HOOK(fmt, ...) 78 #endif 79 80 static void * 81 extent_alloc_hook(extent_hooks_t *extent_hooks, void *new_addr, size_t size, 82 size_t alignment, bool *zero, bool *commit, unsigned arena_ind) { 83 void *ret; 84 85 TRACE_HOOK("%s(extent_hooks=%p, new_addr=%p, size=%zu, alignment=%zu, " 86 "*zero=%s, *commit=%s, arena_ind=%u)\n", __func__, extent_hooks, 87 new_addr, size, alignment, *zero ? "true" : "false", *commit ? 88 "true" : "false", arena_ind); 89 assert_ptr_eq(extent_hooks, &hooks, 90 "extent_hooks should be same as pointer used to set hooks"); 91 assert_ptr_eq(extent_hooks->alloc, extent_alloc_hook, 92 "Wrong hook function"); 93 called_alloc = true; 94 if (!try_alloc) { 95 return NULL; 96 } 97 ret = default_hooks->alloc(default_hooks, new_addr, size, alignment, 98 zero, commit, 0); 99 did_alloc = (ret != NULL); 100 return ret; 101 } 102 103 static bool 104 extent_dalloc_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, 105 bool committed, unsigned arena_ind) { 106 bool err; 107 108 TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, " 109 "arena_ind=%u)\n", __func__, extent_hooks, addr, size, committed ? 110 "true" : "false", arena_ind); 111 assert_ptr_eq(extent_hooks, &hooks, 112 "extent_hooks should be same as pointer used to set hooks"); 113 assert_ptr_eq(extent_hooks->dalloc, extent_dalloc_hook, 114 "Wrong hook function"); 115 called_dalloc = true; 116 if (!try_dalloc) { 117 return true; 118 } 119 err = default_hooks->dalloc(default_hooks, addr, size, committed, 0); 120 did_dalloc = !err; 121 return err; 122 } 123 124 static void 125 extent_destroy_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, 126 bool committed, unsigned arena_ind) { 127 TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, " 128 "arena_ind=%u)\n", __func__, extent_hooks, addr, size, committed ? 129 "true" : "false", arena_ind); 130 assert_ptr_eq(extent_hooks, &hooks, 131 "extent_hooks should be same as pointer used to set hooks"); 132 assert_ptr_eq(extent_hooks->destroy, extent_destroy_hook, 133 "Wrong hook function"); 134 called_destroy = true; 135 if (!try_destroy) { 136 return; 137 } 138 default_hooks->destroy(default_hooks, addr, size, committed, 0); 139 did_destroy = true; 140 } 141 142 static bool 143 extent_commit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, 144 size_t offset, size_t length, unsigned arena_ind) { 145 bool err; 146 147 TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " 148 "length=%zu, arena_ind=%u)\n", __func__, extent_hooks, addr, size, 149 offset, length, arena_ind); 150 assert_ptr_eq(extent_hooks, &hooks, 151 "extent_hooks should be same as pointer used to set hooks"); 152 assert_ptr_eq(extent_hooks->commit, extent_commit_hook, 153 "Wrong hook function"); 154 called_commit = true; 155 if (!try_commit) { 156 return true; 157 } 158 err = default_hooks->commit(default_hooks, addr, size, offset, length, 159 0); 160 did_commit = !err; 161 return err; 162 } 163 164 static bool 165 extent_decommit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, 166 size_t offset, size_t length, unsigned arena_ind) { 167 bool err; 168 169 TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " 170 "length=%zu, arena_ind=%u)\n", __func__, extent_hooks, addr, size, 171 offset, length, arena_ind); 172 assert_ptr_eq(extent_hooks, &hooks, 173 "extent_hooks should be same as pointer used to set hooks"); 174 assert_ptr_eq(extent_hooks->decommit, extent_decommit_hook, 175 "Wrong hook function"); 176 called_decommit = true; 177 if (!try_decommit) { 178 return true; 179 } 180 err = default_hooks->decommit(default_hooks, addr, size, offset, length, 181 0); 182 did_decommit = !err; 183 return err; 184 } 185 186 static bool 187 extent_purge_lazy_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, 188 size_t offset, size_t length, unsigned arena_ind) { 189 bool err; 190 191 TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " 192 "length=%zu arena_ind=%u)\n", __func__, extent_hooks, addr, size, 193 offset, length, arena_ind); 194 assert_ptr_eq(extent_hooks, &hooks, 195 "extent_hooks should be same as pointer used to set hooks"); 196 assert_ptr_eq(extent_hooks->purge_lazy, extent_purge_lazy_hook, 197 "Wrong hook function"); 198 called_purge_lazy = true; 199 if (!try_purge_lazy) { 200 return true; 201 } 202 err = default_hooks->purge_lazy == NULL || 203 default_hooks->purge_lazy(default_hooks, addr, size, offset, length, 204 0); 205 did_purge_lazy = !err; 206 return err; 207 } 208 209 static bool 210 extent_purge_forced_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, 211 size_t offset, size_t length, unsigned arena_ind) { 212 bool err; 213 214 TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " 215 "length=%zu arena_ind=%u)\n", __func__, extent_hooks, addr, size, 216 offset, length, arena_ind); 217 assert_ptr_eq(extent_hooks, &hooks, 218 "extent_hooks should be same as pointer used to set hooks"); 219 assert_ptr_eq(extent_hooks->purge_forced, extent_purge_forced_hook, 220 "Wrong hook function"); 221 called_purge_forced = true; 222 if (!try_purge_forced) { 223 return true; 224 } 225 err = default_hooks->purge_forced == NULL || 226 default_hooks->purge_forced(default_hooks, addr, size, offset, 227 length, 0); 228 did_purge_forced = !err; 229 return err; 230 } 231 232 static bool 233 extent_split_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, 234 size_t size_a, size_t size_b, bool committed, unsigned arena_ind) { 235 bool err; 236 237 TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, size_a=%zu, " 238 "size_b=%zu, committed=%s, arena_ind=%u)\n", __func__, extent_hooks, 239 addr, size, size_a, size_b, committed ? "true" : "false", 240 arena_ind); 241 assert_ptr_eq(extent_hooks, &hooks, 242 "extent_hooks should be same as pointer used to set hooks"); 243 assert_ptr_eq(extent_hooks->split, extent_split_hook, 244 "Wrong hook function"); 245 called_split = true; 246 if (!try_split) { 247 return true; 248 } 249 err = (default_hooks->split == NULL || 250 default_hooks->split(default_hooks, addr, size, size_a, size_b, 251 committed, 0)); 252 did_split = !err; 253 return err; 254 } 255 256 static bool 257 extent_merge_hook(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, 258 void *addr_b, size_t size_b, bool committed, unsigned arena_ind) { 259 bool err; 260 261 TRACE_HOOK("%s(extent_hooks=%p, addr_a=%p, size_a=%zu, addr_b=%p " 262 "size_b=%zu, committed=%s, arena_ind=%u)\n", __func__, extent_hooks, 263 addr_a, size_a, addr_b, size_b, committed ? "true" : "false", 264 arena_ind); 265 assert_ptr_eq(extent_hooks, &hooks, 266 "extent_hooks should be same as pointer used to set hooks"); 267 assert_ptr_eq(extent_hooks->merge, extent_merge_hook, 268 "Wrong hook function"); 269 assert_ptr_eq((void *)((uintptr_t)addr_a + size_a), addr_b, 270 "Extents not mergeable"); 271 called_merge = true; 272 if (!try_merge) { 273 return true; 274 } 275 err = (default_hooks->merge == NULL || 276 default_hooks->merge(default_hooks, addr_a, size_a, addr_b, size_b, 277 committed, 0)); 278 did_merge = !err; 279 return err; 280 } 281 282 static void 283 extent_hooks_prep(void) { 284 size_t sz; 285 286 sz = sizeof(default_hooks); 287 assert_d_eq(mallctl("arena.0.extent_hooks", (void *)&default_hooks, &sz, 288 NULL, 0), 0, "Unexpected mallctl() error"); 289 } 290