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