xref: /netbsd-src/external/bsd/jemalloc/dist/test/unit/tcache_max.c (revision 7bdf38e5b7a28439665f2fdeff81e36913eef7dd)
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