1 #include "test/jemalloc_test.h"
2 
3 #include "jemalloc/internal/util.h"
4 
TEST_BEGIN(test_mallctl_errors)5 TEST_BEGIN(test_mallctl_errors) {
6 	uint64_t epoch;
7 	size_t sz;
8 
9 	assert_d_eq(mallctl("no_such_name", NULL, NULL, NULL, 0), ENOENT,
10 	    "mallctl() should return ENOENT for non-existent names");
11 
12 	assert_d_eq(mallctl("version", NULL, NULL, "0.0.0", strlen("0.0.0")),
13 	    EPERM, "mallctl() should return EPERM on attempt to write "
14 	    "read-only value");
15 
16 	assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
17 	    sizeof(epoch)-1), EINVAL,
18 	    "mallctl() should return EINVAL for input size mismatch");
19 	assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
20 	    sizeof(epoch)+1), EINVAL,
21 	    "mallctl() should return EINVAL for input size mismatch");
22 
23 	sz = sizeof(epoch)-1;
24 	assert_d_eq(mallctl("epoch", (void *)&epoch, &sz, NULL, 0), EINVAL,
25 	    "mallctl() should return EINVAL for output size mismatch");
26 	sz = sizeof(epoch)+1;
27 	assert_d_eq(mallctl("epoch", (void *)&epoch, &sz, NULL, 0), EINVAL,
28 	    "mallctl() should return EINVAL for output size mismatch");
29 }
30 TEST_END
31 
TEST_BEGIN(test_mallctlnametomib_errors)32 TEST_BEGIN(test_mallctlnametomib_errors) {
33 	size_t mib[1];
34 	size_t miblen;
35 
36 	miblen = sizeof(mib)/sizeof(size_t);
37 	assert_d_eq(mallctlnametomib("no_such_name", mib, &miblen), ENOENT,
38 	    "mallctlnametomib() should return ENOENT for non-existent names");
39 }
40 TEST_END
41 
TEST_BEGIN(test_mallctlbymib_errors)42 TEST_BEGIN(test_mallctlbymib_errors) {
43 	uint64_t epoch;
44 	size_t sz;
45 	size_t mib[1];
46 	size_t miblen;
47 
48 	miblen = sizeof(mib)/sizeof(size_t);
49 	assert_d_eq(mallctlnametomib("version", mib, &miblen), 0,
50 	    "Unexpected mallctlnametomib() failure");
51 
52 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, "0.0.0",
53 	    strlen("0.0.0")), EPERM, "mallctl() should return EPERM on "
54 	    "attempt to write read-only value");
55 
56 	miblen = sizeof(mib)/sizeof(size_t);
57 	assert_d_eq(mallctlnametomib("epoch", mib, &miblen), 0,
58 	    "Unexpected mallctlnametomib() failure");
59 
60 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&epoch,
61 	    sizeof(epoch)-1), EINVAL,
62 	    "mallctlbymib() should return EINVAL for input size mismatch");
63 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&epoch,
64 	    sizeof(epoch)+1), EINVAL,
65 	    "mallctlbymib() should return EINVAL for input size mismatch");
66 
67 	sz = sizeof(epoch)-1;
68 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&epoch, &sz, NULL, 0),
69 	    EINVAL,
70 	    "mallctlbymib() should return EINVAL for output size mismatch");
71 	sz = sizeof(epoch)+1;
72 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&epoch, &sz, NULL, 0),
73 	    EINVAL,
74 	    "mallctlbymib() should return EINVAL for output size mismatch");
75 }
76 TEST_END
77 
TEST_BEGIN(test_mallctl_read_write)78 TEST_BEGIN(test_mallctl_read_write) {
79 	uint64_t old_epoch, new_epoch;
80 	size_t sz = sizeof(old_epoch);
81 
82 	/* Blind. */
83 	assert_d_eq(mallctl("epoch", NULL, NULL, NULL, 0), 0,
84 	    "Unexpected mallctl() failure");
85 	assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
86 
87 	/* Read. */
88 	assert_d_eq(mallctl("epoch", (void *)&old_epoch, &sz, NULL, 0), 0,
89 	    "Unexpected mallctl() failure");
90 	assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
91 
92 	/* Write. */
93 	assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&new_epoch,
94 	    sizeof(new_epoch)), 0, "Unexpected mallctl() failure");
95 	assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
96 
97 	/* Read+write. */
98 	assert_d_eq(mallctl("epoch", (void *)&old_epoch, &sz,
99 	    (void *)&new_epoch, sizeof(new_epoch)), 0,
100 	    "Unexpected mallctl() failure");
101 	assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
102 }
103 TEST_END
104 
TEST_BEGIN(test_mallctlnametomib_short_mib)105 TEST_BEGIN(test_mallctlnametomib_short_mib) {
106 	size_t mib[4];
107 	size_t miblen;
108 
109 	miblen = 3;
110 	mib[3] = 42;
111 	assert_d_eq(mallctlnametomib("arenas.bin.0.nregs", mib, &miblen), 0,
112 	    "Unexpected mallctlnametomib() failure");
113 	assert_zu_eq(miblen, 3, "Unexpected mib output length");
114 	assert_zu_eq(mib[3], 42,
115 	    "mallctlnametomib() wrote past the end of the input mib");
116 }
117 TEST_END
118 
TEST_BEGIN(test_mallctl_config)119 TEST_BEGIN(test_mallctl_config) {
120 #define TEST_MALLCTL_CONFIG(config, t) do {				\
121 	t oldval;							\
122 	size_t sz = sizeof(oldval);					\
123 	assert_d_eq(mallctl("config."#config, (void *)&oldval, &sz,	\
124 	    NULL, 0), 0, "Unexpected mallctl() failure");		\
125 	assert_b_eq(oldval, config_##config, "Incorrect config value");	\
126 	assert_zu_eq(sz, sizeof(oldval), "Unexpected output size");	\
127 } while (0)
128 
129 	TEST_MALLCTL_CONFIG(cache_oblivious, bool);
130 	TEST_MALLCTL_CONFIG(debug, bool);
131 	TEST_MALLCTL_CONFIG(fill, bool);
132 	TEST_MALLCTL_CONFIG(lazy_lock, bool);
133 	TEST_MALLCTL_CONFIG(malloc_conf, const char *);
134 	TEST_MALLCTL_CONFIG(prof, bool);
135 	TEST_MALLCTL_CONFIG(prof_libgcc, bool);
136 	TEST_MALLCTL_CONFIG(prof_libunwind, bool);
137 	TEST_MALLCTL_CONFIG(stats, bool);
138 	TEST_MALLCTL_CONFIG(utrace, bool);
139 	TEST_MALLCTL_CONFIG(xmalloc, bool);
140 
141 #undef TEST_MALLCTL_CONFIG
142 }
143 TEST_END
144 
TEST_BEGIN(test_mallctl_opt)145 TEST_BEGIN(test_mallctl_opt) {
146 	bool config_always = true;
147 
148 #define TEST_MALLCTL_OPT(t, opt, config) do {				\
149 	t oldval;							\
150 	size_t sz = sizeof(oldval);					\
151 	int expected = config_##config ? 0 : ENOENT;			\
152 	int result = mallctl("opt."#opt, (void *)&oldval, &sz, NULL,	\
153 	    0);								\
154 	assert_d_eq(result, expected,					\
155 	    "Unexpected mallctl() result for opt."#opt);		\
156 	assert_zu_eq(sz, sizeof(oldval), "Unexpected output size");	\
157 } while (0)
158 
159 	TEST_MALLCTL_OPT(bool, abort, always);
160 	TEST_MALLCTL_OPT(bool, abort_conf, always);
161 	TEST_MALLCTL_OPT(const char *, metadata_thp, always);
162 	TEST_MALLCTL_OPT(bool, retain, always);
163 	TEST_MALLCTL_OPT(const char *, dss, always);
164 	TEST_MALLCTL_OPT(unsigned, narenas, always);
165 	TEST_MALLCTL_OPT(const char *, percpu_arena, always);
166 	TEST_MALLCTL_OPT(bool, background_thread, always);
167 	TEST_MALLCTL_OPT(ssize_t, dirty_decay_ms, always);
168 	TEST_MALLCTL_OPT(ssize_t, muzzy_decay_ms, always);
169 	TEST_MALLCTL_OPT(bool, stats_print, always);
170 	TEST_MALLCTL_OPT(const char *, junk, fill);
171 	TEST_MALLCTL_OPT(bool, zero, fill);
172 	TEST_MALLCTL_OPT(bool, utrace, utrace);
173 	TEST_MALLCTL_OPT(bool, xmalloc, xmalloc);
174 	TEST_MALLCTL_OPT(bool, tcache, always);
175 	TEST_MALLCTL_OPT(size_t, lg_extent_max_active_fit, always);
176 	TEST_MALLCTL_OPT(size_t, lg_tcache_max, always);
177 	TEST_MALLCTL_OPT(const char *, thp, always);
178 	TEST_MALLCTL_OPT(bool, prof, prof);
179 	TEST_MALLCTL_OPT(const char *, prof_prefix, prof);
180 	TEST_MALLCTL_OPT(bool, prof_active, prof);
181 	TEST_MALLCTL_OPT(ssize_t, lg_prof_sample, prof);
182 	TEST_MALLCTL_OPT(bool, prof_accum, prof);
183 	TEST_MALLCTL_OPT(ssize_t, lg_prof_interval, prof);
184 	TEST_MALLCTL_OPT(bool, prof_gdump, prof);
185 	TEST_MALLCTL_OPT(bool, prof_final, prof);
186 	TEST_MALLCTL_OPT(bool, prof_leak, prof);
187 
188 #undef TEST_MALLCTL_OPT
189 }
190 TEST_END
191 
TEST_BEGIN(test_manpage_example)192 TEST_BEGIN(test_manpage_example) {
193 	unsigned nbins, i;
194 	size_t mib[4];
195 	size_t len, miblen;
196 
197 	len = sizeof(nbins);
198 	assert_d_eq(mallctl("arenas.nbins", (void *)&nbins, &len, NULL, 0), 0,
199 	    "Unexpected mallctl() failure");
200 
201 	miblen = 4;
202 	assert_d_eq(mallctlnametomib("arenas.bin.0.size", mib, &miblen), 0,
203 	    "Unexpected mallctlnametomib() failure");
204 	for (i = 0; i < nbins; i++) {
205 		size_t bin_size;
206 
207 		mib[2] = i;
208 		len = sizeof(bin_size);
209 		assert_d_eq(mallctlbymib(mib, miblen, (void *)&bin_size, &len,
210 		    NULL, 0), 0, "Unexpected mallctlbymib() failure");
211 		/* Do something with bin_size... */
212 	}
213 }
214 TEST_END
215 
TEST_BEGIN(test_tcache_none)216 TEST_BEGIN(test_tcache_none) {
217 	test_skip_if(!opt_tcache);
218 
219 	/* Allocate p and q. */
220 	void *p0 = mallocx(42, 0);
221 	assert_ptr_not_null(p0, "Unexpected mallocx() failure");
222 	void *q = mallocx(42, 0);
223 	assert_ptr_not_null(q, "Unexpected mallocx() failure");
224 
225 	/* Deallocate p and q, but bypass the tcache for q. */
226 	dallocx(p0, 0);
227 	dallocx(q, MALLOCX_TCACHE_NONE);
228 
229 	/* Make sure that tcache-based allocation returns p, not q. */
230 	void *p1 = mallocx(42, 0);
231 	assert_ptr_not_null(p1, "Unexpected mallocx() failure");
232 	assert_ptr_eq(p0, p1, "Expected tcache to allocate cached region");
233 
234 	/* Clean up. */
235 	dallocx(p1, MALLOCX_TCACHE_NONE);
236 }
237 TEST_END
238 
TEST_BEGIN(test_tcache)239 TEST_BEGIN(test_tcache) {
240 #define NTCACHES	10
241 	unsigned tis[NTCACHES];
242 	void *ps[NTCACHES];
243 	void *qs[NTCACHES];
244 	unsigned i;
245 	size_t sz, psz, qsz;
246 
247 	psz = 42;
248 	qsz = nallocx(psz, 0) + 1;
249 
250 	/* Create tcaches. */
251 	for (i = 0; i < NTCACHES; i++) {
252 		sz = sizeof(unsigned);
253 		assert_d_eq(mallctl("tcache.create", (void *)&tis[i], &sz, NULL,
254 		    0), 0, "Unexpected mallctl() failure, i=%u", i);
255 	}
256 
257 	/* Exercise tcache ID recycling. */
258 	for (i = 0; i < NTCACHES; i++) {
259 		assert_d_eq(mallctl("tcache.destroy", NULL, NULL,
260 		    (void *)&tis[i], sizeof(unsigned)), 0,
261 		    "Unexpected mallctl() failure, i=%u", i);
262 	}
263 	for (i = 0; i < NTCACHES; i++) {
264 		sz = sizeof(unsigned);
265 		assert_d_eq(mallctl("tcache.create", (void *)&tis[i], &sz, NULL,
266 		    0), 0, "Unexpected mallctl() failure, i=%u", i);
267 	}
268 
269 	/* Flush empty tcaches. */
270 	for (i = 0; i < NTCACHES; i++) {
271 		assert_d_eq(mallctl("tcache.flush", NULL, NULL, (void *)&tis[i],
272 		    sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u",
273 		    i);
274 	}
275 
276 	/* Cache some allocations. */
277 	for (i = 0; i < NTCACHES; i++) {
278 		ps[i] = mallocx(psz, MALLOCX_TCACHE(tis[i]));
279 		assert_ptr_not_null(ps[i], "Unexpected mallocx() failure, i=%u",
280 		    i);
281 		dallocx(ps[i], MALLOCX_TCACHE(tis[i]));
282 
283 		qs[i] = mallocx(qsz, MALLOCX_TCACHE(tis[i]));
284 		assert_ptr_not_null(qs[i], "Unexpected mallocx() failure, i=%u",
285 		    i);
286 		dallocx(qs[i], MALLOCX_TCACHE(tis[i]));
287 	}
288 
289 	/* Verify that tcaches allocate cached regions. */
290 	for (i = 0; i < NTCACHES; i++) {
291 		void *p0 = ps[i];
292 		ps[i] = mallocx(psz, MALLOCX_TCACHE(tis[i]));
293 		assert_ptr_not_null(ps[i], "Unexpected mallocx() failure, i=%u",
294 		    i);
295 		assert_ptr_eq(ps[i], p0,
296 		    "Expected mallocx() to allocate cached region, i=%u", i);
297 	}
298 
299 	/* Verify that reallocation uses cached regions. */
300 	for (i = 0; i < NTCACHES; i++) {
301 		void *q0 = qs[i];
302 		qs[i] = rallocx(ps[i], qsz, MALLOCX_TCACHE(tis[i]));
303 		assert_ptr_not_null(qs[i], "Unexpected rallocx() failure, i=%u",
304 		    i);
305 		assert_ptr_eq(qs[i], q0,
306 		    "Expected rallocx() to allocate cached region, i=%u", i);
307 		/* Avoid undefined behavior in case of test failure. */
308 		if (qs[i] == NULL) {
309 			qs[i] = ps[i];
310 		}
311 	}
312 	for (i = 0; i < NTCACHES; i++) {
313 		dallocx(qs[i], MALLOCX_TCACHE(tis[i]));
314 	}
315 
316 	/* Flush some non-empty tcaches. */
317 	for (i = 0; i < NTCACHES/2; i++) {
318 		assert_d_eq(mallctl("tcache.flush", NULL, NULL, (void *)&tis[i],
319 		    sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u",
320 		    i);
321 	}
322 
323 	/* Destroy tcaches. */
324 	for (i = 0; i < NTCACHES; i++) {
325 		assert_d_eq(mallctl("tcache.destroy", NULL, NULL,
326 		    (void *)&tis[i], sizeof(unsigned)), 0,
327 		    "Unexpected mallctl() failure, i=%u", i);
328 	}
329 }
330 TEST_END
331 
TEST_BEGIN(test_thread_arena)332 TEST_BEGIN(test_thread_arena) {
333 	unsigned old_arena_ind, new_arena_ind, narenas;
334 
335 	const char *opa;
336 	size_t sz = sizeof(opa);
337 	assert_d_eq(mallctl("opt.percpu_arena", (void *)&opa, &sz, NULL, 0), 0,
338 	    "Unexpected mallctl() failure");
339 
340 	sz = sizeof(unsigned);
341 	assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
342 	    0, "Unexpected mallctl() failure");
343 	assert_u_eq(narenas, opt_narenas, "Number of arenas incorrect");
344 
345 	if (strcmp(opa, "disabled") == 0) {
346 		new_arena_ind = narenas - 1;
347 		assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz,
348 		    (void *)&new_arena_ind, sizeof(unsigned)), 0,
349 		    "Unexpected mallctl() failure");
350 		new_arena_ind = 0;
351 		assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz,
352 		    (void *)&new_arena_ind, sizeof(unsigned)), 0,
353 		    "Unexpected mallctl() failure");
354 	} else {
355 		assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz,
356 		    NULL, 0), 0, "Unexpected mallctl() failure");
357 		new_arena_ind = percpu_arena_ind_limit(opt_percpu_arena) - 1;
358 		if (old_arena_ind != new_arena_ind) {
359 			assert_d_eq(mallctl("thread.arena",
360 			    (void *)&old_arena_ind, &sz, (void *)&new_arena_ind,
361 			    sizeof(unsigned)), EPERM, "thread.arena ctl "
362 			    "should not be allowed with percpu arena");
363 		}
364 	}
365 }
366 TEST_END
367 
TEST_BEGIN(test_arena_i_initialized)368 TEST_BEGIN(test_arena_i_initialized) {
369 	unsigned narenas, i;
370 	size_t sz;
371 	size_t mib[3];
372 	size_t miblen = sizeof(mib) / sizeof(size_t);
373 	bool initialized;
374 
375 	sz = sizeof(narenas);
376 	assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
377 	    0, "Unexpected mallctl() failure");
378 
379 	assert_d_eq(mallctlnametomib("arena.0.initialized", mib, &miblen), 0,
380 	    "Unexpected mallctlnametomib() failure");
381 	for (i = 0; i < narenas; i++) {
382 		mib[1] = i;
383 		sz = sizeof(initialized);
384 		assert_d_eq(mallctlbymib(mib, miblen, &initialized, &sz, NULL,
385 		    0), 0, "Unexpected mallctl() failure");
386 	}
387 
388 	mib[1] = MALLCTL_ARENAS_ALL;
389 	sz = sizeof(initialized);
390 	assert_d_eq(mallctlbymib(mib, miblen, &initialized, &sz, NULL, 0), 0,
391 	    "Unexpected mallctl() failure");
392 	assert_true(initialized,
393 	    "Merged arena statistics should always be initialized");
394 
395 	/* Equivalent to the above but using mallctl() directly. */
396 	sz = sizeof(initialized);
397 	assert_d_eq(mallctl(
398 	    "arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".initialized",
399 	    (void *)&initialized, &sz, NULL, 0), 0,
400 	    "Unexpected mallctl() failure");
401 	assert_true(initialized,
402 	    "Merged arena statistics should always be initialized");
403 }
404 TEST_END
405 
TEST_BEGIN(test_arena_i_dirty_decay_ms)406 TEST_BEGIN(test_arena_i_dirty_decay_ms) {
407 	ssize_t dirty_decay_ms, orig_dirty_decay_ms, prev_dirty_decay_ms;
408 	size_t sz = sizeof(ssize_t);
409 
410 	assert_d_eq(mallctl("arena.0.dirty_decay_ms",
411 	    (void *)&orig_dirty_decay_ms, &sz, NULL, 0), 0,
412 	    "Unexpected mallctl() failure");
413 
414 	dirty_decay_ms = -2;
415 	assert_d_eq(mallctl("arena.0.dirty_decay_ms", NULL, NULL,
416 	    (void *)&dirty_decay_ms, sizeof(ssize_t)), EFAULT,
417 	    "Unexpected mallctl() success");
418 
419 	dirty_decay_ms = 0x7fffffff;
420 	assert_d_eq(mallctl("arena.0.dirty_decay_ms", NULL, NULL,
421 	    (void *)&dirty_decay_ms, sizeof(ssize_t)), 0,
422 	    "Unexpected mallctl() failure");
423 
424 	for (prev_dirty_decay_ms = dirty_decay_ms, dirty_decay_ms = -1;
425 	    dirty_decay_ms < 20; prev_dirty_decay_ms = dirty_decay_ms,
426 	    dirty_decay_ms++) {
427 		ssize_t old_dirty_decay_ms;
428 
429 		assert_d_eq(mallctl("arena.0.dirty_decay_ms",
430 		    (void *)&old_dirty_decay_ms, &sz, (void *)&dirty_decay_ms,
431 		    sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
432 		assert_zd_eq(old_dirty_decay_ms, prev_dirty_decay_ms,
433 		    "Unexpected old arena.0.dirty_decay_ms");
434 	}
435 }
436 TEST_END
437 
TEST_BEGIN(test_arena_i_muzzy_decay_ms)438 TEST_BEGIN(test_arena_i_muzzy_decay_ms) {
439 	ssize_t muzzy_decay_ms, orig_muzzy_decay_ms, prev_muzzy_decay_ms;
440 	size_t sz = sizeof(ssize_t);
441 
442 	assert_d_eq(mallctl("arena.0.muzzy_decay_ms",
443 	    (void *)&orig_muzzy_decay_ms, &sz, NULL, 0), 0,
444 	    "Unexpected mallctl() failure");
445 
446 	muzzy_decay_ms = -2;
447 	assert_d_eq(mallctl("arena.0.muzzy_decay_ms", NULL, NULL,
448 	    (void *)&muzzy_decay_ms, sizeof(ssize_t)), EFAULT,
449 	    "Unexpected mallctl() success");
450 
451 	muzzy_decay_ms = 0x7fffffff;
452 	assert_d_eq(mallctl("arena.0.muzzy_decay_ms", NULL, NULL,
453 	    (void *)&muzzy_decay_ms, sizeof(ssize_t)), 0,
454 	    "Unexpected mallctl() failure");
455 
456 	for (prev_muzzy_decay_ms = muzzy_decay_ms, muzzy_decay_ms = -1;
457 	    muzzy_decay_ms < 20; prev_muzzy_decay_ms = muzzy_decay_ms,
458 	    muzzy_decay_ms++) {
459 		ssize_t old_muzzy_decay_ms;
460 
461 		assert_d_eq(mallctl("arena.0.muzzy_decay_ms",
462 		    (void *)&old_muzzy_decay_ms, &sz, (void *)&muzzy_decay_ms,
463 		    sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
464 		assert_zd_eq(old_muzzy_decay_ms, prev_muzzy_decay_ms,
465 		    "Unexpected old arena.0.muzzy_decay_ms");
466 	}
467 }
468 TEST_END
469 
TEST_BEGIN(test_arena_i_purge)470 TEST_BEGIN(test_arena_i_purge) {
471 	unsigned narenas;
472 	size_t sz = sizeof(unsigned);
473 	size_t mib[3];
474 	size_t miblen = 3;
475 
476 	assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
477 	    "Unexpected mallctl() failure");
478 
479 	assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
480 	    0, "Unexpected mallctl() failure");
481 	assert_d_eq(mallctlnametomib("arena.0.purge", mib, &miblen), 0,
482 	    "Unexpected mallctlnametomib() failure");
483 	mib[1] = narenas;
484 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
485 	    "Unexpected mallctlbymib() failure");
486 
487 	mib[1] = MALLCTL_ARENAS_ALL;
488 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
489 	    "Unexpected mallctlbymib() failure");
490 }
491 TEST_END
492 
TEST_BEGIN(test_arena_i_decay)493 TEST_BEGIN(test_arena_i_decay) {
494 	unsigned narenas;
495 	size_t sz = sizeof(unsigned);
496 	size_t mib[3];
497 	size_t miblen = 3;
498 
499 	assert_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0,
500 	    "Unexpected mallctl() failure");
501 
502 	assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
503 	    0, "Unexpected mallctl() failure");
504 	assert_d_eq(mallctlnametomib("arena.0.decay", mib, &miblen), 0,
505 	    "Unexpected mallctlnametomib() failure");
506 	mib[1] = narenas;
507 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
508 	    "Unexpected mallctlbymib() failure");
509 
510 	mib[1] = MALLCTL_ARENAS_ALL;
511 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
512 	    "Unexpected mallctlbymib() failure");
513 }
514 TEST_END
515 
TEST_BEGIN(test_arena_i_dss)516 TEST_BEGIN(test_arena_i_dss) {
517 	const char *dss_prec_old, *dss_prec_new;
518 	size_t sz = sizeof(dss_prec_old);
519 	size_t mib[3];
520 	size_t miblen;
521 
522 	miblen = sizeof(mib)/sizeof(size_t);
523 	assert_d_eq(mallctlnametomib("arena.0.dss", mib, &miblen), 0,
524 	    "Unexpected mallctlnametomib() error");
525 
526 	dss_prec_new = "disabled";
527 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz,
528 	    (void *)&dss_prec_new, sizeof(dss_prec_new)), 0,
529 	    "Unexpected mallctl() failure");
530 	assert_str_ne(dss_prec_old, "primary",
531 	    "Unexpected default for dss precedence");
532 
533 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_new, &sz,
534 	    (void *)&dss_prec_old, sizeof(dss_prec_old)), 0,
535 	    "Unexpected mallctl() failure");
536 
537 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, NULL,
538 	    0), 0, "Unexpected mallctl() failure");
539 	assert_str_ne(dss_prec_old, "primary",
540 	    "Unexpected value for dss precedence");
541 
542 	mib[1] = narenas_total_get();
543 	dss_prec_new = "disabled";
544 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz,
545 	    (void *)&dss_prec_new, sizeof(dss_prec_new)), 0,
546 	    "Unexpected mallctl() failure");
547 	assert_str_ne(dss_prec_old, "primary",
548 	    "Unexpected default for dss precedence");
549 
550 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_new, &sz,
551 	    (void *)&dss_prec_old, sizeof(dss_prec_new)), 0,
552 	    "Unexpected mallctl() failure");
553 
554 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, NULL,
555 	    0), 0, "Unexpected mallctl() failure");
556 	assert_str_ne(dss_prec_old, "primary",
557 	    "Unexpected value for dss precedence");
558 }
559 TEST_END
560 
TEST_BEGIN(test_arena_i_retain_grow_limit)561 TEST_BEGIN(test_arena_i_retain_grow_limit) {
562 	size_t old_limit, new_limit, default_limit;
563 	size_t mib[3];
564 	size_t miblen;
565 
566 	bool retain_enabled;
567 	size_t sz = sizeof(retain_enabled);
568 	assert_d_eq(mallctl("opt.retain", &retain_enabled, &sz, NULL, 0),
569 	    0, "Unexpected mallctl() failure");
570 	test_skip_if(!retain_enabled);
571 
572 	sz = sizeof(default_limit);
573 	miblen = sizeof(mib)/sizeof(size_t);
574 	assert_d_eq(mallctlnametomib("arena.0.retain_grow_limit", mib, &miblen),
575 	    0, "Unexpected mallctlnametomib() error");
576 
577 	assert_d_eq(mallctlbymib(mib, miblen, &default_limit, &sz, NULL, 0), 0,
578 	    "Unexpected mallctl() failure");
579 	assert_zu_eq(default_limit, sz_pind2sz(EXTENT_GROW_MAX_PIND),
580 	    "Unexpected default for retain_grow_limit");
581 
582 	new_limit = PAGE - 1;
583 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &new_limit,
584 	    sizeof(new_limit)), EFAULT, "Unexpected mallctl() success");
585 
586 	new_limit = PAGE + 1;
587 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &new_limit,
588 	    sizeof(new_limit)), 0, "Unexpected mallctl() failure");
589 	assert_d_eq(mallctlbymib(mib, miblen, &old_limit, &sz, NULL, 0), 0,
590 	    "Unexpected mallctl() failure");
591 	assert_zu_eq(old_limit, PAGE,
592 	    "Unexpected value for retain_grow_limit");
593 
594 	/* Expect grow less than psize class 10. */
595 	new_limit = sz_pind2sz(10) - 1;
596 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &new_limit,
597 	    sizeof(new_limit)), 0, "Unexpected mallctl() failure");
598 	assert_d_eq(mallctlbymib(mib, miblen, &old_limit, &sz, NULL, 0), 0,
599 	    "Unexpected mallctl() failure");
600 	assert_zu_eq(old_limit, sz_pind2sz(9),
601 	    "Unexpected value for retain_grow_limit");
602 
603 	/* Restore to default. */
604 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &default_limit,
605 	    sizeof(default_limit)), 0, "Unexpected mallctl() failure");
606 }
607 TEST_END
608 
TEST_BEGIN(test_arenas_dirty_decay_ms)609 TEST_BEGIN(test_arenas_dirty_decay_ms) {
610 	ssize_t dirty_decay_ms, orig_dirty_decay_ms, prev_dirty_decay_ms;
611 	size_t sz = sizeof(ssize_t);
612 
613 	assert_d_eq(mallctl("arenas.dirty_decay_ms",
614 	    (void *)&orig_dirty_decay_ms, &sz, NULL, 0), 0,
615 	    "Unexpected mallctl() failure");
616 
617 	dirty_decay_ms = -2;
618 	assert_d_eq(mallctl("arenas.dirty_decay_ms", NULL, NULL,
619 	    (void *)&dirty_decay_ms, sizeof(ssize_t)), EFAULT,
620 	    "Unexpected mallctl() success");
621 
622 	dirty_decay_ms = 0x7fffffff;
623 	assert_d_eq(mallctl("arenas.dirty_decay_ms", NULL, NULL,
624 	    (void *)&dirty_decay_ms, sizeof(ssize_t)), 0,
625 	    "Expected mallctl() failure");
626 
627 	for (prev_dirty_decay_ms = dirty_decay_ms, dirty_decay_ms = -1;
628 	    dirty_decay_ms < 20; prev_dirty_decay_ms = dirty_decay_ms,
629 	    dirty_decay_ms++) {
630 		ssize_t old_dirty_decay_ms;
631 
632 		assert_d_eq(mallctl("arenas.dirty_decay_ms",
633 		    (void *)&old_dirty_decay_ms, &sz, (void *)&dirty_decay_ms,
634 		    sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
635 		assert_zd_eq(old_dirty_decay_ms, prev_dirty_decay_ms,
636 		    "Unexpected old arenas.dirty_decay_ms");
637 	}
638 }
639 TEST_END
640 
TEST_BEGIN(test_arenas_muzzy_decay_ms)641 TEST_BEGIN(test_arenas_muzzy_decay_ms) {
642 	ssize_t muzzy_decay_ms, orig_muzzy_decay_ms, prev_muzzy_decay_ms;
643 	size_t sz = sizeof(ssize_t);
644 
645 	assert_d_eq(mallctl("arenas.muzzy_decay_ms",
646 	    (void *)&orig_muzzy_decay_ms, &sz, NULL, 0), 0,
647 	    "Unexpected mallctl() failure");
648 
649 	muzzy_decay_ms = -2;
650 	assert_d_eq(mallctl("arenas.muzzy_decay_ms", NULL, NULL,
651 	    (void *)&muzzy_decay_ms, sizeof(ssize_t)), EFAULT,
652 	    "Unexpected mallctl() success");
653 
654 	muzzy_decay_ms = 0x7fffffff;
655 	assert_d_eq(mallctl("arenas.muzzy_decay_ms", NULL, NULL,
656 	    (void *)&muzzy_decay_ms, sizeof(ssize_t)), 0,
657 	    "Expected mallctl() failure");
658 
659 	for (prev_muzzy_decay_ms = muzzy_decay_ms, muzzy_decay_ms = -1;
660 	    muzzy_decay_ms < 20; prev_muzzy_decay_ms = muzzy_decay_ms,
661 	    muzzy_decay_ms++) {
662 		ssize_t old_muzzy_decay_ms;
663 
664 		assert_d_eq(mallctl("arenas.muzzy_decay_ms",
665 		    (void *)&old_muzzy_decay_ms, &sz, (void *)&muzzy_decay_ms,
666 		    sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
667 		assert_zd_eq(old_muzzy_decay_ms, prev_muzzy_decay_ms,
668 		    "Unexpected old arenas.muzzy_decay_ms");
669 	}
670 }
671 TEST_END
672 
TEST_BEGIN(test_arenas_constants)673 TEST_BEGIN(test_arenas_constants) {
674 #define TEST_ARENAS_CONSTANT(t, name, expected) do {			\
675 	t name;								\
676 	size_t sz = sizeof(t);						\
677 	assert_d_eq(mallctl("arenas."#name, (void *)&name, &sz, NULL,	\
678 	    0), 0, "Unexpected mallctl() failure");			\
679 	assert_zu_eq(name, expected, "Incorrect "#name" size");		\
680 } while (0)
681 
682 	TEST_ARENAS_CONSTANT(size_t, quantum, QUANTUM);
683 	TEST_ARENAS_CONSTANT(size_t, page, PAGE);
684 	TEST_ARENAS_CONSTANT(unsigned, nbins, NBINS);
685 	TEST_ARENAS_CONSTANT(unsigned, nlextents, NSIZES - NBINS);
686 
687 #undef TEST_ARENAS_CONSTANT
688 }
689 TEST_END
690 
TEST_BEGIN(test_arenas_bin_constants)691 TEST_BEGIN(test_arenas_bin_constants) {
692 #define TEST_ARENAS_BIN_CONSTANT(t, name, expected) do {		\
693 	t name;								\
694 	size_t sz = sizeof(t);						\
695 	assert_d_eq(mallctl("arenas.bin.0."#name, (void *)&name, &sz,	\
696 	    NULL, 0), 0, "Unexpected mallctl() failure");		\
697 	assert_zu_eq(name, expected, "Incorrect "#name" size");		\
698 } while (0)
699 
700 	TEST_ARENAS_BIN_CONSTANT(size_t, size, bin_infos[0].reg_size);
701 	TEST_ARENAS_BIN_CONSTANT(uint32_t, nregs, bin_infos[0].nregs);
702 	TEST_ARENAS_BIN_CONSTANT(size_t, slab_size,
703 	    bin_infos[0].slab_size);
704 
705 #undef TEST_ARENAS_BIN_CONSTANT
706 }
707 TEST_END
708 
TEST_BEGIN(test_arenas_lextent_constants)709 TEST_BEGIN(test_arenas_lextent_constants) {
710 #define TEST_ARENAS_LEXTENT_CONSTANT(t, name, expected) do {		\
711 	t name;								\
712 	size_t sz = sizeof(t);						\
713 	assert_d_eq(mallctl("arenas.lextent.0."#name, (void *)&name,	\
714 	    &sz, NULL, 0), 0, "Unexpected mallctl() failure");		\
715 	assert_zu_eq(name, expected, "Incorrect "#name" size");		\
716 } while (0)
717 
718 	TEST_ARENAS_LEXTENT_CONSTANT(size_t, size, LARGE_MINCLASS);
719 
720 #undef TEST_ARENAS_LEXTENT_CONSTANT
721 }
722 TEST_END
723 
TEST_BEGIN(test_arenas_create)724 TEST_BEGIN(test_arenas_create) {
725 	unsigned narenas_before, arena, narenas_after;
726 	size_t sz = sizeof(unsigned);
727 
728 	assert_d_eq(mallctl("arenas.narenas", (void *)&narenas_before, &sz,
729 	    NULL, 0), 0, "Unexpected mallctl() failure");
730 	assert_d_eq(mallctl("arenas.create", (void *)&arena, &sz, NULL, 0), 0,
731 	    "Unexpected mallctl() failure");
732 	assert_d_eq(mallctl("arenas.narenas", (void *)&narenas_after, &sz, NULL,
733 	    0), 0, "Unexpected mallctl() failure");
734 
735 	assert_u_eq(narenas_before+1, narenas_after,
736 	    "Unexpected number of arenas before versus after extension");
737 	assert_u_eq(arena, narenas_after-1, "Unexpected arena index");
738 }
739 TEST_END
740 
TEST_BEGIN(test_arenas_lookup)741 TEST_BEGIN(test_arenas_lookup) {
742 	unsigned arena, arena1;
743 	void *ptr;
744 	size_t sz = sizeof(unsigned);
745 
746 	assert_d_eq(mallctl("arenas.create", (void *)&arena, &sz, NULL, 0), 0,
747 	    "Unexpected mallctl() failure");
748 	ptr = mallocx(42, MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE);
749 	assert_ptr_not_null(ptr, "Unexpected mallocx() failure");
750 	assert_d_eq(mallctl("arenas.lookup", &arena1, &sz, &ptr, sizeof(ptr)),
751 	    0, "Unexpected mallctl() failure");
752 	assert_u_eq(arena, arena1, "Unexpected arena index");
753 	dallocx(ptr, 0);
754 }
755 TEST_END
756 
TEST_BEGIN(test_stats_arenas)757 TEST_BEGIN(test_stats_arenas) {
758 #define TEST_STATS_ARENAS(t, name) do {					\
759 	t name;								\
760 	size_t sz = sizeof(t);						\
761 	assert_d_eq(mallctl("stats.arenas.0."#name, (void *)&name, &sz,	\
762 	    NULL, 0), 0, "Unexpected mallctl() failure");		\
763 } while (0)
764 
765 	TEST_STATS_ARENAS(unsigned, nthreads);
766 	TEST_STATS_ARENAS(const char *, dss);
767 	TEST_STATS_ARENAS(ssize_t, dirty_decay_ms);
768 	TEST_STATS_ARENAS(ssize_t, muzzy_decay_ms);
769 	TEST_STATS_ARENAS(size_t, pactive);
770 	TEST_STATS_ARENAS(size_t, pdirty);
771 
772 #undef TEST_STATS_ARENAS
773 }
774 TEST_END
775 
776 int
main(void)777 main(void) {
778 	return test(
779 	    test_mallctl_errors,
780 	    test_mallctlnametomib_errors,
781 	    test_mallctlbymib_errors,
782 	    test_mallctl_read_write,
783 	    test_mallctlnametomib_short_mib,
784 	    test_mallctl_config,
785 	    test_mallctl_opt,
786 	    test_manpage_example,
787 	    test_tcache_none,
788 	    test_tcache,
789 	    test_thread_arena,
790 	    test_arena_i_initialized,
791 	    test_arena_i_dirty_decay_ms,
792 	    test_arena_i_muzzy_decay_ms,
793 	    test_arena_i_purge,
794 	    test_arena_i_decay,
795 	    test_arena_i_dss,
796 	    test_arena_i_retain_grow_limit,
797 	    test_arenas_dirty_decay_ms,
798 	    test_arenas_muzzy_decay_ms,
799 	    test_arenas_constants,
800 	    test_arenas_bin_constants,
801 	    test_arenas_lextent_constants,
802 	    test_arenas_create,
803 	    test_arenas_lookup,
804 	    test_stats_arenas);
805 }
806