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