xref: /netbsd-src/external/bsd/jemalloc.old/dist/test/src/test.c (revision 8e33eff89e26cf71871ead62f0d5063e1313c33a)
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