1 #include "test/jemalloc_test.h"
2 
TEST_BEGIN(test_same_size)3 TEST_BEGIN(test_same_size)
4 {
5 	void *p;
6 	size_t sz, tsz;
7 
8 	p = mallocx(42, 0);
9 	assert_ptr_not_null(p, "Unexpected mallocx() error");
10 	sz = sallocx(p, 0);
11 
12 	tsz = xallocx(p, sz, 0, 0);
13 	assert_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz);
14 
15 	dallocx(p, 0);
16 }
17 TEST_END
18 
TEST_BEGIN(test_extra_no_move)19 TEST_BEGIN(test_extra_no_move)
20 {
21 	void *p;
22 	size_t sz, tsz;
23 
24 	p = mallocx(42, 0);
25 	assert_ptr_not_null(p, "Unexpected mallocx() error");
26 	sz = sallocx(p, 0);
27 
28 	tsz = xallocx(p, sz, sz-42, 0);
29 	assert_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz);
30 
31 	dallocx(p, 0);
32 }
33 TEST_END
34 
TEST_BEGIN(test_no_move_fail)35 TEST_BEGIN(test_no_move_fail)
36 {
37 	void *p;
38 	size_t sz, tsz;
39 
40 	p = mallocx(42, 0);
41 	assert_ptr_not_null(p, "Unexpected mallocx() error");
42 	sz = sallocx(p, 0);
43 
44 	tsz = xallocx(p, sz + 5, 0, 0);
45 	assert_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz);
46 
47 	dallocx(p, 0);
48 }
49 TEST_END
50 
51 static unsigned
get_nsizes_impl(const char * cmd)52 get_nsizes_impl(const char *cmd)
53 {
54 	unsigned ret;
55 	size_t z;
56 
57 	z = sizeof(unsigned);
58 	assert_d_eq(mallctl(cmd, &ret, &z, NULL, 0), 0,
59 	    "Unexpected mallctl(\"%s\", ...) failure", cmd);
60 
61 	return (ret);
62 }
63 
64 static unsigned
get_nsmall(void)65 get_nsmall(void)
66 {
67 
68 	return (get_nsizes_impl("arenas.nbins"));
69 }
70 
71 static unsigned
get_nlarge(void)72 get_nlarge(void)
73 {
74 
75 	return (get_nsizes_impl("arenas.nlruns"));
76 }
77 
78 static unsigned
get_nhuge(void)79 get_nhuge(void)
80 {
81 
82 	return (get_nsizes_impl("arenas.nhchunks"));
83 }
84 
85 static size_t
get_size_impl(const char * cmd,size_t ind)86 get_size_impl(const char *cmd, size_t ind)
87 {
88 	size_t ret;
89 	size_t z;
90 	size_t mib[4];
91 	size_t miblen = 4;
92 
93 	z = sizeof(size_t);
94 	assert_d_eq(mallctlnametomib(cmd, mib, &miblen),
95 	    0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd);
96 	mib[2] = ind;
97 	z = sizeof(size_t);
98 	assert_d_eq(mallctlbymib(mib, miblen, &ret, &z, NULL, 0),
99 	    0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind);
100 
101 	return (ret);
102 }
103 
104 static size_t
get_small_size(size_t ind)105 get_small_size(size_t ind)
106 {
107 
108 	return (get_size_impl("arenas.bin.0.size", ind));
109 }
110 
111 static size_t
get_large_size(size_t ind)112 get_large_size(size_t ind)
113 {
114 
115 	return (get_size_impl("arenas.lrun.0.size", ind));
116 }
117 
118 static size_t
get_huge_size(size_t ind)119 get_huge_size(size_t ind)
120 {
121 
122 	return (get_size_impl("arenas.hchunk.0.size", ind));
123 }
124 
TEST_BEGIN(test_size)125 TEST_BEGIN(test_size)
126 {
127 	size_t small0, hugemax;
128 	void *p;
129 
130 	/* Get size classes. */
131 	small0 = get_small_size(0);
132 	hugemax = get_huge_size(get_nhuge()-1);
133 
134 	p = mallocx(small0, 0);
135 	assert_ptr_not_null(p, "Unexpected mallocx() error");
136 
137 	/* Test smallest supported size. */
138 	assert_zu_eq(xallocx(p, 1, 0, 0), small0,
139 	    "Unexpected xallocx() behavior");
140 
141 	/* Test largest supported size. */
142 	assert_zu_le(xallocx(p, hugemax, 0, 0), hugemax,
143 	    "Unexpected xallocx() behavior");
144 
145 	/* Test size overflow. */
146 	assert_zu_le(xallocx(p, hugemax+1, 0, 0), hugemax,
147 	    "Unexpected xallocx() behavior");
148 	assert_zu_le(xallocx(p, SIZE_T_MAX, 0, 0), hugemax,
149 	    "Unexpected xallocx() behavior");
150 
151 	dallocx(p, 0);
152 }
153 TEST_END
154 
TEST_BEGIN(test_size_extra_overflow)155 TEST_BEGIN(test_size_extra_overflow)
156 {
157 	size_t small0, hugemax;
158 	void *p;
159 
160 	/* Get size classes. */
161 	small0 = get_small_size(0);
162 	hugemax = get_huge_size(get_nhuge()-1);
163 
164 	p = mallocx(small0, 0);
165 	assert_ptr_not_null(p, "Unexpected mallocx() error");
166 
167 	/* Test overflows that can be resolved by clamping extra. */
168 	assert_zu_le(xallocx(p, hugemax-1, 2, 0), hugemax,
169 	    "Unexpected xallocx() behavior");
170 	assert_zu_le(xallocx(p, hugemax, 1, 0), hugemax,
171 	    "Unexpected xallocx() behavior");
172 
173 	/* Test overflow such that hugemax-size underflows. */
174 	assert_zu_le(xallocx(p, hugemax+1, 2, 0), hugemax,
175 	    "Unexpected xallocx() behavior");
176 	assert_zu_le(xallocx(p, hugemax+2, 3, 0), hugemax,
177 	    "Unexpected xallocx() behavior");
178 	assert_zu_le(xallocx(p, SIZE_T_MAX-2, 2, 0), hugemax,
179 	    "Unexpected xallocx() behavior");
180 	assert_zu_le(xallocx(p, SIZE_T_MAX-1, 1, 0), hugemax,
181 	    "Unexpected xallocx() behavior");
182 
183 	dallocx(p, 0);
184 }
185 TEST_END
186 
TEST_BEGIN(test_extra_small)187 TEST_BEGIN(test_extra_small)
188 {
189 	size_t small0, small1, hugemax;
190 	void *p;
191 
192 	/* Get size classes. */
193 	small0 = get_small_size(0);
194 	small1 = get_small_size(1);
195 	hugemax = get_huge_size(get_nhuge()-1);
196 
197 	p = mallocx(small0, 0);
198 	assert_ptr_not_null(p, "Unexpected mallocx() error");
199 
200 	assert_zu_eq(xallocx(p, small1, 0, 0), small0,
201 	    "Unexpected xallocx() behavior");
202 
203 	assert_zu_eq(xallocx(p, small1, 0, 0), small0,
204 	    "Unexpected xallocx() behavior");
205 
206 	assert_zu_eq(xallocx(p, small0, small1 - small0, 0), small0,
207 	    "Unexpected xallocx() behavior");
208 
209 	/* Test size+extra overflow. */
210 	assert_zu_eq(xallocx(p, small0, hugemax - small0 + 1, 0), small0,
211 	    "Unexpected xallocx() behavior");
212 	assert_zu_eq(xallocx(p, small0, SIZE_T_MAX - small0, 0), small0,
213 	    "Unexpected xallocx() behavior");
214 
215 	dallocx(p, 0);
216 }
217 TEST_END
218 
TEST_BEGIN(test_extra_large)219 TEST_BEGIN(test_extra_large)
220 {
221 	size_t smallmax, large0, large1, large2, huge0, hugemax;
222 	void *p;
223 
224 	/* Get size classes. */
225 	smallmax = get_small_size(get_nsmall()-1);
226 	large0 = get_large_size(0);
227 	large1 = get_large_size(1);
228 	large2 = get_large_size(2);
229 	huge0 = get_huge_size(0);
230 	hugemax = get_huge_size(get_nhuge()-1);
231 
232 	p = mallocx(large2, 0);
233 	assert_ptr_not_null(p, "Unexpected mallocx() error");
234 
235 	assert_zu_eq(xallocx(p, large2, 0, 0), large2,
236 	    "Unexpected xallocx() behavior");
237 	/* Test size decrease with zero extra. */
238 	assert_zu_eq(xallocx(p, large0, 0, 0), large0,
239 	    "Unexpected xallocx() behavior");
240 	assert_zu_eq(xallocx(p, smallmax, 0, 0), large0,
241 	    "Unexpected xallocx() behavior");
242 
243 	assert_zu_eq(xallocx(p, large2, 0, 0), large2,
244 	    "Unexpected xallocx() behavior");
245 	/* Test size decrease with non-zero extra. */
246 	assert_zu_eq(xallocx(p, large0, large2 - large0, 0), large2,
247 	    "Unexpected xallocx() behavior");
248 	assert_zu_eq(xallocx(p, large1, large2 - large1, 0), large2,
249 	    "Unexpected xallocx() behavior");
250 	assert_zu_eq(xallocx(p, large0, large1 - large0, 0), large1,
251 	    "Unexpected xallocx() behavior");
252 	assert_zu_eq(xallocx(p, smallmax, large0 - smallmax, 0), large0,
253 	    "Unexpected xallocx() behavior");
254 
255 	assert_zu_eq(xallocx(p, large0, 0, 0), large0,
256 	    "Unexpected xallocx() behavior");
257 	/* Test size increase with zero extra. */
258 	assert_zu_eq(xallocx(p, large2, 0, 0), large2,
259 	    "Unexpected xallocx() behavior");
260 	assert_zu_eq(xallocx(p, huge0, 0, 0), large2,
261 	    "Unexpected xallocx() behavior");
262 
263 	assert_zu_eq(xallocx(p, large0, 0, 0), large0,
264 	    "Unexpected xallocx() behavior");
265 	/* Test size increase with non-zero extra. */
266 	assert_zu_lt(xallocx(p, large0, huge0 - large0, 0), huge0,
267 	    "Unexpected xallocx() behavior");
268 
269 	assert_zu_eq(xallocx(p, large0, 0, 0), large0,
270 	    "Unexpected xallocx() behavior");
271 	/* Test size increase with non-zero extra. */
272 	assert_zu_eq(xallocx(p, large0, large2 - large0, 0), large2,
273 	    "Unexpected xallocx() behavior");
274 
275 	assert_zu_eq(xallocx(p, large2, 0, 0), large2,
276 	    "Unexpected xallocx() behavior");
277 	/* Test size+extra overflow. */
278 	assert_zu_lt(xallocx(p, large2, hugemax - large2 + 1, 0), huge0,
279 	    "Unexpected xallocx() behavior");
280 
281 	dallocx(p, 0);
282 }
283 TEST_END
284 
TEST_BEGIN(test_extra_huge)285 TEST_BEGIN(test_extra_huge)
286 {
287 	size_t largemax, huge0, huge1, huge2, hugemax;
288 	void *p;
289 
290 	/* Get size classes. */
291 	largemax = get_large_size(get_nlarge()-1);
292 	huge0 = get_huge_size(0);
293 	huge1 = get_huge_size(1);
294 	huge2 = get_huge_size(2);
295 	hugemax = get_huge_size(get_nhuge()-1);
296 
297 	p = mallocx(huge2, 0);
298 	assert_ptr_not_null(p, "Unexpected mallocx() error");
299 
300 	assert_zu_eq(xallocx(p, huge2, 0, 0), huge2,
301 	    "Unexpected xallocx() behavior");
302 	/* Test size decrease with zero extra. */
303 	assert_zu_ge(xallocx(p, huge0, 0, 0), huge0,
304 	    "Unexpected xallocx() behavior");
305 	assert_zu_ge(xallocx(p, largemax, 0, 0), huge0,
306 	    "Unexpected xallocx() behavior");
307 
308 	assert_zu_eq(xallocx(p, huge2, 0, 0), huge2,
309 	    "Unexpected xallocx() behavior");
310 	/* Test size decrease with non-zero extra. */
311 	assert_zu_eq(xallocx(p, huge0, huge2 - huge0, 0), huge2,
312 	    "Unexpected xallocx() behavior");
313 	assert_zu_eq(xallocx(p, huge1, huge2 - huge1, 0), huge2,
314 	    "Unexpected xallocx() behavior");
315 	assert_zu_eq(xallocx(p, huge0, huge1 - huge0, 0), huge1,
316 	    "Unexpected xallocx() behavior");
317 	assert_zu_ge(xallocx(p, largemax, huge0 - largemax, 0), huge0,
318 	    "Unexpected xallocx() behavior");
319 
320 	assert_zu_ge(xallocx(p, huge0, 0, 0), huge0,
321 	    "Unexpected xallocx() behavior");
322 	/* Test size increase with zero extra. */
323 	assert_zu_le(xallocx(p, huge2, 0, 0), huge2,
324 	    "Unexpected xallocx() behavior");
325 	assert_zu_le(xallocx(p, hugemax+1, 0, 0), huge2,
326 	    "Unexpected xallocx() behavior");
327 
328 	assert_zu_ge(xallocx(p, huge0, 0, 0), huge0,
329 	    "Unexpected xallocx() behavior");
330 	/* Test size increase with non-zero extra. */
331 	assert_zu_le(xallocx(p, huge0, SIZE_T_MAX - huge0, 0), hugemax,
332 	    "Unexpected xallocx() behavior");
333 
334 	assert_zu_ge(xallocx(p, huge0, 0, 0), huge0,
335 	    "Unexpected xallocx() behavior");
336 	/* Test size increase with non-zero extra. */
337 	assert_zu_le(xallocx(p, huge0, huge2 - huge0, 0), huge2,
338 	    "Unexpected xallocx() behavior");
339 
340 	assert_zu_eq(xallocx(p, huge2, 0, 0), huge2,
341 	    "Unexpected xallocx() behavior");
342 	/* Test size+extra overflow. */
343 	assert_zu_le(xallocx(p, huge2, hugemax - huge2 + 1, 0), hugemax,
344 	    "Unexpected xallocx() behavior");
345 
346 	dallocx(p, 0);
347 }
348 TEST_END
349 
350 static void
print_filled_extents(const void * p,uint8_t c,size_t len)351 print_filled_extents(const void *p, uint8_t c, size_t len)
352 {
353 	const uint8_t *pc = (const uint8_t *)p;
354 	size_t i, range0;
355 	uint8_t c0;
356 
357 	malloc_printf("  p=%p, c=%#x, len=%zu:", p, c, len);
358 	range0 = 0;
359 	c0 = pc[0];
360 	for (i = 0; i < len; i++) {
361 		if (pc[i] != c0) {
362 			malloc_printf(" %#x[%zu..%zu)", c0, range0, i);
363 			range0 = i;
364 			c0 = pc[i];
365 		}
366 	}
367 	malloc_printf(" %#x[%zu..%zu)\n", c0, range0, i);
368 }
369 
370 static bool
validate_fill(const void * p,uint8_t c,size_t offset,size_t len)371 validate_fill(const void *p, uint8_t c, size_t offset, size_t len)
372 {
373 	const uint8_t *pc = (const uint8_t *)p;
374 	bool err;
375 	size_t i;
376 
377 	for (i = offset, err = false; i < offset+len; i++) {
378 		if (pc[i] != c)
379 			err = true;
380 	}
381 
382 	if (err)
383 		print_filled_extents(p, c, offset + len);
384 
385 	return (err);
386 }
387 
388 static void
test_zero(size_t szmin,size_t szmax)389 test_zero(size_t szmin, size_t szmax)
390 {
391 	size_t sz, nsz;
392 	void *p;
393 #define	FILL_BYTE 0x7aU
394 
395 	sz = szmax;
396 	p = mallocx(sz, MALLOCX_ZERO);
397 	assert_ptr_not_null(p, "Unexpected mallocx() error");
398 	assert_false(validate_fill(p, 0x00, 0, sz), "Memory not filled: sz=%zu",
399 	    sz);
400 
401 	/*
402 	 * Fill with non-zero so that non-debug builds are more likely to detect
403 	 * errors.
404 	 */
405 	memset(p, FILL_BYTE, sz);
406 	assert_false(validate_fill(p, FILL_BYTE, 0, sz),
407 	    "Memory not filled: sz=%zu", sz);
408 
409 	/* Shrink in place so that we can expect growing in place to succeed. */
410 	sz = szmin;
411 	assert_zu_eq(xallocx(p, sz, 0, MALLOCX_ZERO), sz,
412 	    "Unexpected xallocx() error");
413 	assert_false(validate_fill(p, FILL_BYTE, 0, sz),
414 	    "Memory not filled: sz=%zu", sz);
415 
416 	for (sz = szmin; sz < szmax; sz = nsz) {
417 		nsz = nallocx(sz+1, MALLOCX_ZERO);
418 		assert_zu_eq(xallocx(p, sz+1, 0, MALLOCX_ZERO), nsz,
419 		    "Unexpected xallocx() failure");
420 		assert_false(validate_fill(p, FILL_BYTE, 0, sz),
421 		    "Memory not filled: sz=%zu", sz);
422 		assert_false(validate_fill(p, 0x00, sz, nsz-sz),
423 		    "Memory not filled: sz=%zu, nsz-sz=%zu", sz, nsz-sz);
424 		memset((void *)((uintptr_t)p + sz), FILL_BYTE, nsz-sz);
425 		assert_false(validate_fill(p, FILL_BYTE, 0, nsz),
426 		    "Memory not filled: nsz=%zu", nsz);
427 	}
428 
429 	dallocx(p, 0);
430 }
431 
TEST_BEGIN(test_zero_large)432 TEST_BEGIN(test_zero_large)
433 {
434 	size_t large0, largemax;
435 
436 	/* Get size classes. */
437 	large0 = get_large_size(0);
438 	largemax = get_large_size(get_nlarge()-1);
439 
440 	test_zero(large0, largemax);
441 }
442 TEST_END
443 
TEST_BEGIN(test_zero_huge)444 TEST_BEGIN(test_zero_huge)
445 {
446 	size_t huge0, huge1;
447 
448 	/* Get size classes. */
449 	huge0 = get_huge_size(0);
450 	huge1 = get_huge_size(1);
451 
452 	test_zero(huge1, huge0 * 2);
453 }
454 TEST_END
455 
456 int
main(void)457 main(void)
458 {
459 
460 	return (test(
461 	    test_same_size,
462 	    test_extra_no_move,
463 	    test_no_move_fail,
464 	    test_size,
465 	    test_size_extra_overflow,
466 	    test_extra_small,
467 	    test_extra_large,
468 	    test_extra_huge,
469 	    test_zero_large,
470 	    test_zero_huge));
471 }
472