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