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