1*7bdf38e5Schristos #include "test/jemalloc_test.h" 2*7bdf38e5Schristos #include "test/san.h" 3*7bdf38e5Schristos 4*7bdf38e5Schristos const char *malloc_conf = TEST_SAN_UAF_ALIGN_DISABLE; 5*7bdf38e5Schristos 6*7bdf38e5Schristos enum { 7*7bdf38e5Schristos alloc_option_start = 0, 8*7bdf38e5Schristos use_malloc = 0, 9*7bdf38e5Schristos use_mallocx, 10*7bdf38e5Schristos alloc_option_end 11*7bdf38e5Schristos }; 12*7bdf38e5Schristos 13*7bdf38e5Schristos enum { 14*7bdf38e5Schristos dalloc_option_start = 0, 15*7bdf38e5Schristos use_free = 0, 16*7bdf38e5Schristos use_dallocx, 17*7bdf38e5Schristos use_sdallocx, 18*7bdf38e5Schristos dalloc_option_end 19*7bdf38e5Schristos }; 20*7bdf38e5Schristos 21*7bdf38e5Schristos static unsigned alloc_option, dalloc_option; 22*7bdf38e5Schristos static size_t tcache_max; 23*7bdf38e5Schristos 24*7bdf38e5Schristos static void * 25*7bdf38e5Schristos alloc_func(size_t sz) { 26*7bdf38e5Schristos void *ret; 27*7bdf38e5Schristos 28*7bdf38e5Schristos switch (alloc_option) { 29*7bdf38e5Schristos case use_malloc: 30*7bdf38e5Schristos ret = malloc(sz); 31*7bdf38e5Schristos break; 32*7bdf38e5Schristos case use_mallocx: 33*7bdf38e5Schristos ret = mallocx(sz, 0); 34*7bdf38e5Schristos break; 35*7bdf38e5Schristos default: 36*7bdf38e5Schristos unreachable(); 37*7bdf38e5Schristos } 38*7bdf38e5Schristos expect_ptr_not_null(ret, "Unexpected malloc / mallocx failure"); 39*7bdf38e5Schristos 40*7bdf38e5Schristos return ret; 41*7bdf38e5Schristos } 42*7bdf38e5Schristos 43*7bdf38e5Schristos static void 44*7bdf38e5Schristos dalloc_func(void *ptr, size_t sz) { 45*7bdf38e5Schristos switch (dalloc_option) { 46*7bdf38e5Schristos case use_free: 47*7bdf38e5Schristos free(ptr); 48*7bdf38e5Schristos break; 49*7bdf38e5Schristos case use_dallocx: 50*7bdf38e5Schristos dallocx(ptr, 0); 51*7bdf38e5Schristos break; 52*7bdf38e5Schristos case use_sdallocx: 53*7bdf38e5Schristos sdallocx(ptr, sz, 0); 54*7bdf38e5Schristos break; 55*7bdf38e5Schristos default: 56*7bdf38e5Schristos unreachable(); 57*7bdf38e5Schristos } 58*7bdf38e5Schristos } 59*7bdf38e5Schristos 60*7bdf38e5Schristos static size_t 61*7bdf38e5Schristos tcache_bytes_read(void) { 62*7bdf38e5Schristos uint64_t epoch; 63*7bdf38e5Schristos assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), 64*7bdf38e5Schristos 0, "Unexpected mallctl() failure"); 65*7bdf38e5Schristos 66*7bdf38e5Schristos size_t tcache_bytes; 67*7bdf38e5Schristos size_t sz = sizeof(tcache_bytes); 68*7bdf38e5Schristos assert_d_eq(mallctl( 69*7bdf38e5Schristos "stats.arenas." STRINGIFY(MALLCTL_ARENAS_ALL) ".tcache_bytes", 70*7bdf38e5Schristos &tcache_bytes, &sz, NULL, 0), 0, "Unexpected mallctl failure"); 71*7bdf38e5Schristos 72*7bdf38e5Schristos return tcache_bytes; 73*7bdf38e5Schristos } 74*7bdf38e5Schristos 75*7bdf38e5Schristos static void 76*7bdf38e5Schristos tcache_bytes_check_update(size_t *prev, ssize_t diff) { 77*7bdf38e5Schristos size_t tcache_bytes = tcache_bytes_read(); 78*7bdf38e5Schristos expect_zu_eq(tcache_bytes, *prev + diff, "tcache bytes not expected"); 79*7bdf38e5Schristos 80*7bdf38e5Schristos *prev += diff; 81*7bdf38e5Schristos } 82*7bdf38e5Schristos 83*7bdf38e5Schristos static void 84*7bdf38e5Schristos test_tcache_bytes_alloc(size_t alloc_size) { 85*7bdf38e5Schristos expect_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), 0, 86*7bdf38e5Schristos "Unexpected tcache flush failure"); 87*7bdf38e5Schristos 88*7bdf38e5Schristos size_t usize = sz_s2u(alloc_size); 89*7bdf38e5Schristos /* No change is expected if usize is outside of tcache_max range. */ 90*7bdf38e5Schristos bool cached = (usize <= tcache_max); 91*7bdf38e5Schristos ssize_t diff = cached ? usize : 0; 92*7bdf38e5Schristos 93*7bdf38e5Schristos void *ptr1 = alloc_func(alloc_size); 94*7bdf38e5Schristos void *ptr2 = alloc_func(alloc_size); 95*7bdf38e5Schristos 96*7bdf38e5Schristos size_t bytes = tcache_bytes_read(); 97*7bdf38e5Schristos dalloc_func(ptr2, alloc_size); 98*7bdf38e5Schristos /* Expect tcache_bytes increase after dalloc */ 99*7bdf38e5Schristos tcache_bytes_check_update(&bytes, diff); 100*7bdf38e5Schristos 101*7bdf38e5Schristos dalloc_func(ptr1, alloc_size); 102*7bdf38e5Schristos /* Expect tcache_bytes increase again */ 103*7bdf38e5Schristos tcache_bytes_check_update(&bytes, diff); 104*7bdf38e5Schristos 105*7bdf38e5Schristos void *ptr3 = alloc_func(alloc_size); 106*7bdf38e5Schristos if (cached) { 107*7bdf38e5Schristos expect_ptr_eq(ptr1, ptr3, "Unexpected cached ptr"); 108*7bdf38e5Schristos } 109*7bdf38e5Schristos /* Expect tcache_bytes decrease after alloc */ 110*7bdf38e5Schristos tcache_bytes_check_update(&bytes, -diff); 111*7bdf38e5Schristos 112*7bdf38e5Schristos void *ptr4 = alloc_func(alloc_size); 113*7bdf38e5Schristos if (cached) { 114*7bdf38e5Schristos expect_ptr_eq(ptr2, ptr4, "Unexpected cached ptr"); 115*7bdf38e5Schristos } 116*7bdf38e5Schristos /* Expect tcache_bytes decrease again */ 117*7bdf38e5Schristos tcache_bytes_check_update(&bytes, -diff); 118*7bdf38e5Schristos 119*7bdf38e5Schristos dalloc_func(ptr3, alloc_size); 120*7bdf38e5Schristos tcache_bytes_check_update(&bytes, diff); 121*7bdf38e5Schristos dalloc_func(ptr4, alloc_size); 122*7bdf38e5Schristos tcache_bytes_check_update(&bytes, diff); 123*7bdf38e5Schristos } 124*7bdf38e5Schristos 125*7bdf38e5Schristos static void 126*7bdf38e5Schristos test_tcache_max_impl(void) { 127*7bdf38e5Schristos size_t sz; 128*7bdf38e5Schristos sz = sizeof(tcache_max); 129*7bdf38e5Schristos assert_d_eq(mallctl("arenas.tcache_max", (void *)&tcache_max, 130*7bdf38e5Schristos &sz, NULL, 0), 0, "Unexpected mallctl() failure"); 131*7bdf38e5Schristos 132*7bdf38e5Schristos /* opt.tcache_max set to 1024 in tcache_max.sh */ 133*7bdf38e5Schristos expect_zu_eq(tcache_max, 1024, "tcache_max not expected"); 134*7bdf38e5Schristos 135*7bdf38e5Schristos test_tcache_bytes_alloc(1); 136*7bdf38e5Schristos test_tcache_bytes_alloc(tcache_max - 1); 137*7bdf38e5Schristos test_tcache_bytes_alloc(tcache_max); 138*7bdf38e5Schristos test_tcache_bytes_alloc(tcache_max + 1); 139*7bdf38e5Schristos 140*7bdf38e5Schristos test_tcache_bytes_alloc(PAGE - 1); 141*7bdf38e5Schristos test_tcache_bytes_alloc(PAGE); 142*7bdf38e5Schristos test_tcache_bytes_alloc(PAGE + 1); 143*7bdf38e5Schristos 144*7bdf38e5Schristos size_t large; 145*7bdf38e5Schristos sz = sizeof(large); 146*7bdf38e5Schristos assert_d_eq(mallctl("arenas.lextent.0.size", (void *)&large, &sz, NULL, 147*7bdf38e5Schristos 0), 0, "Unexpected mallctl() failure"); 148*7bdf38e5Schristos 149*7bdf38e5Schristos test_tcache_bytes_alloc(large - 1); 150*7bdf38e5Schristos test_tcache_bytes_alloc(large); 151*7bdf38e5Schristos test_tcache_bytes_alloc(large + 1); 152*7bdf38e5Schristos } 153*7bdf38e5Schristos 154*7bdf38e5Schristos TEST_BEGIN(test_tcache_max) { 155*7bdf38e5Schristos test_skip_if(!config_stats); 156*7bdf38e5Schristos test_skip_if(!opt_tcache); 157*7bdf38e5Schristos test_skip_if(opt_prof); 158*7bdf38e5Schristos test_skip_if(san_uaf_detection_enabled()); 159*7bdf38e5Schristos 160*7bdf38e5Schristos for (alloc_option = alloc_option_start; 161*7bdf38e5Schristos alloc_option < alloc_option_end; 162*7bdf38e5Schristos alloc_option++) { 163*7bdf38e5Schristos for (dalloc_option = dalloc_option_start; 164*7bdf38e5Schristos dalloc_option < dalloc_option_end; 165*7bdf38e5Schristos dalloc_option++) { 166*7bdf38e5Schristos test_tcache_max_impl(); 167*7bdf38e5Schristos } 168*7bdf38e5Schristos } 169*7bdf38e5Schristos } 170*7bdf38e5Schristos TEST_END 171*7bdf38e5Schristos 172*7bdf38e5Schristos int 173*7bdf38e5Schristos main(void) { 174*7bdf38e5Schristos return test(test_tcache_max); 175*7bdf38e5Schristos } 176