xref: /netbsd-src/external/bsd/jemalloc/dist/test/integration/xallocx.c (revision 7bdf38e5b7a28439665f2fdeff81e36913eef7dd)
1a0698ed9Schristos #include "test/jemalloc_test.h"
2a0698ed9Schristos 
3a0698ed9Schristos /*
4a0698ed9Schristos  * Use a separate arena for xallocx() extension/contraction tests so that
5a0698ed9Schristos  * internal allocation e.g. by heap profiling can't interpose allocations where
6a0698ed9Schristos  * xallocx() would ordinarily be able to extend.
7a0698ed9Schristos  */
8a0698ed9Schristos static unsigned
9a0698ed9Schristos arena_ind(void) {
10a0698ed9Schristos 	static unsigned ind = 0;
11a0698ed9Schristos 
12a0698ed9Schristos 	if (ind == 0) {
13a0698ed9Schristos 		size_t sz = sizeof(ind);
14*7bdf38e5Schristos 		expect_d_eq(mallctl("arenas.create", (void *)&ind, &sz, NULL,
15a0698ed9Schristos 		    0), 0, "Unexpected mallctl failure creating arena");
16a0698ed9Schristos 	}
17a0698ed9Schristos 
18a0698ed9Schristos 	return ind;
19a0698ed9Schristos }
20a0698ed9Schristos 
21a0698ed9Schristos TEST_BEGIN(test_same_size) {
22a0698ed9Schristos 	void *p;
23a0698ed9Schristos 	size_t sz, tsz;
24a0698ed9Schristos 
25a0698ed9Schristos 	p = mallocx(42, 0);
26*7bdf38e5Schristos 	expect_ptr_not_null(p, "Unexpected mallocx() error");
27a0698ed9Schristos 	sz = sallocx(p, 0);
28a0698ed9Schristos 
29a0698ed9Schristos 	tsz = xallocx(p, sz, 0, 0);
30*7bdf38e5Schristos 	expect_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz);
31a0698ed9Schristos 
32a0698ed9Schristos 	dallocx(p, 0);
33a0698ed9Schristos }
34a0698ed9Schristos TEST_END
35a0698ed9Schristos 
36a0698ed9Schristos TEST_BEGIN(test_extra_no_move) {
37a0698ed9Schristos 	void *p;
38a0698ed9Schristos 	size_t sz, tsz;
39a0698ed9Schristos 
40a0698ed9Schristos 	p = mallocx(42, 0);
41*7bdf38e5Schristos 	expect_ptr_not_null(p, "Unexpected mallocx() error");
42a0698ed9Schristos 	sz = sallocx(p, 0);
43a0698ed9Schristos 
44a0698ed9Schristos 	tsz = xallocx(p, sz, sz-42, 0);
45*7bdf38e5Schristos 	expect_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz);
46a0698ed9Schristos 
47a0698ed9Schristos 	dallocx(p, 0);
48a0698ed9Schristos }
49a0698ed9Schristos TEST_END
50a0698ed9Schristos 
51a0698ed9Schristos TEST_BEGIN(test_no_move_fail) {
52a0698ed9Schristos 	void *p;
53a0698ed9Schristos 	size_t sz, tsz;
54a0698ed9Schristos 
55a0698ed9Schristos 	p = mallocx(42, 0);
56*7bdf38e5Schristos 	expect_ptr_not_null(p, "Unexpected mallocx() error");
57a0698ed9Schristos 	sz = sallocx(p, 0);
58a0698ed9Schristos 
59a0698ed9Schristos 	tsz = xallocx(p, sz + 5, 0, 0);
60*7bdf38e5Schristos 	expect_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz);
61a0698ed9Schristos 
62a0698ed9Schristos 	dallocx(p, 0);
63a0698ed9Schristos }
64a0698ed9Schristos TEST_END
65a0698ed9Schristos 
66a0698ed9Schristos static unsigned
67a0698ed9Schristos get_nsizes_impl(const char *cmd) {
68a0698ed9Schristos 	unsigned ret;
69a0698ed9Schristos 	size_t z;
70a0698ed9Schristos 
71a0698ed9Schristos 	z = sizeof(unsigned);
72*7bdf38e5Schristos 	expect_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0,
73a0698ed9Schristos 	    "Unexpected mallctl(\"%s\", ...) failure", cmd);
74a0698ed9Schristos 
75a0698ed9Schristos 	return ret;
76a0698ed9Schristos }
77a0698ed9Schristos 
78a0698ed9Schristos static unsigned
79a0698ed9Schristos get_nsmall(void) {
80a0698ed9Schristos 	return get_nsizes_impl("arenas.nbins");
81a0698ed9Schristos }
82a0698ed9Schristos 
83a0698ed9Schristos static unsigned
84a0698ed9Schristos get_nlarge(void) {
85a0698ed9Schristos 	return get_nsizes_impl("arenas.nlextents");
86a0698ed9Schristos }
87a0698ed9Schristos 
88a0698ed9Schristos static size_t
89a0698ed9Schristos get_size_impl(const char *cmd, size_t ind) {
90a0698ed9Schristos 	size_t ret;
91a0698ed9Schristos 	size_t z;
92a0698ed9Schristos 	size_t mib[4];
93a0698ed9Schristos 	size_t miblen = 4;
94a0698ed9Schristos 
95a0698ed9Schristos 	z = sizeof(size_t);
96*7bdf38e5Schristos 	expect_d_eq(mallctlnametomib(cmd, mib, &miblen),
97a0698ed9Schristos 	    0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd);
98a0698ed9Schristos 	mib[2] = ind;
99a0698ed9Schristos 	z = sizeof(size_t);
100*7bdf38e5Schristos 	expect_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0),
101a0698ed9Schristos 	    0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind);
102a0698ed9Schristos 
103a0698ed9Schristos 	return ret;
104a0698ed9Schristos }
105a0698ed9Schristos 
106a0698ed9Schristos static size_t
107a0698ed9Schristos get_small_size(size_t ind) {
108a0698ed9Schristos 	return get_size_impl("arenas.bin.0.size", ind);
109a0698ed9Schristos }
110a0698ed9Schristos 
111a0698ed9Schristos static size_t
112a0698ed9Schristos get_large_size(size_t ind) {
113a0698ed9Schristos 	return get_size_impl("arenas.lextent.0.size", ind);
114a0698ed9Schristos }
115a0698ed9Schristos 
116a0698ed9Schristos TEST_BEGIN(test_size) {
117a0698ed9Schristos 	size_t small0, largemax;
118a0698ed9Schristos 	void *p;
119a0698ed9Schristos 
120a0698ed9Schristos 	/* Get size classes. */
121a0698ed9Schristos 	small0 = get_small_size(0);
122a0698ed9Schristos 	largemax = get_large_size(get_nlarge()-1);
123a0698ed9Schristos 
124a0698ed9Schristos 	p = mallocx(small0, 0);
125*7bdf38e5Schristos 	expect_ptr_not_null(p, "Unexpected mallocx() error");
126a0698ed9Schristos 
127a0698ed9Schristos 	/* Test smallest supported size. */
128*7bdf38e5Schristos 	expect_zu_eq(xallocx(p, 1, 0, 0), small0,
129a0698ed9Schristos 	    "Unexpected xallocx() behavior");
130a0698ed9Schristos 
131a0698ed9Schristos 	/* Test largest supported size. */
132*7bdf38e5Schristos 	expect_zu_le(xallocx(p, largemax, 0, 0), largemax,
133a0698ed9Schristos 	    "Unexpected xallocx() behavior");
134a0698ed9Schristos 
135a0698ed9Schristos 	/* Test size overflow. */
136*7bdf38e5Schristos 	expect_zu_le(xallocx(p, largemax+1, 0, 0), largemax,
137a0698ed9Schristos 	    "Unexpected xallocx() behavior");
138*7bdf38e5Schristos 	expect_zu_le(xallocx(p, SIZE_T_MAX, 0, 0), largemax,
139a0698ed9Schristos 	    "Unexpected xallocx() behavior");
140a0698ed9Schristos 
141a0698ed9Schristos 	dallocx(p, 0);
142a0698ed9Schristos }
143a0698ed9Schristos TEST_END
144a0698ed9Schristos 
145a0698ed9Schristos TEST_BEGIN(test_size_extra_overflow) {
146a0698ed9Schristos 	size_t small0, largemax;
147a0698ed9Schristos 	void *p;
148a0698ed9Schristos 
149a0698ed9Schristos 	/* Get size classes. */
150a0698ed9Schristos 	small0 = get_small_size(0);
151a0698ed9Schristos 	largemax = get_large_size(get_nlarge()-1);
152a0698ed9Schristos 
153a0698ed9Schristos 	p = mallocx(small0, 0);
154*7bdf38e5Schristos 	expect_ptr_not_null(p, "Unexpected mallocx() error");
155a0698ed9Schristos 
156a0698ed9Schristos 	/* Test overflows that can be resolved by clamping extra. */
157*7bdf38e5Schristos 	expect_zu_le(xallocx(p, largemax-1, 2, 0), largemax,
158a0698ed9Schristos 	    "Unexpected xallocx() behavior");
159*7bdf38e5Schristos 	expect_zu_le(xallocx(p, largemax, 1, 0), largemax,
160a0698ed9Schristos 	    "Unexpected xallocx() behavior");
161a0698ed9Schristos 
162a0698ed9Schristos 	/* Test overflow such that largemax-size underflows. */
163*7bdf38e5Schristos 	expect_zu_le(xallocx(p, largemax+1, 2, 0), largemax,
164a0698ed9Schristos 	    "Unexpected xallocx() behavior");
165*7bdf38e5Schristos 	expect_zu_le(xallocx(p, largemax+2, 3, 0), largemax,
166a0698ed9Schristos 	    "Unexpected xallocx() behavior");
167*7bdf38e5Schristos 	expect_zu_le(xallocx(p, SIZE_T_MAX-2, 2, 0), largemax,
168a0698ed9Schristos 	    "Unexpected xallocx() behavior");
169*7bdf38e5Schristos 	expect_zu_le(xallocx(p, SIZE_T_MAX-1, 1, 0), largemax,
170a0698ed9Schristos 	    "Unexpected xallocx() behavior");
171a0698ed9Schristos 
172a0698ed9Schristos 	dallocx(p, 0);
173a0698ed9Schristos }
174a0698ed9Schristos TEST_END
175a0698ed9Schristos 
176a0698ed9Schristos TEST_BEGIN(test_extra_small) {
177a0698ed9Schristos 	size_t small0, small1, largemax;
178a0698ed9Schristos 	void *p;
179a0698ed9Schristos 
180a0698ed9Schristos 	/* Get size classes. */
181a0698ed9Schristos 	small0 = get_small_size(0);
182a0698ed9Schristos 	small1 = get_small_size(1);
183a0698ed9Schristos 	largemax = get_large_size(get_nlarge()-1);
184a0698ed9Schristos 
185a0698ed9Schristos 	p = mallocx(small0, 0);
186*7bdf38e5Schristos 	expect_ptr_not_null(p, "Unexpected mallocx() error");
187a0698ed9Schristos 
188*7bdf38e5Schristos 	expect_zu_eq(xallocx(p, small1, 0, 0), small0,
189a0698ed9Schristos 	    "Unexpected xallocx() behavior");
190a0698ed9Schristos 
191*7bdf38e5Schristos 	expect_zu_eq(xallocx(p, small1, 0, 0), small0,
192a0698ed9Schristos 	    "Unexpected xallocx() behavior");
193a0698ed9Schristos 
194*7bdf38e5Schristos 	expect_zu_eq(xallocx(p, small0, small1 - small0, 0), small0,
195a0698ed9Schristos 	    "Unexpected xallocx() behavior");
196a0698ed9Schristos 
197a0698ed9Schristos 	/* Test size+extra overflow. */
198*7bdf38e5Schristos 	expect_zu_eq(xallocx(p, small0, largemax - small0 + 1, 0), small0,
199a0698ed9Schristos 	    "Unexpected xallocx() behavior");
200*7bdf38e5Schristos 	expect_zu_eq(xallocx(p, small0, SIZE_T_MAX - small0, 0), small0,
201a0698ed9Schristos 	    "Unexpected xallocx() behavior");
202a0698ed9Schristos 
203a0698ed9Schristos 	dallocx(p, 0);
204a0698ed9Schristos }
205a0698ed9Schristos TEST_END
206a0698ed9Schristos 
207a0698ed9Schristos TEST_BEGIN(test_extra_large) {
208a0698ed9Schristos 	int flags = MALLOCX_ARENA(arena_ind());
209a0698ed9Schristos 	size_t smallmax, large1, large2, large3, largemax;
210a0698ed9Schristos 	void *p;
211a0698ed9Schristos 
212a0698ed9Schristos 	/* Get size classes. */
213a0698ed9Schristos 	smallmax = get_small_size(get_nsmall()-1);
214a0698ed9Schristos 	large1 = get_large_size(1);
215a0698ed9Schristos 	large2 = get_large_size(2);
216a0698ed9Schristos 	large3 = get_large_size(3);
217a0698ed9Schristos 	largemax = get_large_size(get_nlarge()-1);
218a0698ed9Schristos 
219a0698ed9Schristos 	p = mallocx(large3, flags);
220*7bdf38e5Schristos 	expect_ptr_not_null(p, "Unexpected mallocx() error");
221a0698ed9Schristos 
222*7bdf38e5Schristos 	expect_zu_eq(xallocx(p, large3, 0, flags), large3,
223a0698ed9Schristos 	    "Unexpected xallocx() behavior");
224a0698ed9Schristos 	/* Test size decrease with zero extra. */
225*7bdf38e5Schristos 	expect_zu_ge(xallocx(p, large1, 0, flags), large1,
226a0698ed9Schristos 	    "Unexpected xallocx() behavior");
227*7bdf38e5Schristos 	expect_zu_ge(xallocx(p, smallmax, 0, flags), large1,
228a0698ed9Schristos 	    "Unexpected xallocx() behavior");
229a0698ed9Schristos 
230a0698ed9Schristos 	if (xallocx(p, large3, 0, flags) != large3) {
231a0698ed9Schristos 		p = rallocx(p, large3, flags);
232*7bdf38e5Schristos 		expect_ptr_not_null(p, "Unexpected rallocx() failure");
233a0698ed9Schristos 	}
234a0698ed9Schristos 	/* Test size decrease with non-zero extra. */
235*7bdf38e5Schristos 	expect_zu_eq(xallocx(p, large1, large3 - large1, flags), large3,
236a0698ed9Schristos 	    "Unexpected xallocx() behavior");
237*7bdf38e5Schristos 	expect_zu_eq(xallocx(p, large2, large3 - large2, flags), large3,
238a0698ed9Schristos 	    "Unexpected xallocx() behavior");
239*7bdf38e5Schristos 	expect_zu_ge(xallocx(p, large1, large2 - large1, flags), large2,
240a0698ed9Schristos 	    "Unexpected xallocx() behavior");
241*7bdf38e5Schristos 	expect_zu_ge(xallocx(p, smallmax, large1 - smallmax, flags), large1,
242a0698ed9Schristos 	    "Unexpected xallocx() behavior");
243a0698ed9Schristos 
244*7bdf38e5Schristos 	expect_zu_ge(xallocx(p, large1, 0, flags), large1,
245a0698ed9Schristos 	    "Unexpected xallocx() behavior");
246a0698ed9Schristos 	/* Test size increase with zero extra. */
247*7bdf38e5Schristos 	expect_zu_le(xallocx(p, large3, 0, flags), large3,
248a0698ed9Schristos 	    "Unexpected xallocx() behavior");
249*7bdf38e5Schristos 	expect_zu_le(xallocx(p, largemax+1, 0, flags), large3,
250a0698ed9Schristos 	    "Unexpected xallocx() behavior");
251a0698ed9Schristos 
252*7bdf38e5Schristos 	expect_zu_ge(xallocx(p, large1, 0, flags), large1,
253a0698ed9Schristos 	    "Unexpected xallocx() behavior");
254a0698ed9Schristos 	/* Test size increase with non-zero extra. */
255*7bdf38e5Schristos 	expect_zu_le(xallocx(p, large1, SIZE_T_MAX - large1, flags), largemax,
256a0698ed9Schristos 	    "Unexpected xallocx() behavior");
257a0698ed9Schristos 
258*7bdf38e5Schristos 	expect_zu_ge(xallocx(p, large1, 0, flags), large1,
259a0698ed9Schristos 	    "Unexpected xallocx() behavior");
260a0698ed9Schristos 	/* Test size increase with non-zero extra. */
261*7bdf38e5Schristos 	expect_zu_le(xallocx(p, large1, large3 - large1, flags), large3,
262a0698ed9Schristos 	    "Unexpected xallocx() behavior");
263a0698ed9Schristos 
264a0698ed9Schristos 	if (xallocx(p, large3, 0, flags) != large3) {
265a0698ed9Schristos 		p = rallocx(p, large3, flags);
266*7bdf38e5Schristos 		expect_ptr_not_null(p, "Unexpected rallocx() failure");
267a0698ed9Schristos 	}
268a0698ed9Schristos 	/* Test size+extra overflow. */
269*7bdf38e5Schristos 	expect_zu_le(xallocx(p, large3, largemax - large3 + 1, flags), largemax,
270a0698ed9Schristos 	    "Unexpected xallocx() behavior");
271a0698ed9Schristos 
272a0698ed9Schristos 	dallocx(p, flags);
273a0698ed9Schristos }
274a0698ed9Schristos TEST_END
275a0698ed9Schristos 
276a0698ed9Schristos static void
277a0698ed9Schristos print_filled_extents(const void *p, uint8_t c, size_t len) {
278a0698ed9Schristos 	const uint8_t *pc = (const uint8_t *)p;
279a0698ed9Schristos 	size_t i, range0;
280a0698ed9Schristos 	uint8_t c0;
281a0698ed9Schristos 
282a0698ed9Schristos 	malloc_printf("  p=%p, c=%#x, len=%zu:", p, c, len);
283a0698ed9Schristos 	range0 = 0;
284a0698ed9Schristos 	c0 = pc[0];
285a0698ed9Schristos 	for (i = 0; i < len; i++) {
286a0698ed9Schristos 		if (pc[i] != c0) {
287a0698ed9Schristos 			malloc_printf(" %#x[%zu..%zu)", c0, range0, i);
288a0698ed9Schristos 			range0 = i;
289a0698ed9Schristos 			c0 = pc[i];
290a0698ed9Schristos 		}
291a0698ed9Schristos 	}
292a0698ed9Schristos 	malloc_printf(" %#x[%zu..%zu)\n", c0, range0, i);
293a0698ed9Schristos }
294a0698ed9Schristos 
295a0698ed9Schristos static bool
296a0698ed9Schristos validate_fill(const void *p, uint8_t c, size_t offset, size_t len) {
297a0698ed9Schristos 	const uint8_t *pc = (const uint8_t *)p;
298a0698ed9Schristos 	bool err;
299a0698ed9Schristos 	size_t i;
300a0698ed9Schristos 
301a0698ed9Schristos 	for (i = offset, err = false; i < offset+len; i++) {
302a0698ed9Schristos 		if (pc[i] != c) {
303a0698ed9Schristos 			err = true;
304a0698ed9Schristos 		}
305a0698ed9Schristos 	}
306a0698ed9Schristos 
307a0698ed9Schristos 	if (err) {
308a0698ed9Schristos 		print_filled_extents(p, c, offset + len);
309a0698ed9Schristos 	}
310a0698ed9Schristos 
311a0698ed9Schristos 	return err;
312a0698ed9Schristos }
313a0698ed9Schristos 
314a0698ed9Schristos static void
315a0698ed9Schristos test_zero(size_t szmin, size_t szmax) {
316a0698ed9Schristos 	int flags = MALLOCX_ARENA(arena_ind()) | MALLOCX_ZERO;
317a0698ed9Schristos 	size_t sz, nsz;
318a0698ed9Schristos 	void *p;
319a0698ed9Schristos #define FILL_BYTE 0x7aU
320a0698ed9Schristos 
321a0698ed9Schristos 	sz = szmax;
322a0698ed9Schristos 	p = mallocx(sz, flags);
323*7bdf38e5Schristos 	expect_ptr_not_null(p, "Unexpected mallocx() error");
324*7bdf38e5Schristos 	expect_false(validate_fill(p, 0x00, 0, sz), "Memory not filled: sz=%zu",
325a0698ed9Schristos 	    sz);
326a0698ed9Schristos 
327a0698ed9Schristos 	/*
328a0698ed9Schristos 	 * Fill with non-zero so that non-debug builds are more likely to detect
329a0698ed9Schristos 	 * errors.
330a0698ed9Schristos 	 */
331a0698ed9Schristos 	memset(p, FILL_BYTE, sz);
332*7bdf38e5Schristos 	expect_false(validate_fill(p, FILL_BYTE, 0, sz),
333a0698ed9Schristos 	    "Memory not filled: sz=%zu", sz);
334a0698ed9Schristos 
335a0698ed9Schristos 	/* Shrink in place so that we can expect growing in place to succeed. */
336a0698ed9Schristos 	sz = szmin;
337a0698ed9Schristos 	if (xallocx(p, sz, 0, flags) != sz) {
338a0698ed9Schristos 		p = rallocx(p, sz, flags);
339*7bdf38e5Schristos 		expect_ptr_not_null(p, "Unexpected rallocx() failure");
340a0698ed9Schristos 	}
341*7bdf38e5Schristos 	expect_false(validate_fill(p, FILL_BYTE, 0, sz),
342a0698ed9Schristos 	    "Memory not filled: sz=%zu", sz);
343a0698ed9Schristos 
344a0698ed9Schristos 	for (sz = szmin; sz < szmax; sz = nsz) {
345a0698ed9Schristos 		nsz = nallocx(sz+1, flags);
346a0698ed9Schristos 		if (xallocx(p, sz+1, 0, flags) != nsz) {
347a0698ed9Schristos 			p = rallocx(p, sz+1, flags);
348*7bdf38e5Schristos 			expect_ptr_not_null(p, "Unexpected rallocx() failure");
349a0698ed9Schristos 		}
350*7bdf38e5Schristos 		expect_false(validate_fill(p, FILL_BYTE, 0, sz),
351a0698ed9Schristos 		    "Memory not filled: sz=%zu", sz);
352*7bdf38e5Schristos 		expect_false(validate_fill(p, 0x00, sz, nsz-sz),
353a0698ed9Schristos 		    "Memory not filled: sz=%zu, nsz-sz=%zu", sz, nsz-sz);
354a0698ed9Schristos 		memset((void *)((uintptr_t)p + sz), FILL_BYTE, nsz-sz);
355*7bdf38e5Schristos 		expect_false(validate_fill(p, FILL_BYTE, 0, nsz),
356a0698ed9Schristos 		    "Memory not filled: nsz=%zu", nsz);
357a0698ed9Schristos 	}
358a0698ed9Schristos 
359a0698ed9Schristos 	dallocx(p, flags);
360a0698ed9Schristos }
361a0698ed9Schristos 
362a0698ed9Schristos TEST_BEGIN(test_zero_large) {
363a0698ed9Schristos 	size_t large0, large1;
364a0698ed9Schristos 
365a0698ed9Schristos 	/* Get size classes. */
366a0698ed9Schristos 	large0 = get_large_size(0);
367a0698ed9Schristos 	large1 = get_large_size(1);
368a0698ed9Schristos 
369a0698ed9Schristos 	test_zero(large1, large0 * 2);
370a0698ed9Schristos }
371a0698ed9Schristos TEST_END
372a0698ed9Schristos 
373a0698ed9Schristos int
374a0698ed9Schristos main(void) {
375a0698ed9Schristos 	return test(
376a0698ed9Schristos 	    test_same_size,
377a0698ed9Schristos 	    test_extra_no_move,
378a0698ed9Schristos 	    test_no_move_fail,
379a0698ed9Schristos 	    test_size,
380a0698ed9Schristos 	    test_size_extra_overflow,
381a0698ed9Schristos 	    test_extra_small,
382a0698ed9Schristos 	    test_extra_large,
383a0698ed9Schristos 	    test_zero_large);
384a0698ed9Schristos }
385