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