1*8e33eff8Schristos #include "test/jemalloc_test.h" 2*8e33eff8Schristos 3*8e33eff8Schristos /* Test status state. */ 4*8e33eff8Schristos 5*8e33eff8Schristos static unsigned test_count = 0; 6*8e33eff8Schristos static test_status_t test_counts[test_status_count] = {0, 0, 0}; 7*8e33eff8Schristos static test_status_t test_status = test_status_pass; 8*8e33eff8Schristos static const char * test_name = ""; 9*8e33eff8Schristos 10*8e33eff8Schristos /* Reentrancy testing helpers. */ 11*8e33eff8Schristos 12*8e33eff8Schristos #define NUM_REENTRANT_ALLOCS 20 13*8e33eff8Schristos typedef enum { 14*8e33eff8Schristos non_reentrant = 0, 15*8e33eff8Schristos libc_reentrant = 1, 16*8e33eff8Schristos arena_new_reentrant = 2 17*8e33eff8Schristos } reentrancy_t; 18*8e33eff8Schristos static reentrancy_t reentrancy; 19*8e33eff8Schristos 20*8e33eff8Schristos static bool libc_hook_ran = false; 21*8e33eff8Schristos static bool arena_new_hook_ran = false; 22*8e33eff8Schristos 23*8e33eff8Schristos static const char * 24*8e33eff8Schristos reentrancy_t_str(reentrancy_t r) { 25*8e33eff8Schristos switch (r) { 26*8e33eff8Schristos case non_reentrant: 27*8e33eff8Schristos return "non-reentrant"; 28*8e33eff8Schristos case libc_reentrant: 29*8e33eff8Schristos return "libc-reentrant"; 30*8e33eff8Schristos case arena_new_reentrant: 31*8e33eff8Schristos return "arena_new-reentrant"; 32*8e33eff8Schristos default: 33*8e33eff8Schristos unreachable(); 34*8e33eff8Schristos } 35*8e33eff8Schristos } 36*8e33eff8Schristos 37*8e33eff8Schristos static void 38*8e33eff8Schristos do_hook(bool *hook_ran, void (**hook)()) { 39*8e33eff8Schristos *hook_ran = true; 40*8e33eff8Schristos *hook = NULL; 41*8e33eff8Schristos 42*8e33eff8Schristos size_t alloc_size = 1; 43*8e33eff8Schristos for (int i = 0; i < NUM_REENTRANT_ALLOCS; i++) { 44*8e33eff8Schristos free(malloc(alloc_size)); 45*8e33eff8Schristos alloc_size *= 2; 46*8e33eff8Schristos } 47*8e33eff8Schristos } 48*8e33eff8Schristos 49*8e33eff8Schristos static void 50*8e33eff8Schristos libc_reentrancy_hook() { 51*8e33eff8Schristos do_hook(&libc_hook_ran, &hooks_libc_hook); 52*8e33eff8Schristos } 53*8e33eff8Schristos 54*8e33eff8Schristos static void 55*8e33eff8Schristos arena_new_reentrancy_hook() { 56*8e33eff8Schristos do_hook(&arena_new_hook_ran, &hooks_arena_new_hook); 57*8e33eff8Schristos } 58*8e33eff8Schristos 59*8e33eff8Schristos /* Actual test infrastructure. */ 60*8e33eff8Schristos bool 61*8e33eff8Schristos test_is_reentrant() { 62*8e33eff8Schristos return reentrancy != non_reentrant; 63*8e33eff8Schristos } 64*8e33eff8Schristos 65*8e33eff8Schristos JEMALLOC_FORMAT_PRINTF(1, 2) 66*8e33eff8Schristos void 67*8e33eff8Schristos test_skip(const char *format, ...) { 68*8e33eff8Schristos va_list ap; 69*8e33eff8Schristos 70*8e33eff8Schristos va_start(ap, format); 71*8e33eff8Schristos malloc_vcprintf(NULL, NULL, format, ap); 72*8e33eff8Schristos va_end(ap); 73*8e33eff8Schristos malloc_printf("\n"); 74*8e33eff8Schristos test_status = test_status_skip; 75*8e33eff8Schristos } 76*8e33eff8Schristos 77*8e33eff8Schristos JEMALLOC_FORMAT_PRINTF(1, 2) 78*8e33eff8Schristos void 79*8e33eff8Schristos test_fail(const char *format, ...) { 80*8e33eff8Schristos va_list ap; 81*8e33eff8Schristos 82*8e33eff8Schristos va_start(ap, format); 83*8e33eff8Schristos malloc_vcprintf(NULL, NULL, format, ap); 84*8e33eff8Schristos va_end(ap); 85*8e33eff8Schristos malloc_printf("\n"); 86*8e33eff8Schristos test_status = test_status_fail; 87*8e33eff8Schristos } 88*8e33eff8Schristos 89*8e33eff8Schristos static const char * 90*8e33eff8Schristos test_status_string(test_status_t test_status) { 91*8e33eff8Schristos switch (test_status) { 92*8e33eff8Schristos case test_status_pass: return "pass"; 93*8e33eff8Schristos case test_status_skip: return "skip"; 94*8e33eff8Schristos case test_status_fail: return "fail"; 95*8e33eff8Schristos default: not_reached(); 96*8e33eff8Schristos } 97*8e33eff8Schristos } 98*8e33eff8Schristos 99*8e33eff8Schristos void 100*8e33eff8Schristos p_test_init(const char *name) { 101*8e33eff8Schristos test_count++; 102*8e33eff8Schristos test_status = test_status_pass; 103*8e33eff8Schristos test_name = name; 104*8e33eff8Schristos } 105*8e33eff8Schristos 106*8e33eff8Schristos void 107*8e33eff8Schristos p_test_fini(void) { 108*8e33eff8Schristos test_counts[test_status]++; 109*8e33eff8Schristos malloc_printf("%s (%s): %s\n", test_name, reentrancy_t_str(reentrancy), 110*8e33eff8Schristos test_status_string(test_status)); 111*8e33eff8Schristos } 112*8e33eff8Schristos 113*8e33eff8Schristos static test_status_t 114*8e33eff8Schristos p_test_impl(bool do_malloc_init, bool do_reentrant, test_t *t, va_list ap) { 115*8e33eff8Schristos test_status_t ret; 116*8e33eff8Schristos 117*8e33eff8Schristos if (do_malloc_init) { 118*8e33eff8Schristos /* 119*8e33eff8Schristos * Make sure initialization occurs prior to running tests. 120*8e33eff8Schristos * Tests are special because they may use internal facilities 121*8e33eff8Schristos * prior to triggering initialization as a side effect of 122*8e33eff8Schristos * calling into the public API. 123*8e33eff8Schristos */ 124*8e33eff8Schristos if (nallocx(1, 0) == 0) { 125*8e33eff8Schristos malloc_printf("Initialization error"); 126*8e33eff8Schristos return test_status_fail; 127*8e33eff8Schristos } 128*8e33eff8Schristos } 129*8e33eff8Schristos 130*8e33eff8Schristos ret = test_status_pass; 131*8e33eff8Schristos for (; t != NULL; t = va_arg(ap, test_t *)) { 132*8e33eff8Schristos /* Non-reentrant run. */ 133*8e33eff8Schristos reentrancy = non_reentrant; 134*8e33eff8Schristos hooks_arena_new_hook = hooks_libc_hook = NULL; 135*8e33eff8Schristos t(); 136*8e33eff8Schristos if (test_status > ret) { 137*8e33eff8Schristos ret = test_status; 138*8e33eff8Schristos } 139*8e33eff8Schristos /* Reentrant run. */ 140*8e33eff8Schristos if (do_reentrant) { 141*8e33eff8Schristos reentrancy = libc_reentrant; 142*8e33eff8Schristos hooks_arena_new_hook = NULL; 143*8e33eff8Schristos hooks_libc_hook = &libc_reentrancy_hook; 144*8e33eff8Schristos t(); 145*8e33eff8Schristos if (test_status > ret) { 146*8e33eff8Schristos ret = test_status; 147*8e33eff8Schristos } 148*8e33eff8Schristos 149*8e33eff8Schristos reentrancy = arena_new_reentrant; 150*8e33eff8Schristos hooks_libc_hook = NULL; 151*8e33eff8Schristos hooks_arena_new_hook = &arena_new_reentrancy_hook; 152*8e33eff8Schristos t(); 153*8e33eff8Schristos if (test_status > ret) { 154*8e33eff8Schristos ret = test_status; 155*8e33eff8Schristos } 156*8e33eff8Schristos } 157*8e33eff8Schristos } 158*8e33eff8Schristos 159*8e33eff8Schristos malloc_printf("--- %s: %u/%u, %s: %u/%u, %s: %u/%u ---\n", 160*8e33eff8Schristos test_status_string(test_status_pass), 161*8e33eff8Schristos test_counts[test_status_pass], test_count, 162*8e33eff8Schristos test_status_string(test_status_skip), 163*8e33eff8Schristos test_counts[test_status_skip], test_count, 164*8e33eff8Schristos test_status_string(test_status_fail), 165*8e33eff8Schristos test_counts[test_status_fail], test_count); 166*8e33eff8Schristos 167*8e33eff8Schristos return ret; 168*8e33eff8Schristos } 169*8e33eff8Schristos 170*8e33eff8Schristos test_status_t 171*8e33eff8Schristos p_test(test_t *t, ...) { 172*8e33eff8Schristos test_status_t ret; 173*8e33eff8Schristos va_list ap; 174*8e33eff8Schristos 175*8e33eff8Schristos ret = test_status_pass; 176*8e33eff8Schristos va_start(ap, t); 177*8e33eff8Schristos ret = p_test_impl(true, true, t, ap); 178*8e33eff8Schristos va_end(ap); 179*8e33eff8Schristos 180*8e33eff8Schristos return ret; 181*8e33eff8Schristos } 182*8e33eff8Schristos 183*8e33eff8Schristos test_status_t 184*8e33eff8Schristos p_test_no_reentrancy(test_t *t, ...) { 185*8e33eff8Schristos test_status_t ret; 186*8e33eff8Schristos va_list ap; 187*8e33eff8Schristos 188*8e33eff8Schristos ret = test_status_pass; 189*8e33eff8Schristos va_start(ap, t); 190*8e33eff8Schristos ret = p_test_impl(true, false, t, ap); 191*8e33eff8Schristos va_end(ap); 192*8e33eff8Schristos 193*8e33eff8Schristos return ret; 194*8e33eff8Schristos } 195*8e33eff8Schristos 196*8e33eff8Schristos test_status_t 197*8e33eff8Schristos p_test_no_malloc_init(test_t *t, ...) { 198*8e33eff8Schristos test_status_t ret; 199*8e33eff8Schristos va_list ap; 200*8e33eff8Schristos 201*8e33eff8Schristos ret = test_status_pass; 202*8e33eff8Schristos va_start(ap, t); 203*8e33eff8Schristos /* 204*8e33eff8Schristos * We also omit reentrancy from bootstrapping tests, since we don't 205*8e33eff8Schristos * (yet) care about general reentrancy during bootstrapping. 206*8e33eff8Schristos */ 207*8e33eff8Schristos ret = p_test_impl(false, false, t, ap); 208*8e33eff8Schristos va_end(ap); 209*8e33eff8Schristos 210*8e33eff8Schristos return ret; 211*8e33eff8Schristos } 212*8e33eff8Schristos 213*8e33eff8Schristos void 214*8e33eff8Schristos p_test_fail(const char *prefix, const char *message) { 215*8e33eff8Schristos malloc_cprintf(NULL, NULL, "%s%s\n", prefix, message); 216*8e33eff8Schristos test_status = test_status_fail; 217*8e33eff8Schristos } 218