1 #include "test/jemalloc_test.h"
2 
TEST_BEGIN(test_mallctl_errors)3 TEST_BEGIN(test_mallctl_errors)
4 {
5 	uint64_t epoch;
6 	size_t sz;
7 
8 	assert_d_eq(mallctl("no_such_name", NULL, NULL, NULL, 0), ENOENT,
9 	    "mallctl() should return ENOENT for non-existent names");
10 
11 	assert_d_eq(mallctl("version", NULL, NULL, "0.0.0", strlen("0.0.0")),
12 	    EPERM, "mallctl() should return EPERM on attempt to write "
13 	    "read-only value");
14 
15 	assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
16 	    sizeof(epoch)-1), EINVAL,
17 	    "mallctl() should return EINVAL for input size mismatch");
18 	assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
19 	    sizeof(epoch)+1), EINVAL,
20 	    "mallctl() should return EINVAL for input size mismatch");
21 
22 	sz = sizeof(epoch)-1;
23 	assert_d_eq(mallctl("epoch", (void *)&epoch, &sz, NULL, 0), EINVAL,
24 	    "mallctl() should return EINVAL for output size mismatch");
25 	sz = sizeof(epoch)+1;
26 	assert_d_eq(mallctl("epoch", (void *)&epoch, &sz, NULL, 0), EINVAL,
27 	    "mallctl() should return EINVAL for output size mismatch");
28 }
29 TEST_END
30 
TEST_BEGIN(test_mallctlnametomib_errors)31 TEST_BEGIN(test_mallctlnametomib_errors)
32 {
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 {
44 	uint64_t epoch;
45 	size_t sz;
46 	size_t mib[1];
47 	size_t miblen;
48 
49 	miblen = sizeof(mib)/sizeof(size_t);
50 	assert_d_eq(mallctlnametomib("version", mib, &miblen), 0,
51 	    "Unexpected mallctlnametomib() failure");
52 
53 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, "0.0.0",
54 	    strlen("0.0.0")), EPERM, "mallctl() should return EPERM on "
55 	    "attempt to write read-only value");
56 
57 	miblen = sizeof(mib)/sizeof(size_t);
58 	assert_d_eq(mallctlnametomib("epoch", mib, &miblen), 0,
59 	    "Unexpected mallctlnametomib() failure");
60 
61 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&epoch,
62 	    sizeof(epoch)-1), EINVAL,
63 	    "mallctlbymib() should return EINVAL for input size mismatch");
64 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&epoch,
65 	    sizeof(epoch)+1), EINVAL,
66 	    "mallctlbymib() should return EINVAL for input size mismatch");
67 
68 	sz = sizeof(epoch)-1;
69 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&epoch, &sz, NULL, 0),
70 	    EINVAL,
71 	    "mallctlbymib() should return EINVAL for output size mismatch");
72 	sz = sizeof(epoch)+1;
73 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&epoch, &sz, NULL, 0),
74 	    EINVAL,
75 	    "mallctlbymib() should return EINVAL for output size mismatch");
76 }
77 TEST_END
78 
TEST_BEGIN(test_mallctl_read_write)79 TEST_BEGIN(test_mallctl_read_write)
80 {
81 	uint64_t old_epoch, new_epoch;
82 	size_t sz = sizeof(old_epoch);
83 
84 	/* Blind. */
85 	assert_d_eq(mallctl("epoch", NULL, NULL, NULL, 0), 0,
86 	    "Unexpected mallctl() failure");
87 	assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
88 
89 	/* Read. */
90 	assert_d_eq(mallctl("epoch", (void *)&old_epoch, &sz, NULL, 0), 0,
91 	    "Unexpected mallctl() failure");
92 	assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
93 
94 	/* Write. */
95 	assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&new_epoch,
96 	    sizeof(new_epoch)), 0, "Unexpected mallctl() failure");
97 	assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
98 
99 	/* Read+write. */
100 	assert_d_eq(mallctl("epoch", (void *)&old_epoch, &sz,
101 	    (void *)&new_epoch, sizeof(new_epoch)), 0,
102 	    "Unexpected mallctl() failure");
103 	assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
104 }
105 TEST_END
106 
TEST_BEGIN(test_mallctlnametomib_short_mib)107 TEST_BEGIN(test_mallctlnametomib_short_mib)
108 {
109 	size_t mib[4];
110 	size_t miblen;
111 
112 	miblen = 3;
113 	mib[3] = 42;
114 	assert_d_eq(mallctlnametomib("arenas.bin.0.nregs", mib, &miblen), 0,
115 	    "Unexpected mallctlnametomib() failure");
116 	assert_zu_eq(miblen, 3, "Unexpected mib output length");
117 	assert_zu_eq(mib[3], 42,
118 	    "mallctlnametomib() wrote past the end of the input mib");
119 }
120 TEST_END
121 
TEST_BEGIN(test_mallctl_config)122 TEST_BEGIN(test_mallctl_config)
123 {
124 #define	TEST_MALLCTL_CONFIG(config, t) do {				\
125 	t oldval;							\
126 	size_t sz = sizeof(oldval);					\
127 	assert_d_eq(mallctl("config."#config, (void *)&oldval, &sz,	\
128 	    NULL, 0), 0, "Unexpected mallctl() failure");		\
129 	assert_b_eq(oldval, config_##config, "Incorrect config value");	\
130 	assert_zu_eq(sz, sizeof(oldval), "Unexpected output size");	\
131 } while (0)
132 
133 	TEST_MALLCTL_CONFIG(cache_oblivious, bool);
134 	TEST_MALLCTL_CONFIG(debug, bool);
135 	TEST_MALLCTL_CONFIG(fill, bool);
136 	TEST_MALLCTL_CONFIG(lazy_lock, bool);
137 	TEST_MALLCTL_CONFIG(malloc_conf, const char *);
138 	TEST_MALLCTL_CONFIG(munmap, bool);
139 	TEST_MALLCTL_CONFIG(prof, bool);
140 	TEST_MALLCTL_CONFIG(prof_libgcc, bool);
141 	TEST_MALLCTL_CONFIG(prof_libunwind, bool);
142 	TEST_MALLCTL_CONFIG(stats, bool);
143 	TEST_MALLCTL_CONFIG(tcache, bool);
144 	TEST_MALLCTL_CONFIG(tls, bool);
145 	TEST_MALLCTL_CONFIG(utrace, bool);
146 	TEST_MALLCTL_CONFIG(xmalloc, bool);
147 
148 #undef TEST_MALLCTL_CONFIG
149 }
150 TEST_END
151 
TEST_BEGIN(test_mallctl_opt)152 TEST_BEGIN(test_mallctl_opt)
153 {
154 	bool config_always = true;
155 
156 #define	TEST_MALLCTL_OPT(t, opt, config) do {				\
157 	t oldval;							\
158 	size_t sz = sizeof(oldval);					\
159 	int expected = config_##config ? 0 : ENOENT;			\
160 	int result = mallctl("opt."#opt, (void *)&oldval, &sz, NULL,	\
161 	    0);								\
162 	assert_d_eq(result, expected,					\
163 	    "Unexpected mallctl() result for opt."#opt);		\
164 	assert_zu_eq(sz, sizeof(oldval), "Unexpected output size");	\
165 } while (0)
166 
167 	TEST_MALLCTL_OPT(bool, abort, always);
168 	TEST_MALLCTL_OPT(const char *, dss, always);
169 	TEST_MALLCTL_OPT(unsigned, narenas, always);
170 	TEST_MALLCTL_OPT(ssize_t, decay_time, always);
171 	TEST_MALLCTL_OPT(bool, stats_print, always);
172 	TEST_MALLCTL_OPT(const char *, junk, fill);
173 	TEST_MALLCTL_OPT(bool, zero, fill);
174 	TEST_MALLCTL_OPT(bool, utrace, utrace);
175 	TEST_MALLCTL_OPT(bool, xmalloc, xmalloc);
176 	TEST_MALLCTL_OPT(bool, tcache, tcache);
177 	TEST_MALLCTL_OPT(size_t, lg_tcache_max, tcache);
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 {
194 	unsigned nbins, i;
195 	size_t mib[4];
196 	size_t len, miblen;
197 
198 	len = sizeof(nbins);
199 	assert_d_eq(mallctl("arenas.nbins", (void *)&nbins, &len, NULL, 0), 0,
200 	    "Unexpected mallctl() failure");
201 
202 	miblen = 4;
203 	assert_d_eq(mallctlnametomib("arenas.bin.0.size", mib, &miblen), 0,
204 	    "Unexpected mallctlnametomib() failure");
205 	for (i = 0; i < nbins; i++) {
206 		size_t bin_size;
207 
208 		mib[2] = i;
209 		len = sizeof(bin_size);
210 		assert_d_eq(mallctlbymib(mib, miblen, (void *)&bin_size, &len,
211 		    NULL, 0), 0, "Unexpected mallctlbymib() failure");
212 		/* Do something with bin_size... */
213 	}
214 }
215 TEST_END
216 
TEST_BEGIN(test_tcache_none)217 TEST_BEGIN(test_tcache_none)
218 {
219 	void *p0, *q, *p1;
220 
221 	test_skip_if(!config_tcache);
222 
223 	/* Allocate p and q. */
224 	p0 = mallocx(42, 0);
225 	assert_ptr_not_null(p0, "Unexpected mallocx() failure");
226 	q = mallocx(42, 0);
227 	assert_ptr_not_null(q, "Unexpected mallocx() failure");
228 
229 	/* Deallocate p and q, but bypass the tcache for q. */
230 	dallocx(p0, 0);
231 	dallocx(q, MALLOCX_TCACHE_NONE);
232 
233 	/* Make sure that tcache-based allocation returns p, not q. */
234 	p1 = mallocx(42, 0);
235 	assert_ptr_not_null(p1, "Unexpected mallocx() failure");
236 	assert_ptr_eq(p0, p1, "Expected tcache to allocate cached region");
237 
238 	/* Clean up. */
239 	dallocx(p1, MALLOCX_TCACHE_NONE);
240 }
241 TEST_END
242 
TEST_BEGIN(test_tcache)243 TEST_BEGIN(test_tcache)
244 {
245 #define	NTCACHES	10
246 	unsigned tis[NTCACHES];
247 	void *ps[NTCACHES];
248 	void *qs[NTCACHES];
249 	unsigned i;
250 	size_t sz, psz, qsz;
251 
252 	test_skip_if(!config_tcache);
253 
254 	psz = 42;
255 	qsz = nallocx(psz, 0) + 1;
256 
257 	/* Create tcaches. */
258 	for (i = 0; i < NTCACHES; i++) {
259 		sz = sizeof(unsigned);
260 		assert_d_eq(mallctl("tcache.create", (void *)&tis[i], &sz, NULL,
261 		    0), 0, "Unexpected mallctl() failure, i=%u", i);
262 	}
263 
264 	/* Exercise tcache ID recycling. */
265 	for (i = 0; i < NTCACHES; i++) {
266 		assert_d_eq(mallctl("tcache.destroy", NULL, NULL,
267 		    (void *)&tis[i], sizeof(unsigned)), 0,
268 		    "Unexpected mallctl() failure, i=%u", i);
269 	}
270 	for (i = 0; i < NTCACHES; i++) {
271 		sz = sizeof(unsigned);
272 		assert_d_eq(mallctl("tcache.create", (void *)&tis[i], &sz, NULL,
273 		    0), 0, "Unexpected mallctl() failure, i=%u", i);
274 	}
275 
276 	/* Flush empty tcaches. */
277 	for (i = 0; i < NTCACHES; i++) {
278 		assert_d_eq(mallctl("tcache.flush", NULL, NULL, (void *)&tis[i],
279 		    sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u",
280 		    i);
281 	}
282 
283 	/* Cache some allocations. */
284 	for (i = 0; i < NTCACHES; i++) {
285 		ps[i] = mallocx(psz, MALLOCX_TCACHE(tis[i]));
286 		assert_ptr_not_null(ps[i], "Unexpected mallocx() failure, i=%u",
287 		    i);
288 		dallocx(ps[i], MALLOCX_TCACHE(tis[i]));
289 
290 		qs[i] = mallocx(qsz, MALLOCX_TCACHE(tis[i]));
291 		assert_ptr_not_null(qs[i], "Unexpected mallocx() failure, i=%u",
292 		    i);
293 		dallocx(qs[i], MALLOCX_TCACHE(tis[i]));
294 	}
295 
296 	/* Verify that tcaches allocate cached regions. */
297 	for (i = 0; i < NTCACHES; i++) {
298 		void *p0 = ps[i];
299 		ps[i] = mallocx(psz, MALLOCX_TCACHE(tis[i]));
300 		assert_ptr_not_null(ps[i], "Unexpected mallocx() failure, i=%u",
301 		    i);
302 		assert_ptr_eq(ps[i], p0,
303 		    "Expected mallocx() to allocate cached region, i=%u", i);
304 	}
305 
306 	/* Verify that reallocation uses cached regions. */
307 	for (i = 0; i < NTCACHES; i++) {
308 		void *q0 = qs[i];
309 		qs[i] = rallocx(ps[i], qsz, MALLOCX_TCACHE(tis[i]));
310 		assert_ptr_not_null(qs[i], "Unexpected rallocx() failure, i=%u",
311 		    i);
312 		assert_ptr_eq(qs[i], q0,
313 		    "Expected rallocx() to allocate cached region, i=%u", i);
314 		/* Avoid undefined behavior in case of test failure. */
315 		if (qs[i] == NULL)
316 			qs[i] = ps[i];
317 	}
318 	for (i = 0; i < NTCACHES; i++)
319 		dallocx(qs[i], MALLOCX_TCACHE(tis[i]));
320 
321 	/* Flush some non-empty tcaches. */
322 	for (i = 0; i < NTCACHES/2; i++) {
323 		assert_d_eq(mallctl("tcache.flush", NULL, NULL, (void *)&tis[i],
324 		    sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u",
325 		    i);
326 	}
327 
328 	/* Destroy tcaches. */
329 	for (i = 0; i < NTCACHES; i++) {
330 		assert_d_eq(mallctl("tcache.destroy", NULL, NULL,
331 		    (void *)&tis[i], sizeof(unsigned)), 0,
332 		    "Unexpected mallctl() failure, i=%u", i);
333 	}
334 }
335 TEST_END
336 
TEST_BEGIN(test_thread_arena)337 TEST_BEGIN(test_thread_arena)
338 {
339 	unsigned arena_old, arena_new, narenas;
340 	size_t sz = sizeof(unsigned);
341 
342 	assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
343 	    0, "Unexpected mallctl() failure");
344 	assert_u_eq(narenas, opt_narenas, "Number of arenas incorrect");
345 	arena_new = narenas - 1;
346 	assert_d_eq(mallctl("thread.arena", (void *)&arena_old, &sz,
347 	    (void *)&arena_new, sizeof(unsigned)), 0,
348 	    "Unexpected mallctl() failure");
349 	arena_new = 0;
350 	assert_d_eq(mallctl("thread.arena", (void *)&arena_old, &sz,
351 	    (void *)&arena_new, sizeof(unsigned)), 0,
352 	    "Unexpected mallctl() failure");
353 }
354 TEST_END
355 
TEST_BEGIN(test_arena_i_initialized)356 TEST_BEGIN(test_arena_i_initialized)
357 {
358 	unsigned narenas, i;
359 	size_t sz;
360 	size_t mib[3];
361 	size_t miblen = sizeof(mib) / sizeof(size_t);
362 	bool initialized;
363 
364 	sz = sizeof(narenas);
365 	assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
366 	    0, "Unexpected mallctl() failure");
367 
368 	assert_d_eq(mallctlnametomib("arena.0.initialized", mib, &miblen), 0,
369 	    "Unexpected mallctlnametomib() failure");
370 	for (i = 0; i < narenas; i++) {
371 		mib[1] = i;
372 		sz = sizeof(initialized);
373 		assert_d_eq(mallctlbymib(mib, miblen, &initialized, &sz, NULL,
374 		    0), 0, "Unexpected mallctl() failure");
375 	}
376 
377 	mib[1] = MALLCTL_ARENAS_ALL;
378 	sz = sizeof(initialized);
379 	assert_d_eq(mallctlbymib(mib, miblen, &initialized, &sz, NULL, 0), 0,
380 	    "Unexpected mallctl() failure");
381 	assert_true(initialized,
382 	    "Merged arena statistics should always be initialized");
383 
384 	/* Equivalent to the above but using mallctl() directly. */
385 	sz = sizeof(initialized);
386 	assert_d_eq(mallctl(
387 	    "arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".initialized",
388 	    (void *)&initialized, &sz, NULL, 0), 0,
389 	    "Unexpected mallctl() failure");
390 	assert_true(initialized,
391 	    "Merged arena statistics should always be initialized");
392 }
393 TEST_END
394 
TEST_BEGIN(test_arena_i_decay_time)395 TEST_BEGIN(test_arena_i_decay_time)
396 {
397 	ssize_t decay_time, orig_decay_time, prev_decay_time;
398 	size_t sz = sizeof(ssize_t);
399 
400 	assert_d_eq(mallctl("arena.0.decay_time", (void *)&orig_decay_time, &sz,
401 	    NULL, 0), 0, "Unexpected mallctl() failure");
402 
403 	decay_time = -2;
404 	assert_d_eq(mallctl("arena.0.decay_time", NULL, NULL,
405 	    (void *)&decay_time, sizeof(ssize_t)), EFAULT,
406 	    "Unexpected mallctl() success");
407 
408 	decay_time = 0x7fffffff;
409 	assert_d_eq(mallctl("arena.0.decay_time", NULL, NULL,
410 	    (void *)&decay_time, sizeof(ssize_t)), 0,
411 	    "Unexpected mallctl() failure");
412 
413 	for (prev_decay_time = decay_time, decay_time = -1;
414 	    decay_time < 20; prev_decay_time = decay_time, decay_time++) {
415 		ssize_t old_decay_time;
416 
417 		assert_d_eq(mallctl("arena.0.decay_time", (void *)&old_decay_time,
418 		    &sz, (void *)&decay_time, sizeof(ssize_t)), 0,
419 		    "Unexpected mallctl() failure");
420 		assert_zd_eq(old_decay_time, prev_decay_time,
421 		    "Unexpected old arena.0.decay_time");
422 	}
423 }
424 TEST_END
425 
TEST_BEGIN(test_arena_i_purge)426 TEST_BEGIN(test_arena_i_purge)
427 {
428 	unsigned narenas;
429 	size_t sz = sizeof(unsigned);
430 	size_t mib[3];
431 	size_t miblen = 3;
432 
433 	assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
434 	    "Unexpected mallctl() failure");
435 
436 	assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
437 	    0, "Unexpected mallctl() failure");
438 	assert_d_eq(mallctlnametomib("arena.0.purge", mib, &miblen), 0,
439 	    "Unexpected mallctlnametomib() failure");
440 	mib[1] = narenas;
441 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
442 	    "Unexpected mallctlbymib() failure");
443 
444 	mib[1] = MALLCTL_ARENAS_ALL;
445 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
446 	    "Unexpected mallctlbymib() failure");
447 }
448 TEST_END
449 
TEST_BEGIN(test_arena_i_decay)450 TEST_BEGIN(test_arena_i_decay)
451 {
452 	unsigned narenas;
453 	size_t sz = sizeof(unsigned);
454 	size_t mib[3];
455 	size_t miblen = 3;
456 
457 	assert_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0,
458 	    "Unexpected mallctl() failure");
459 
460 	assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
461 	    0, "Unexpected mallctl() failure");
462 	assert_d_eq(mallctlnametomib("arena.0.decay", mib, &miblen), 0,
463 	    "Unexpected mallctlnametomib() failure");
464 	mib[1] = narenas;
465 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
466 	    "Unexpected mallctlbymib() failure");
467 
468 	mib[1] = MALLCTL_ARENAS_ALL;
469 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
470 	    "Unexpected mallctlbymib() failure");
471 }
472 TEST_END
473 
TEST_BEGIN(test_arena_i_dss)474 TEST_BEGIN(test_arena_i_dss)
475 {
476 	const char *dss_prec_old, *dss_prec_new;
477 	size_t sz = sizeof(dss_prec_old);
478 	size_t mib[3];
479 	size_t miblen;
480 
481 	miblen = sizeof(mib)/sizeof(size_t);
482 	assert_d_eq(mallctlnametomib("arena.0.dss", mib, &miblen), 0,
483 	    "Unexpected mallctlnametomib() error");
484 
485 	dss_prec_new = "disabled";
486 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz,
487 	    (void *)&dss_prec_new, sizeof(dss_prec_new)), 0,
488 	    "Unexpected mallctl() failure");
489 	assert_str_ne(dss_prec_old, "primary",
490 	    "Unexpected default for dss precedence");
491 
492 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_new, &sz,
493 	    (void *)&dss_prec_old, sizeof(dss_prec_old)), 0,
494 	    "Unexpected mallctl() failure");
495 
496 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, NULL,
497 	    0), 0, "Unexpected mallctl() failure");
498 	assert_str_ne(dss_prec_old, "primary",
499 	    "Unexpected value for dss precedence");
500 
501 	mib[1] = narenas_total_get();
502 	dss_prec_new = "disabled";
503 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz,
504 	    (void *)&dss_prec_new, sizeof(dss_prec_new)), 0,
505 	    "Unexpected mallctl() failure");
506 	assert_str_ne(dss_prec_old, "primary",
507 	    "Unexpected default for dss precedence");
508 
509 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_new, &sz,
510 	    (void *)&dss_prec_old, sizeof(dss_prec_new)), 0,
511 	    "Unexpected mallctl() failure");
512 
513 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, NULL,
514 	    0), 0, "Unexpected mallctl() failure");
515 	assert_str_ne(dss_prec_old, "primary",
516 	    "Unexpected value for dss precedence");
517 }
518 TEST_END
519 
TEST_BEGIN(test_arenas_decay_time)520 TEST_BEGIN(test_arenas_decay_time)
521 {
522 	ssize_t decay_time, orig_decay_time, prev_decay_time;
523 	size_t sz = sizeof(ssize_t);
524 
525 	assert_d_eq(mallctl("arenas.decay_time", (void *)&orig_decay_time, &sz,
526 	    NULL, 0), 0, "Unexpected mallctl() failure");
527 
528 	decay_time = -2;
529 	assert_d_eq(mallctl("arenas.decay_time", NULL, NULL,
530 	    (void *)&decay_time, sizeof(ssize_t)), EFAULT,
531 	    "Unexpected mallctl() success");
532 
533 	decay_time = 0x7fffffff;
534 	assert_d_eq(mallctl("arenas.decay_time", NULL, NULL,
535 	    (void *)&decay_time, sizeof(ssize_t)), 0,
536 	    "Expected mallctl() failure");
537 
538 	for (prev_decay_time = decay_time, decay_time = -1;
539 	    decay_time < 20; prev_decay_time = decay_time, decay_time++) {
540 		ssize_t old_decay_time;
541 
542 		assert_d_eq(mallctl("arenas.decay_time",
543 		    (void *)&old_decay_time, &sz, (void *)&decay_time,
544 		    sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
545 		assert_zd_eq(old_decay_time, prev_decay_time,
546 		    "Unexpected old arenas.decay_time");
547 	}
548 }
549 TEST_END
550 
TEST_BEGIN(test_arenas_constants)551 TEST_BEGIN(test_arenas_constants)
552 {
553 #define	TEST_ARENAS_CONSTANT(t, name, expected) do {			\
554 	t name;								\
555 	size_t sz = sizeof(t);						\
556 	assert_d_eq(mallctl("arenas."#name, (void *)&name, &sz, NULL,	\
557 	    0), 0, "Unexpected mallctl() failure");			\
558 	assert_zu_eq(name, expected, "Incorrect "#name" size");		\
559 } while (0)
560 
561 	TEST_ARENAS_CONSTANT(size_t, quantum, QUANTUM);
562 	TEST_ARENAS_CONSTANT(size_t, page, PAGE);
563 	TEST_ARENAS_CONSTANT(unsigned, nbins, NBINS);
564 	TEST_ARENAS_CONSTANT(unsigned, nlextents, NSIZES - NBINS);
565 
566 #undef TEST_ARENAS_CONSTANT
567 }
568 TEST_END
569 
TEST_BEGIN(test_arenas_bin_constants)570 TEST_BEGIN(test_arenas_bin_constants)
571 {
572 #define	TEST_ARENAS_BIN_CONSTANT(t, name, expected) do {		\
573 	t name;								\
574 	size_t sz = sizeof(t);						\
575 	assert_d_eq(mallctl("arenas.bin.0."#name, (void *)&name, &sz,	\
576 	    NULL, 0), 0, "Unexpected mallctl() failure");		\
577 	assert_zu_eq(name, expected, "Incorrect "#name" size");		\
578 } while (0)
579 
580 	TEST_ARENAS_BIN_CONSTANT(size_t, size, arena_bin_info[0].reg_size);
581 	TEST_ARENAS_BIN_CONSTANT(uint32_t, nregs, arena_bin_info[0].nregs);
582 	TEST_ARENAS_BIN_CONSTANT(size_t, slab_size,
583 	    arena_bin_info[0].slab_size);
584 
585 #undef TEST_ARENAS_BIN_CONSTANT
586 }
587 TEST_END
588 
TEST_BEGIN(test_arenas_lextent_constants)589 TEST_BEGIN(test_arenas_lextent_constants)
590 {
591 #define	TEST_ARENAS_LEXTENT_CONSTANT(t, name, expected) do {		\
592 	t name;								\
593 	size_t sz = sizeof(t);						\
594 	assert_d_eq(mallctl("arenas.lextent.0."#name, (void *)&name,	\
595 	    &sz, NULL, 0), 0, "Unexpected mallctl() failure");		\
596 	assert_zu_eq(name, expected, "Incorrect "#name" size");		\
597 } while (0)
598 
599 	TEST_ARENAS_LEXTENT_CONSTANT(size_t, size, LARGE_MINCLASS);
600 
601 #undef TEST_ARENAS_LEXTENT_CONSTANT
602 }
603 TEST_END
604 
TEST_BEGIN(test_arenas_create)605 TEST_BEGIN(test_arenas_create)
606 {
607 	unsigned narenas_before, arena, narenas_after;
608 	size_t sz = sizeof(unsigned);
609 
610 	assert_d_eq(mallctl("arenas.narenas", (void *)&narenas_before, &sz,
611 	    NULL, 0), 0, "Unexpected mallctl() failure");
612 	assert_d_eq(mallctl("arenas.create", (void *)&arena, &sz, NULL, 0), 0,
613 	    "Unexpected mallctl() failure");
614 	assert_d_eq(mallctl("arenas.narenas", (void *)&narenas_after, &sz, NULL,
615 	    0), 0, "Unexpected mallctl() failure");
616 
617 	assert_u_eq(narenas_before+1, narenas_after,
618 	    "Unexpected number of arenas before versus after extension");
619 	assert_u_eq(arena, narenas_after-1, "Unexpected arena index");
620 }
621 TEST_END
622 
TEST_BEGIN(test_stats_arenas)623 TEST_BEGIN(test_stats_arenas)
624 {
625 #define	TEST_STATS_ARENAS(t, name) do {					\
626 	t name;								\
627 	size_t sz = sizeof(t);						\
628 	assert_d_eq(mallctl("stats.arenas.0."#name, (void *)&name, &sz,	\
629 	    NULL, 0), 0, "Unexpected mallctl() failure");		\
630 } while (0)
631 
632 	TEST_STATS_ARENAS(unsigned, nthreads);
633 	TEST_STATS_ARENAS(const char *, dss);
634 	TEST_STATS_ARENAS(ssize_t, decay_time);
635 	TEST_STATS_ARENAS(size_t, pactive);
636 	TEST_STATS_ARENAS(size_t, pdirty);
637 
638 #undef TEST_STATS_ARENAS
639 }
640 TEST_END
641 
642 int
main(void)643 main(void)
644 {
645 	return (test(
646 	    test_mallctl_errors,
647 	    test_mallctlnametomib_errors,
648 	    test_mallctlbymib_errors,
649 	    test_mallctl_read_write,
650 	    test_mallctlnametomib_short_mib,
651 	    test_mallctl_config,
652 	    test_mallctl_opt,
653 	    test_manpage_example,
654 	    test_tcache_none,
655 	    test_tcache,
656 	    test_thread_arena,
657 	    test_arena_i_initialized,
658 	    test_arena_i_decay_time,
659 	    test_arena_i_purge,
660 	    test_arena_i_decay,
661 	    test_arena_i_dss,
662 	    test_arenas_decay_time,
663 	    test_arenas_constants,
664 	    test_arenas_bin_constants,
665 	    test_arenas_lextent_constants,
666 	    test_arenas_create,
667 	    test_stats_arenas));
668 }
669