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