xref: /netbsd-src/external/bsd/jemalloc/dist/test/integration/rallocx.c (revision 7bdf38e5b7a28439665f2fdeff81e36913eef7dd)
1a0698ed9Schristos #include "test/jemalloc_test.h"
2a0698ed9Schristos 
3a0698ed9Schristos static unsigned
4a0698ed9Schristos get_nsizes_impl(const char *cmd) {
5a0698ed9Schristos 	unsigned ret;
6a0698ed9Schristos 	size_t z;
7a0698ed9Schristos 
8a0698ed9Schristos 	z = sizeof(unsigned);
9*7bdf38e5Schristos 	expect_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0,
10a0698ed9Schristos 	    "Unexpected mallctl(\"%s\", ...) failure", cmd);
11a0698ed9Schristos 
12a0698ed9Schristos 	return ret;
13a0698ed9Schristos }
14a0698ed9Schristos 
15a0698ed9Schristos static unsigned
16a0698ed9Schristos get_nlarge(void) {
17a0698ed9Schristos 	return get_nsizes_impl("arenas.nlextents");
18a0698ed9Schristos }
19a0698ed9Schristos 
20a0698ed9Schristos static size_t
21a0698ed9Schristos get_size_impl(const char *cmd, size_t ind) {
22a0698ed9Schristos 	size_t ret;
23a0698ed9Schristos 	size_t z;
24a0698ed9Schristos 	size_t mib[4];
25a0698ed9Schristos 	size_t miblen = 4;
26a0698ed9Schristos 
27a0698ed9Schristos 	z = sizeof(size_t);
28*7bdf38e5Schristos 	expect_d_eq(mallctlnametomib(cmd, mib, &miblen),
29a0698ed9Schristos 	    0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd);
30a0698ed9Schristos 	mib[2] = ind;
31a0698ed9Schristos 	z = sizeof(size_t);
32*7bdf38e5Schristos 	expect_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0),
33a0698ed9Schristos 	    0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind);
34a0698ed9Schristos 
35a0698ed9Schristos 	return ret;
36a0698ed9Schristos }
37a0698ed9Schristos 
38a0698ed9Schristos static size_t
39a0698ed9Schristos get_large_size(size_t ind) {
40a0698ed9Schristos 	return get_size_impl("arenas.lextent.0.size", ind);
41a0698ed9Schristos }
42a0698ed9Schristos 
43a0698ed9Schristos TEST_BEGIN(test_grow_and_shrink) {
44*7bdf38e5Schristos 	/*
45*7bdf38e5Schristos 	 * Use volatile to workaround buffer overflow false positives
46*7bdf38e5Schristos 	 * (-D_FORTIFY_SOURCE=3).
47*7bdf38e5Schristos 	 */
48*7bdf38e5Schristos 	void *volatile p, *volatile q;
49a0698ed9Schristos 	size_t tsz;
50a0698ed9Schristos #define NCYCLES 3
51a0698ed9Schristos 	unsigned i, j;
52a0698ed9Schristos #define NSZS 1024
53a0698ed9Schristos 	size_t szs[NSZS];
54a0698ed9Schristos #define MAXSZ ZU(12 * 1024 * 1024)
55a0698ed9Schristos 
56a0698ed9Schristos 	p = mallocx(1, 0);
57*7bdf38e5Schristos 	expect_ptr_not_null(p, "Unexpected mallocx() error");
58a0698ed9Schristos 	szs[0] = sallocx(p, 0);
59a0698ed9Schristos 
60a0698ed9Schristos 	for (i = 0; i < NCYCLES; i++) {
61a0698ed9Schristos 		for (j = 1; j < NSZS && szs[j-1] < MAXSZ; j++) {
62a0698ed9Schristos 			q = rallocx(p, szs[j-1]+1, 0);
63*7bdf38e5Schristos 			expect_ptr_not_null(q,
64a0698ed9Schristos 			    "Unexpected rallocx() error for size=%zu-->%zu",
65a0698ed9Schristos 			    szs[j-1], szs[j-1]+1);
66a0698ed9Schristos 			szs[j] = sallocx(q, 0);
67*7bdf38e5Schristos 			expect_zu_ne(szs[j], szs[j-1]+1,
68a0698ed9Schristos 			    "Expected size to be at least: %zu", szs[j-1]+1);
69a0698ed9Schristos 			p = q;
70a0698ed9Schristos 		}
71a0698ed9Schristos 
72a0698ed9Schristos 		for (j--; j > 0; j--) {
73a0698ed9Schristos 			q = rallocx(p, szs[j-1], 0);
74*7bdf38e5Schristos 			expect_ptr_not_null(q,
75a0698ed9Schristos 			    "Unexpected rallocx() error for size=%zu-->%zu",
76a0698ed9Schristos 			    szs[j], szs[j-1]);
77a0698ed9Schristos 			tsz = sallocx(q, 0);
78*7bdf38e5Schristos 			expect_zu_eq(tsz, szs[j-1],
79a0698ed9Schristos 			    "Expected size=%zu, got size=%zu", szs[j-1], tsz);
80a0698ed9Schristos 			p = q;
81a0698ed9Schristos 		}
82a0698ed9Schristos 	}
83a0698ed9Schristos 
84a0698ed9Schristos 	dallocx(p, 0);
85a0698ed9Schristos #undef MAXSZ
86a0698ed9Schristos #undef NSZS
87a0698ed9Schristos #undef NCYCLES
88a0698ed9Schristos }
89a0698ed9Schristos TEST_END
90a0698ed9Schristos 
91a0698ed9Schristos static bool
92*7bdf38e5Schristos validate_fill(void *p, uint8_t c, size_t offset, size_t len) {
93a0698ed9Schristos 	bool ret = false;
94*7bdf38e5Schristos 	/*
95*7bdf38e5Schristos 	 * Use volatile to workaround buffer overflow false positives
96*7bdf38e5Schristos 	 * (-D_FORTIFY_SOURCE=3).
97*7bdf38e5Schristos 	 */
98*7bdf38e5Schristos 	uint8_t *volatile buf = (uint8_t *)p;
99a0698ed9Schristos 	size_t i;
100a0698ed9Schristos 
101a0698ed9Schristos 	for (i = 0; i < len; i++) {
102a0698ed9Schristos 		uint8_t b = buf[offset+i];
103a0698ed9Schristos 		if (b != c) {
104a0698ed9Schristos 			test_fail("Allocation at %p (len=%zu) contains %#x "
105a0698ed9Schristos 			    "rather than %#x at offset %zu", p, len, b, c,
106a0698ed9Schristos 			    offset+i);
107a0698ed9Schristos 			ret = true;
108a0698ed9Schristos 		}
109a0698ed9Schristos 	}
110a0698ed9Schristos 
111a0698ed9Schristos 	return ret;
112a0698ed9Schristos }
113a0698ed9Schristos 
114a0698ed9Schristos TEST_BEGIN(test_zero) {
115*7bdf38e5Schristos 	/*
116*7bdf38e5Schristos 	 * Use volatile to workaround buffer overflow false positives
117*7bdf38e5Schristos 	 * (-D_FORTIFY_SOURCE=3).
118*7bdf38e5Schristos 	 */
119*7bdf38e5Schristos 	void *volatile p, *volatile q;
120a0698ed9Schristos 	size_t psz, qsz, i, j;
121a0698ed9Schristos 	size_t start_sizes[] = {1, 3*1024, 63*1024, 4095*1024};
122a0698ed9Schristos #define FILL_BYTE 0xaaU
123a0698ed9Schristos #define RANGE 2048
124a0698ed9Schristos 
125a0698ed9Schristos 	for (i = 0; i < sizeof(start_sizes)/sizeof(size_t); i++) {
126a0698ed9Schristos 		size_t start_size = start_sizes[i];
127a0698ed9Schristos 		p = mallocx(start_size, MALLOCX_ZERO);
128*7bdf38e5Schristos 		expect_ptr_not_null(p, "Unexpected mallocx() error");
129a0698ed9Schristos 		psz = sallocx(p, 0);
130a0698ed9Schristos 
131*7bdf38e5Schristos 		expect_false(validate_fill(p, 0, 0, psz),
132a0698ed9Schristos 		    "Expected zeroed memory");
133a0698ed9Schristos 		memset(p, FILL_BYTE, psz);
134*7bdf38e5Schristos 		expect_false(validate_fill(p, FILL_BYTE, 0, psz),
135a0698ed9Schristos 		    "Expected filled memory");
136a0698ed9Schristos 
137a0698ed9Schristos 		for (j = 1; j < RANGE; j++) {
138a0698ed9Schristos 			q = rallocx(p, start_size+j, MALLOCX_ZERO);
139*7bdf38e5Schristos 			expect_ptr_not_null(q, "Unexpected rallocx() error");
140a0698ed9Schristos 			qsz = sallocx(q, 0);
141a0698ed9Schristos 			if (q != p || qsz != psz) {
142*7bdf38e5Schristos 				expect_false(validate_fill(q, FILL_BYTE, 0,
143a0698ed9Schristos 				    psz), "Expected filled memory");
144*7bdf38e5Schristos 				expect_false(validate_fill(q, 0, psz, qsz-psz),
145a0698ed9Schristos 				    "Expected zeroed memory");
146a0698ed9Schristos 			}
147a0698ed9Schristos 			if (psz != qsz) {
148a0698ed9Schristos 				memset((void *)((uintptr_t)q+psz), FILL_BYTE,
149a0698ed9Schristos 				    qsz-psz);
150a0698ed9Schristos 				psz = qsz;
151a0698ed9Schristos 			}
152a0698ed9Schristos 			p = q;
153a0698ed9Schristos 		}
154*7bdf38e5Schristos 		expect_false(validate_fill(p, FILL_BYTE, 0, psz),
155a0698ed9Schristos 		    "Expected filled memory");
156a0698ed9Schristos 		dallocx(p, 0);
157a0698ed9Schristos 	}
158a0698ed9Schristos #undef FILL_BYTE
159a0698ed9Schristos }
160a0698ed9Schristos TEST_END
161a0698ed9Schristos 
162a0698ed9Schristos TEST_BEGIN(test_align) {
163a0698ed9Schristos 	void *p, *q;
164a0698ed9Schristos 	size_t align;
165a0698ed9Schristos #define MAX_ALIGN (ZU(1) << 25)
166a0698ed9Schristos 
167a0698ed9Schristos 	align = ZU(1);
168a0698ed9Schristos 	p = mallocx(1, MALLOCX_ALIGN(align));
169*7bdf38e5Schristos 	expect_ptr_not_null(p, "Unexpected mallocx() error");
170a0698ed9Schristos 
171a0698ed9Schristos 	for (align <<= 1; align <= MAX_ALIGN; align <<= 1) {
172a0698ed9Schristos 		q = rallocx(p, 1, MALLOCX_ALIGN(align));
173*7bdf38e5Schristos 		expect_ptr_not_null(q,
174a0698ed9Schristos 		    "Unexpected rallocx() error for align=%zu", align);
175*7bdf38e5Schristos 		expect_ptr_null(
176a0698ed9Schristos 		    (void *)((uintptr_t)q & (align-1)),
177a0698ed9Schristos 		    "%p inadequately aligned for align=%zu",
178a0698ed9Schristos 		    q, align);
179a0698ed9Schristos 		p = q;
180a0698ed9Schristos 	}
181a0698ed9Schristos 	dallocx(p, 0);
182a0698ed9Schristos #undef MAX_ALIGN
183a0698ed9Schristos }
184a0698ed9Schristos TEST_END
185a0698ed9Schristos 
186*7bdf38e5Schristos TEST_BEGIN(test_align_enum) {
187*7bdf38e5Schristos /* Span both small sizes and large sizes. */
188*7bdf38e5Schristos #define LG_MIN 12
189*7bdf38e5Schristos #define LG_MAX 15
190*7bdf38e5Schristos 	for (size_t lg_align = LG_MIN; lg_align <= LG_MAX; ++lg_align) {
191*7bdf38e5Schristos 		for (size_t lg_size = LG_MIN; lg_size <= LG_MAX; ++lg_size) {
192*7bdf38e5Schristos 			size_t size = 1 << lg_size;
193*7bdf38e5Schristos 			for (size_t lg_align_next = LG_MIN;
194*7bdf38e5Schristos 			    lg_align_next <= LG_MAX; ++lg_align_next) {
195*7bdf38e5Schristos 				int flags = MALLOCX_LG_ALIGN(lg_align);
196*7bdf38e5Schristos 				void *p = mallocx(1, flags);
197*7bdf38e5Schristos 				assert_ptr_not_null(p,
198*7bdf38e5Schristos 				    "Unexpected mallocx() error");
199*7bdf38e5Schristos 				assert_zu_eq(nallocx(1, flags),
200*7bdf38e5Schristos 				    TEST_MALLOC_SIZE(p),
201*7bdf38e5Schristos 				    "Wrong mallocx() usable size");
202*7bdf38e5Schristos 				int flags_next =
203*7bdf38e5Schristos 				    MALLOCX_LG_ALIGN(lg_align_next);
204*7bdf38e5Schristos 				p = rallocx(p, size, flags_next);
205*7bdf38e5Schristos 				assert_ptr_not_null(p,
206*7bdf38e5Schristos 				    "Unexpected rallocx() error");
207*7bdf38e5Schristos 				expect_zu_eq(nallocx(size, flags_next),
208*7bdf38e5Schristos 				    TEST_MALLOC_SIZE(p),
209*7bdf38e5Schristos 				    "Wrong rallocx() usable size");
210*7bdf38e5Schristos 				free(p);
211*7bdf38e5Schristos 			}
212*7bdf38e5Schristos 		}
213*7bdf38e5Schristos 	}
214*7bdf38e5Schristos #undef LG_MAX
215*7bdf38e5Schristos #undef LG_MIN
216*7bdf38e5Schristos }
217*7bdf38e5Schristos TEST_END
218*7bdf38e5Schristos 
219a0698ed9Schristos TEST_BEGIN(test_lg_align_and_zero) {
220*7bdf38e5Schristos 	/*
221*7bdf38e5Schristos 	 * Use volatile to workaround buffer overflow false positives
222*7bdf38e5Schristos 	 * (-D_FORTIFY_SOURCE=3).
223*7bdf38e5Schristos 	 */
224*7bdf38e5Schristos 	void *volatile p, *volatile q;
225a0698ed9Schristos 	unsigned lg_align;
226a0698ed9Schristos 	size_t sz;
227a0698ed9Schristos #define MAX_LG_ALIGN 25
228a0698ed9Schristos #define MAX_VALIDATE (ZU(1) << 22)
229a0698ed9Schristos 
230a0698ed9Schristos 	lg_align = 0;
231a0698ed9Schristos 	p = mallocx(1, MALLOCX_LG_ALIGN(lg_align)|MALLOCX_ZERO);
232*7bdf38e5Schristos 	expect_ptr_not_null(p, "Unexpected mallocx() error");
233a0698ed9Schristos 
234a0698ed9Schristos 	for (lg_align++; lg_align <= MAX_LG_ALIGN; lg_align++) {
235a0698ed9Schristos 		q = rallocx(p, 1, MALLOCX_LG_ALIGN(lg_align)|MALLOCX_ZERO);
236*7bdf38e5Schristos 		expect_ptr_not_null(q,
237a0698ed9Schristos 		    "Unexpected rallocx() error for lg_align=%u", lg_align);
238*7bdf38e5Schristos 		expect_ptr_null(
239a0698ed9Schristos 		    (void *)((uintptr_t)q & ((ZU(1) << lg_align)-1)),
240a0698ed9Schristos 		    "%p inadequately aligned for lg_align=%u", q, lg_align);
241a0698ed9Schristos 		sz = sallocx(q, 0);
242a0698ed9Schristos 		if ((sz << 1) <= MAX_VALIDATE) {
243*7bdf38e5Schristos 			expect_false(validate_fill(q, 0, 0, sz),
244a0698ed9Schristos 			    "Expected zeroed memory");
245a0698ed9Schristos 		} else {
246*7bdf38e5Schristos 			expect_false(validate_fill(q, 0, 0, MAX_VALIDATE),
247a0698ed9Schristos 			    "Expected zeroed memory");
248*7bdf38e5Schristos 			expect_false(validate_fill(
249a0698ed9Schristos 			    (void *)((uintptr_t)q+sz-MAX_VALIDATE),
250a0698ed9Schristos 			    0, 0, MAX_VALIDATE), "Expected zeroed memory");
251a0698ed9Schristos 		}
252a0698ed9Schristos 		p = q;
253a0698ed9Schristos 	}
254a0698ed9Schristos 	dallocx(p, 0);
255a0698ed9Schristos #undef MAX_VALIDATE
256a0698ed9Schristos #undef MAX_LG_ALIGN
257a0698ed9Schristos }
258a0698ed9Schristos TEST_END
259a0698ed9Schristos 
260*7bdf38e5Schristos /*
261*7bdf38e5Schristos  * GCC "-Walloc-size-larger-than" warning detects when one of the memory
262*7bdf38e5Schristos  * allocation functions is called with a size larger than the maximum size that
263*7bdf38e5Schristos  * they support. Here we want to explicitly test that the allocation functions
264*7bdf38e5Schristos  * do indeed fail properly when this is the case, which triggers the warning.
265*7bdf38e5Schristos  * Therefore we disable the warning for these tests.
266*7bdf38e5Schristos  */
267*7bdf38e5Schristos JEMALLOC_DIAGNOSTIC_PUSH
268*7bdf38e5Schristos JEMALLOC_DIAGNOSTIC_IGNORE_ALLOC_SIZE_LARGER_THAN
269*7bdf38e5Schristos 
270a0698ed9Schristos TEST_BEGIN(test_overflow) {
271a0698ed9Schristos 	size_t largemax;
272a0698ed9Schristos 	void *p;
273a0698ed9Schristos 
274a0698ed9Schristos 	largemax = get_large_size(get_nlarge()-1);
275a0698ed9Schristos 
276a0698ed9Schristos 	p = mallocx(1, 0);
277*7bdf38e5Schristos 	expect_ptr_not_null(p, "Unexpected mallocx() failure");
278a0698ed9Schristos 
279*7bdf38e5Schristos 	expect_ptr_null(rallocx(p, largemax+1, 0),
280a0698ed9Schristos 	    "Expected OOM for rallocx(p, size=%#zx, 0)", largemax+1);
281a0698ed9Schristos 
282*7bdf38e5Schristos 	expect_ptr_null(rallocx(p, ZU(PTRDIFF_MAX)+1, 0),
283a0698ed9Schristos 	    "Expected OOM for rallocx(p, size=%#zx, 0)", ZU(PTRDIFF_MAX)+1);
284a0698ed9Schristos 
285*7bdf38e5Schristos 	expect_ptr_null(rallocx(p, SIZE_T_MAX, 0),
286a0698ed9Schristos 	    "Expected OOM for rallocx(p, size=%#zx, 0)", SIZE_T_MAX);
287a0698ed9Schristos 
288*7bdf38e5Schristos 	expect_ptr_null(rallocx(p, 1, MALLOCX_ALIGN(ZU(PTRDIFF_MAX)+1)),
289a0698ed9Schristos 	    "Expected OOM for rallocx(p, size=1, MALLOCX_ALIGN(%#zx))",
290a0698ed9Schristos 	    ZU(PTRDIFF_MAX)+1);
291a0698ed9Schristos 
292a0698ed9Schristos 	dallocx(p, 0);
293a0698ed9Schristos }
294a0698ed9Schristos TEST_END
295a0698ed9Schristos 
296*7bdf38e5Schristos /* Re-enable the "-Walloc-size-larger-than=" warning */
297*7bdf38e5Schristos JEMALLOC_DIAGNOSTIC_POP
298*7bdf38e5Schristos 
299a0698ed9Schristos int
300a0698ed9Schristos main(void) {
301a0698ed9Schristos 	return test(
302a0698ed9Schristos 	    test_grow_and_shrink,
303a0698ed9Schristos 	    test_zero,
304a0698ed9Schristos 	    test_align,
305*7bdf38e5Schristos 	    test_align_enum,
306a0698ed9Schristos 	    test_lg_align_and_zero,
307a0698ed9Schristos 	    test_overflow);
308a0698ed9Schristos }
309