1 1.1 christos #include "test/jemalloc_test.h" 2 1.1 christos 3 1.1 christos #include "jemalloc/internal/hook.h" 4 1.1 christos 5 1.1 christos static void *arg_extra; 6 1.1 christos static int arg_type; 7 1.1 christos static void *arg_result; 8 1.1 christos static void *arg_address; 9 1.1 christos static size_t arg_old_usize; 10 1.1 christos static size_t arg_new_usize; 11 1.1 christos static uintptr_t arg_result_raw; 12 1.1 christos static uintptr_t arg_args_raw[4]; 13 1.1 christos 14 1.1 christos static int call_count = 0; 15 1.1 christos 16 1.1 christos static void 17 1.1 christos reset_args() { 18 1.1 christos arg_extra = NULL; 19 1.1 christos arg_type = 12345; 20 1.1 christos arg_result = NULL; 21 1.1 christos arg_address = NULL; 22 1.1 christos arg_old_usize = 0; 23 1.1 christos arg_new_usize = 0; 24 1.1 christos arg_result_raw = 0; 25 1.1 christos memset(arg_args_raw, 77, sizeof(arg_args_raw)); 26 1.1 christos } 27 1.1 christos 28 1.1 christos static void 29 1.1 christos alloc_free_size(size_t sz) { 30 1.1 christos void *ptr = mallocx(1, 0); 31 1.1 christos free(ptr); 32 1.1 christos ptr = mallocx(1, 0); 33 1.1 christos free(ptr); 34 1.1 christos ptr = mallocx(1, MALLOCX_TCACHE_NONE); 35 1.1 christos dallocx(ptr, MALLOCX_TCACHE_NONE); 36 1.1 christos } 37 1.1 christos 38 1.1 christos /* 39 1.1 christos * We want to support a degree of user reentrancy. This tests a variety of 40 1.1 christos * allocation scenarios. 41 1.1 christos */ 42 1.1 christos static void 43 1.1 christos be_reentrant() { 44 1.1 christos /* Let's make sure the tcache is non-empty if enabled. */ 45 1.1 christos alloc_free_size(1); 46 1.1 christos alloc_free_size(1024); 47 1.1 christos alloc_free_size(64 * 1024); 48 1.1 christos alloc_free_size(256 * 1024); 49 1.1 christos alloc_free_size(1024 * 1024); 50 1.1 christos 51 1.1 christos /* Some reallocation. */ 52 1.1 christos void *ptr = mallocx(129, 0); 53 1.1 christos ptr = rallocx(ptr, 130, 0); 54 1.1 christos free(ptr); 55 1.1 christos 56 1.1 christos ptr = mallocx(2 * 1024 * 1024, 0); 57 1.1 christos free(ptr); 58 1.1 christos ptr = mallocx(1 * 1024 * 1024, 0); 59 1.1 christos ptr = rallocx(ptr, 2 * 1024 * 1024, 0); 60 1.1 christos free(ptr); 61 1.1 christos 62 1.1 christos ptr = mallocx(1, 0); 63 1.1 christos ptr = rallocx(ptr, 1000, 0); 64 1.1 christos free(ptr); 65 1.1 christos } 66 1.1 christos 67 1.1 christos static void 68 1.1 christos set_args_raw(uintptr_t *args_raw, int nargs) { 69 1.1 christos memcpy(arg_args_raw, args_raw, sizeof(uintptr_t) * nargs); 70 1.1 christos } 71 1.1 christos 72 1.1 christos static void 73 1.1 christos expect_args_raw(uintptr_t *args_raw_expected, int nargs) { 74 1.1 christos int cmp = memcmp(args_raw_expected, arg_args_raw, 75 1.1 christos sizeof(uintptr_t) * nargs); 76 1.1 christos expect_d_eq(cmp, 0, "Raw args mismatch"); 77 1.1 christos } 78 1.1 christos 79 1.1 christos static void 80 1.1 christos reset() { 81 1.1 christos call_count = 0; 82 1.1 christos reset_args(); 83 1.1 christos } 84 1.1 christos 85 1.1 christos static void 86 1.1 christos test_alloc_hook(void *extra, hook_alloc_t type, void *result, 87 1.1 christos uintptr_t result_raw, uintptr_t args_raw[3]) { 88 1.1 christos call_count++; 89 1.1 christos arg_extra = extra; 90 1.1 christos arg_type = (int)type; 91 1.1 christos arg_result = result; 92 1.1 christos arg_result_raw = result_raw; 93 1.1 christos set_args_raw(args_raw, 3); 94 1.1 christos be_reentrant(); 95 1.1 christos } 96 1.1 christos 97 1.1 christos static void 98 1.1 christos test_dalloc_hook(void *extra, hook_dalloc_t type, void *address, 99 1.1 christos uintptr_t args_raw[3]) { 100 1.1 christos call_count++; 101 1.1 christos arg_extra = extra; 102 1.1 christos arg_type = (int)type; 103 1.1 christos arg_address = address; 104 1.1 christos set_args_raw(args_raw, 3); 105 1.1 christos be_reentrant(); 106 1.1 christos } 107 1.1 christos 108 1.1 christos static void 109 1.1 christos test_expand_hook(void *extra, hook_expand_t type, void *address, 110 1.1 christos size_t old_usize, size_t new_usize, uintptr_t result_raw, 111 1.1 christos uintptr_t args_raw[4]) { 112 1.1 christos call_count++; 113 1.1 christos arg_extra = extra; 114 1.1 christos arg_type = (int)type; 115 1.1 christos arg_address = address; 116 1.1 christos arg_old_usize = old_usize; 117 1.1 christos arg_new_usize = new_usize; 118 1.1 christos arg_result_raw = result_raw; 119 1.1 christos set_args_raw(args_raw, 4); 120 1.1 christos be_reentrant(); 121 1.1 christos } 122 1.1 christos 123 1.1 christos TEST_BEGIN(test_hooks_basic) { 124 1.1 christos /* Just verify that the record their arguments correctly. */ 125 1.1 christos hooks_t hooks = { 126 1.1 christos &test_alloc_hook, &test_dalloc_hook, &test_expand_hook, 127 1.1 christos (void *)111}; 128 1.1 christos void *handle = hook_install(TSDN_NULL, &hooks); 129 1.1 christos uintptr_t args_raw[4] = {10, 20, 30, 40}; 130 1.1 christos 131 1.1 christos /* Alloc */ 132 1.1 christos reset_args(); 133 1.1 christos hook_invoke_alloc(hook_alloc_posix_memalign, (void *)222, 333, 134 1.1 christos args_raw); 135 1.1 christos expect_ptr_eq(arg_extra, (void *)111, "Passed wrong user pointer"); 136 1.1 christos expect_d_eq((int)hook_alloc_posix_memalign, arg_type, 137 1.1 christos "Passed wrong alloc type"); 138 1.1 christos expect_ptr_eq((void *)222, arg_result, "Passed wrong result address"); 139 1.1 christos expect_u64_eq(333, arg_result_raw, "Passed wrong result"); 140 1.1 christos expect_args_raw(args_raw, 3); 141 1.1 christos 142 1.1 christos /* Dalloc */ 143 1.1 christos reset_args(); 144 1.1 christos hook_invoke_dalloc(hook_dalloc_sdallocx, (void *)222, args_raw); 145 1.1 christos expect_d_eq((int)hook_dalloc_sdallocx, arg_type, 146 1.1 christos "Passed wrong dalloc type"); 147 1.1 christos expect_ptr_eq((void *)111, arg_extra, "Passed wrong user pointer"); 148 1.1 christos expect_ptr_eq((void *)222, arg_address, "Passed wrong address"); 149 1.1 christos expect_args_raw(args_raw, 3); 150 1.1 christos 151 1.1 christos /* Expand */ 152 1.1 christos reset_args(); 153 1.1 christos hook_invoke_expand(hook_expand_xallocx, (void *)222, 333, 444, 555, 154 1.1 christos args_raw); 155 1.1 christos expect_d_eq((int)hook_expand_xallocx, arg_type, 156 1.1 christos "Passed wrong expand type"); 157 1.1 christos expect_ptr_eq((void *)111, arg_extra, "Passed wrong user pointer"); 158 1.1 christos expect_ptr_eq((void *)222, arg_address, "Passed wrong address"); 159 1.1 christos expect_zu_eq(333, arg_old_usize, "Passed wrong old usize"); 160 1.1 christos expect_zu_eq(444, arg_new_usize, "Passed wrong new usize"); 161 1.1 christos expect_zu_eq(555, arg_result_raw, "Passed wrong result"); 162 1.1 christos expect_args_raw(args_raw, 4); 163 1.1 christos 164 1.1 christos hook_remove(TSDN_NULL, handle); 165 1.1 christos } 166 1.1 christos TEST_END 167 1.1 christos 168 1.1 christos TEST_BEGIN(test_hooks_null) { 169 1.1 christos /* Null hooks should be ignored, not crash. */ 170 1.1 christos hooks_t hooks1 = {NULL, NULL, NULL, NULL}; 171 1.1 christos hooks_t hooks2 = {&test_alloc_hook, NULL, NULL, NULL}; 172 1.1 christos hooks_t hooks3 = {NULL, &test_dalloc_hook, NULL, NULL}; 173 1.1 christos hooks_t hooks4 = {NULL, NULL, &test_expand_hook, NULL}; 174 1.1 christos 175 1.1 christos void *handle1 = hook_install(TSDN_NULL, &hooks1); 176 1.1 christos void *handle2 = hook_install(TSDN_NULL, &hooks2); 177 1.1 christos void *handle3 = hook_install(TSDN_NULL, &hooks3); 178 1.1 christos void *handle4 = hook_install(TSDN_NULL, &hooks4); 179 1.1 christos 180 1.1 christos expect_ptr_ne(handle1, NULL, "Hook installation failed"); 181 1.1 christos expect_ptr_ne(handle2, NULL, "Hook installation failed"); 182 1.1 christos expect_ptr_ne(handle3, NULL, "Hook installation failed"); 183 1.1 christos expect_ptr_ne(handle4, NULL, "Hook installation failed"); 184 1.1 christos 185 1.1 christos uintptr_t args_raw[4] = {10, 20, 30, 40}; 186 1.1 christos 187 1.1 christos call_count = 0; 188 1.1 christos hook_invoke_alloc(hook_alloc_malloc, NULL, 0, args_raw); 189 1.1 christos expect_d_eq(call_count, 1, "Called wrong number of times"); 190 1.1 christos 191 1.1 christos call_count = 0; 192 1.1 christos hook_invoke_dalloc(hook_dalloc_free, NULL, args_raw); 193 1.1 christos expect_d_eq(call_count, 1, "Called wrong number of times"); 194 1.1 christos 195 1.1 christos call_count = 0; 196 1.1 christos hook_invoke_expand(hook_expand_realloc, NULL, 0, 0, 0, args_raw); 197 1.1 christos expect_d_eq(call_count, 1, "Called wrong number of times"); 198 1.1 christos 199 1.1 christos hook_remove(TSDN_NULL, handle1); 200 1.1 christos hook_remove(TSDN_NULL, handle2); 201 1.1 christos hook_remove(TSDN_NULL, handle3); 202 1.1 christos hook_remove(TSDN_NULL, handle4); 203 1.1 christos } 204 1.1 christos TEST_END 205 1.1 christos 206 1.1 christos TEST_BEGIN(test_hooks_remove) { 207 1.1 christos hooks_t hooks = {&test_alloc_hook, NULL, NULL, NULL}; 208 1.1 christos void *handle = hook_install(TSDN_NULL, &hooks); 209 1.1 christos expect_ptr_ne(handle, NULL, "Hook installation failed"); 210 1.1 christos call_count = 0; 211 1.1 christos uintptr_t args_raw[4] = {10, 20, 30, 40}; 212 1.1 christos hook_invoke_alloc(hook_alloc_malloc, NULL, 0, args_raw); 213 1.1 christos expect_d_eq(call_count, 1, "Hook not invoked"); 214 1.1 christos 215 1.1 christos call_count = 0; 216 1.1 christos hook_remove(TSDN_NULL, handle); 217 1.1 christos hook_invoke_alloc(hook_alloc_malloc, NULL, 0, NULL); 218 1.1 christos expect_d_eq(call_count, 0, "Hook invoked after removal"); 219 1.1 christos 220 1.1 christos } 221 1.1 christos TEST_END 222 1.1 christos 223 1.1 christos TEST_BEGIN(test_hooks_alloc_simple) { 224 1.1 christos /* "Simple" in the sense that we're not in a realloc variant. */ 225 1.1 christos hooks_t hooks = {&test_alloc_hook, NULL, NULL, (void *)123}; 226 1.1 christos void *handle = hook_install(TSDN_NULL, &hooks); 227 1.1 christos expect_ptr_ne(handle, NULL, "Hook installation failed"); 228 1.1 christos 229 1.1 christos /* Stop malloc from being optimized away. */ 230 1.1 christos volatile int err; 231 1.1 christos void *volatile ptr; 232 1.1 christos 233 1.1 christos /* malloc */ 234 1.1 christos reset(); 235 1.1 christos ptr = malloc(1); 236 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 237 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 238 1.1 christos expect_d_eq(arg_type, (int)hook_alloc_malloc, "Wrong hook type"); 239 1.1 christos expect_ptr_eq(ptr, arg_result, "Wrong result"); 240 1.1 christos expect_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw, 241 1.1 christos "Wrong raw result"); 242 1.1 christos expect_u64_eq((uintptr_t)1, arg_args_raw[0], "Wrong argument"); 243 1.1 christos free(ptr); 244 1.1 christos 245 1.1 christos /* posix_memalign */ 246 1.1 christos reset(); 247 1.1 christos err = posix_memalign((void **)&ptr, 1024, 1); 248 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 249 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 250 1.1 christos expect_d_eq(arg_type, (int)hook_alloc_posix_memalign, 251 1.1 christos "Wrong hook type"); 252 1.1 christos expect_ptr_eq(ptr, arg_result, "Wrong result"); 253 1.1 christos expect_u64_eq((uintptr_t)err, (uintptr_t)arg_result_raw, 254 1.1 christos "Wrong raw result"); 255 1.1 christos expect_u64_eq((uintptr_t)&ptr, arg_args_raw[0], "Wrong argument"); 256 1.1 christos expect_u64_eq((uintptr_t)1024, arg_args_raw[1], "Wrong argument"); 257 1.1 christos expect_u64_eq((uintptr_t)1, arg_args_raw[2], "Wrong argument"); 258 1.1 christos free(ptr); 259 1.1 christos 260 1.1 christos /* aligned_alloc */ 261 1.1 christos reset(); 262 1.1 christos ptr = aligned_alloc(1024, 1); 263 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 264 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 265 1.1 christos expect_d_eq(arg_type, (int)hook_alloc_aligned_alloc, 266 1.1 christos "Wrong hook type"); 267 1.1 christos expect_ptr_eq(ptr, arg_result, "Wrong result"); 268 1.1 christos expect_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw, 269 1.1 christos "Wrong raw result"); 270 1.1 christos expect_u64_eq((uintptr_t)1024, arg_args_raw[0], "Wrong argument"); 271 1.1 christos expect_u64_eq((uintptr_t)1, arg_args_raw[1], "Wrong argument"); 272 1.1 christos free(ptr); 273 1.1 christos 274 1.1 christos /* calloc */ 275 1.1 christos reset(); 276 1.1 christos ptr = calloc(11, 13); 277 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 278 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 279 1.1 christos expect_d_eq(arg_type, (int)hook_alloc_calloc, "Wrong hook type"); 280 1.1 christos expect_ptr_eq(ptr, arg_result, "Wrong result"); 281 1.1 christos expect_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw, 282 1.1 christos "Wrong raw result"); 283 1.1 christos expect_u64_eq((uintptr_t)11, arg_args_raw[0], "Wrong argument"); 284 1.1 christos expect_u64_eq((uintptr_t)13, arg_args_raw[1], "Wrong argument"); 285 1.1 christos free(ptr); 286 1.1 christos 287 1.1 christos /* memalign */ 288 1.1 christos #ifdef JEMALLOC_OVERRIDE_MEMALIGN 289 1.1 christos reset(); 290 1.1 christos ptr = memalign(1024, 1); 291 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 292 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 293 1.1 christos expect_d_eq(arg_type, (int)hook_alloc_memalign, "Wrong hook type"); 294 1.1 christos expect_ptr_eq(ptr, arg_result, "Wrong result"); 295 1.1 christos expect_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw, 296 1.1 christos "Wrong raw result"); 297 1.1 christos expect_u64_eq((uintptr_t)1024, arg_args_raw[0], "Wrong argument"); 298 1.1 christos expect_u64_eq((uintptr_t)1, arg_args_raw[1], "Wrong argument"); 299 1.1 christos free(ptr); 300 1.1 christos #endif /* JEMALLOC_OVERRIDE_MEMALIGN */ 301 1.1 christos 302 1.1 christos /* valloc */ 303 1.1 christos #ifdef JEMALLOC_OVERRIDE_VALLOC 304 1.1 christos reset(); 305 1.1 christos ptr = valloc(1); 306 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 307 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 308 1.1 christos expect_d_eq(arg_type, (int)hook_alloc_valloc, "Wrong hook type"); 309 1.1 christos expect_ptr_eq(ptr, arg_result, "Wrong result"); 310 1.1 christos expect_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw, 311 1.1 christos "Wrong raw result"); 312 1.1 christos expect_u64_eq((uintptr_t)1, arg_args_raw[0], "Wrong argument"); 313 1.1 christos free(ptr); 314 1.1 christos #endif /* JEMALLOC_OVERRIDE_VALLOC */ 315 1.1 christos 316 1.1 christos /* mallocx */ 317 1.1 christos reset(); 318 1.1 christos ptr = mallocx(1, MALLOCX_LG_ALIGN(10)); 319 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 320 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 321 1.1 christos expect_d_eq(arg_type, (int)hook_alloc_mallocx, "Wrong hook type"); 322 1.1 christos expect_ptr_eq(ptr, arg_result, "Wrong result"); 323 1.1 christos expect_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw, 324 1.1 christos "Wrong raw result"); 325 1.1 christos expect_u64_eq((uintptr_t)1, arg_args_raw[0], "Wrong argument"); 326 1.1 christos expect_u64_eq((uintptr_t)MALLOCX_LG_ALIGN(10), arg_args_raw[1], 327 1.1 christos "Wrong flags"); 328 1.1 christos free(ptr); 329 1.1 christos 330 1.1 christos hook_remove(TSDN_NULL, handle); 331 1.1 christos } 332 1.1 christos TEST_END 333 1.1 christos 334 1.1 christos TEST_BEGIN(test_hooks_dalloc_simple) { 335 1.1 christos /* "Simple" in the sense that we're not in a realloc variant. */ 336 1.1 christos hooks_t hooks = {NULL, &test_dalloc_hook, NULL, (void *)123}; 337 1.1 christos void *handle = hook_install(TSDN_NULL, &hooks); 338 1.1 christos expect_ptr_ne(handle, NULL, "Hook installation failed"); 339 1.1 christos 340 1.1 christos void *volatile ptr; 341 1.1 christos 342 1.1 christos /* free() */ 343 1.1 christos reset(); 344 1.1 christos ptr = malloc(1); 345 1.1 christos free(ptr); 346 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 347 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 348 1.1 christos expect_d_eq(arg_type, (int)hook_dalloc_free, "Wrong hook type"); 349 1.1 christos expect_ptr_eq(ptr, arg_address, "Wrong pointer freed"); 350 1.1 christos expect_u64_eq((uintptr_t)ptr, arg_args_raw[0], "Wrong raw arg"); 351 1.1 christos 352 1.1 christos /* dallocx() */ 353 1.1 christos reset(); 354 1.1 christos ptr = malloc(1); 355 1.1 christos dallocx(ptr, MALLOCX_TCACHE_NONE); 356 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 357 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 358 1.1 christos expect_d_eq(arg_type, (int)hook_dalloc_dallocx, "Wrong hook type"); 359 1.1 christos expect_ptr_eq(ptr, arg_address, "Wrong pointer freed"); 360 1.1 christos expect_u64_eq((uintptr_t)ptr, arg_args_raw[0], "Wrong raw arg"); 361 1.1 christos expect_u64_eq((uintptr_t)MALLOCX_TCACHE_NONE, arg_args_raw[1], 362 1.1 christos "Wrong raw arg"); 363 1.1 christos 364 1.1 christos /* sdallocx() */ 365 1.1 christos reset(); 366 1.1 christos ptr = malloc(1); 367 1.1 christos sdallocx(ptr, 1, MALLOCX_TCACHE_NONE); 368 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 369 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 370 1.1 christos expect_d_eq(arg_type, (int)hook_dalloc_sdallocx, "Wrong hook type"); 371 1.1 christos expect_ptr_eq(ptr, arg_address, "Wrong pointer freed"); 372 1.1 christos expect_u64_eq((uintptr_t)ptr, arg_args_raw[0], "Wrong raw arg"); 373 1.1 christos expect_u64_eq((uintptr_t)1, arg_args_raw[1], "Wrong raw arg"); 374 1.1 christos expect_u64_eq((uintptr_t)MALLOCX_TCACHE_NONE, arg_args_raw[2], 375 1.1 christos "Wrong raw arg"); 376 1.1 christos 377 1.1 christos hook_remove(TSDN_NULL, handle); 378 1.1 christos } 379 1.1 christos TEST_END 380 1.1 christos 381 1.1 christos TEST_BEGIN(test_hooks_expand_simple) { 382 1.1 christos /* "Simple" in the sense that we're not in a realloc variant. */ 383 1.1 christos hooks_t hooks = {NULL, NULL, &test_expand_hook, (void *)123}; 384 1.1 christos void *handle = hook_install(TSDN_NULL, &hooks); 385 1.1 christos expect_ptr_ne(handle, NULL, "Hook installation failed"); 386 1.1 christos 387 1.1 christos void *volatile ptr; 388 1.1 christos 389 1.1 christos /* xallocx() */ 390 1.1 christos reset(); 391 1.1 christos ptr = malloc(1); 392 1.1 christos size_t new_usize = xallocx(ptr, 100, 200, MALLOCX_TCACHE_NONE); 393 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 394 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 395 1.1 christos expect_d_eq(arg_type, (int)hook_expand_xallocx, "Wrong hook type"); 396 1.1 christos expect_ptr_eq(ptr, arg_address, "Wrong pointer expanded"); 397 1.1 christos expect_u64_eq(arg_old_usize, nallocx(1, 0), "Wrong old usize"); 398 1.1 christos expect_u64_eq(arg_new_usize, sallocx(ptr, 0), "Wrong new usize"); 399 1.1 christos expect_u64_eq(new_usize, arg_result_raw, "Wrong result"); 400 1.1 christos expect_u64_eq((uintptr_t)ptr, arg_args_raw[0], "Wrong arg"); 401 1.1 christos expect_u64_eq(100, arg_args_raw[1], "Wrong arg"); 402 1.1 christos expect_u64_eq(200, arg_args_raw[2], "Wrong arg"); 403 1.1 christos expect_u64_eq(MALLOCX_TCACHE_NONE, arg_args_raw[3], "Wrong arg"); 404 1.1 christos 405 1.1 christos hook_remove(TSDN_NULL, handle); 406 1.1 christos } 407 1.1 christos TEST_END 408 1.1 christos 409 1.1 christos TEST_BEGIN(test_hooks_realloc_as_malloc_or_free) { 410 1.1 christos hooks_t hooks = {&test_alloc_hook, &test_dalloc_hook, 411 1.1 christos &test_expand_hook, (void *)123}; 412 1.1 christos void *handle = hook_install(TSDN_NULL, &hooks); 413 1.1 christos expect_ptr_ne(handle, NULL, "Hook installation failed"); 414 1.1 christos 415 1.1 christos void *volatile ptr; 416 1.1 christos 417 1.1 christos /* realloc(NULL, size) as malloc */ 418 1.1 christos reset(); 419 1.1 christos ptr = realloc(NULL, 1); 420 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 421 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 422 1.1 christos expect_d_eq(arg_type, (int)hook_alloc_realloc, "Wrong hook type"); 423 1.1 christos expect_ptr_eq(ptr, arg_result, "Wrong result"); 424 1.1 christos expect_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw, 425 1.1 christos "Wrong raw result"); 426 1.1 christos expect_u64_eq((uintptr_t)NULL, arg_args_raw[0], "Wrong argument"); 427 1.1 christos expect_u64_eq((uintptr_t)1, arg_args_raw[1], "Wrong argument"); 428 1.1 christos free(ptr); 429 1.1 christos 430 1.1 christos /* realloc(ptr, 0) as free */ 431 1.1 christos if (opt_zero_realloc_action == zero_realloc_action_free) { 432 1.1 christos ptr = malloc(1); 433 1.1 christos reset(); 434 1.1 christos realloc(ptr, 0); 435 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 436 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 437 1.1 christos expect_d_eq(arg_type, (int)hook_dalloc_realloc, 438 1.1 christos "Wrong hook type"); 439 1.1 christos expect_ptr_eq(ptr, arg_address, 440 1.1 christos "Wrong pointer freed"); 441 1.1 christos expect_u64_eq((uintptr_t)ptr, arg_args_raw[0], 442 1.1 christos "Wrong raw arg"); 443 1.1 christos expect_u64_eq((uintptr_t)0, arg_args_raw[1], 444 1.1 christos "Wrong raw arg"); 445 1.1 christos } 446 1.1 christos 447 1.1 christos /* realloc(NULL, 0) as malloc(0) */ 448 1.1 christos reset(); 449 1.1 christos ptr = realloc(NULL, 0); 450 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 451 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 452 1.1 christos expect_d_eq(arg_type, (int)hook_alloc_realloc, "Wrong hook type"); 453 1.1 christos expect_ptr_eq(ptr, arg_result, "Wrong result"); 454 1.1 christos expect_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw, 455 1.1 christos "Wrong raw result"); 456 1.1 christos expect_u64_eq((uintptr_t)NULL, arg_args_raw[0], "Wrong argument"); 457 1.1 christos expect_u64_eq((uintptr_t)0, arg_args_raw[1], "Wrong argument"); 458 1.1 christos free(ptr); 459 1.1 christos 460 1.1 christos hook_remove(TSDN_NULL, handle); 461 1.1 christos } 462 1.1 christos TEST_END 463 1.1 christos 464 1.1 christos static void 465 1.1 christos do_realloc_test(void *(*ralloc)(void *, size_t, int), int flags, 466 1.1 christos int expand_type, int dalloc_type) { 467 1.1 christos hooks_t hooks = {&test_alloc_hook, &test_dalloc_hook, 468 1.1 christos &test_expand_hook, (void *)123}; 469 1.1 christos void *handle = hook_install(TSDN_NULL, &hooks); 470 1.1 christos expect_ptr_ne(handle, NULL, "Hook installation failed"); 471 1.1 christos 472 1.1 christos void *volatile ptr; 473 1.1 christos void *volatile ptr2; 474 1.1 christos 475 1.1 christos /* Realloc in-place, small. */ 476 1.1 christos ptr = malloc(129); 477 1.1 christos reset(); 478 1.1 christos ptr2 = ralloc(ptr, 130, flags); 479 1.1 christos expect_ptr_eq(ptr, ptr2, "Small realloc moved"); 480 1.1 christos 481 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 482 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 483 1.1 christos expect_d_eq(arg_type, expand_type, "Wrong hook type"); 484 1.1 christos expect_ptr_eq(ptr, arg_address, "Wrong address"); 485 1.1 christos expect_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw, 486 1.1 christos "Wrong raw result"); 487 1.1 christos expect_u64_eq((uintptr_t)ptr, arg_args_raw[0], "Wrong argument"); 488 1.1 christos expect_u64_eq((uintptr_t)130, arg_args_raw[1], "Wrong argument"); 489 1.1 christos free(ptr); 490 1.1 christos 491 1.1 christos /* 492 1.1 christos * Realloc in-place, large. Since we can't guarantee the large case 493 1.1 christos * across all platforms, we stay resilient to moving results. 494 1.1 christos */ 495 1.1 christos ptr = malloc(2 * 1024 * 1024); 496 1.1 christos free(ptr); 497 1.1 christos ptr2 = malloc(1 * 1024 * 1024); 498 1.1 christos reset(); 499 1.1 christos ptr = ralloc(ptr2, 2 * 1024 * 1024, flags); 500 1.1 christos /* ptr is the new address, ptr2 is the old address. */ 501 1.1 christos if (ptr == ptr2) { 502 1.1 christos expect_d_eq(call_count, 1, "Hook not called"); 503 1.1 christos expect_d_eq(arg_type, expand_type, "Wrong hook type"); 504 1.1 christos } else { 505 1.1 christos expect_d_eq(call_count, 2, "Wrong hooks called"); 506 1.1 christos expect_ptr_eq(ptr, arg_result, "Wrong address"); 507 1.1 christos expect_d_eq(arg_type, dalloc_type, "Wrong hook type"); 508 1.1 christos } 509 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 510 1.1 christos expect_ptr_eq(ptr2, arg_address, "Wrong address"); 511 1.1 christos expect_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw, 512 1.1 christos "Wrong raw result"); 513 1.1 christos expect_u64_eq((uintptr_t)ptr2, arg_args_raw[0], "Wrong argument"); 514 1.1 christos expect_u64_eq((uintptr_t)2 * 1024 * 1024, arg_args_raw[1], 515 1.1 christos "Wrong argument"); 516 1.1 christos free(ptr); 517 1.1 christos 518 1.1 christos /* Realloc with move, small. */ 519 1.1 christos ptr = malloc(8); 520 1.1 christos reset(); 521 1.1 christos ptr2 = ralloc(ptr, 128, flags); 522 1.1 christos expect_ptr_ne(ptr, ptr2, "Small realloc didn't move"); 523 1.1 christos 524 1.1 christos expect_d_eq(call_count, 2, "Hook not called"); 525 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 526 1.1 christos expect_d_eq(arg_type, dalloc_type, "Wrong hook type"); 527 1.1 christos expect_ptr_eq(ptr, arg_address, "Wrong address"); 528 1.1 christos expect_ptr_eq(ptr2, arg_result, "Wrong address"); 529 1.1 christos expect_u64_eq((uintptr_t)ptr2, (uintptr_t)arg_result_raw, 530 1.1 christos "Wrong raw result"); 531 1.1 christos expect_u64_eq((uintptr_t)ptr, arg_args_raw[0], "Wrong argument"); 532 1.1 christos expect_u64_eq((uintptr_t)128, arg_args_raw[1], "Wrong argument"); 533 1.1 christos free(ptr2); 534 1.1 christos 535 1.1 christos /* Realloc with move, large. */ 536 1.1 christos ptr = malloc(1); 537 1.1 christos reset(); 538 1.1 christos ptr2 = ralloc(ptr, 2 * 1024 * 1024, flags); 539 1.1 christos expect_ptr_ne(ptr, ptr2, "Large realloc didn't move"); 540 1.1 christos 541 1.1 christos expect_d_eq(call_count, 2, "Hook not called"); 542 1.1 christos expect_ptr_eq(arg_extra, (void *)123, "Wrong extra"); 543 1.1 christos expect_d_eq(arg_type, dalloc_type, "Wrong hook type"); 544 1.1 christos expect_ptr_eq(ptr, arg_address, "Wrong address"); 545 1.1 christos expect_ptr_eq(ptr2, arg_result, "Wrong address"); 546 1.1 christos expect_u64_eq((uintptr_t)ptr2, (uintptr_t)arg_result_raw, 547 1.1 christos "Wrong raw result"); 548 1.1 christos expect_u64_eq((uintptr_t)ptr, arg_args_raw[0], "Wrong argument"); 549 1.1 christos expect_u64_eq((uintptr_t)2 * 1024 * 1024, arg_args_raw[1], 550 1.1 christos "Wrong argument"); 551 1.1 christos free(ptr2); 552 1.1 christos 553 1.1 christos hook_remove(TSDN_NULL, handle); 554 1.1 christos } 555 1.1 christos 556 1.1 christos static void * 557 1.1 christos realloc_wrapper(void *ptr, size_t size, UNUSED int flags) { 558 1.1 christos return realloc(ptr, size); 559 1.1 christos } 560 1.1 christos 561 1.1 christos TEST_BEGIN(test_hooks_realloc) { 562 1.1 christos do_realloc_test(&realloc_wrapper, 0, hook_expand_realloc, 563 1.1 christos hook_dalloc_realloc); 564 1.1 christos } 565 1.1 christos TEST_END 566 1.1 christos 567 1.1 christos TEST_BEGIN(test_hooks_rallocx) { 568 1.1 christos do_realloc_test(&rallocx, MALLOCX_TCACHE_NONE, hook_expand_rallocx, 569 1.1 christos hook_dalloc_rallocx); 570 1.1 christos } 571 1.1 christos TEST_END 572 1.1 christos 573 1.1 christos int 574 1.1 christos main(void) { 575 1.1 christos /* We assert on call counts. */ 576 1.1 christos return test_no_reentrancy( 577 1.1 christos test_hooks_basic, 578 1.1 christos test_hooks_null, 579 1.1 christos test_hooks_remove, 580 1.1 christos test_hooks_alloc_simple, 581 1.1 christos test_hooks_dalloc_simple, 582 1.1 christos test_hooks_expand_simple, 583 1.1 christos test_hooks_realloc_as_malloc_or_free, 584 1.1 christos test_hooks_realloc, 585 1.1 christos test_hooks_rallocx); 586 1.1 christos } 587