2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright 2016 Joyent, Inc.
14 * Copyright 2024 Oxide Computer Company
18 * Basic tests for aligned_alloc(3C). Note that we test ENOMEM failure by
19 * relying on the implementation of the current libc malloc. Specifically we go
20 * through and add a mapping so we can't expand the heap and then use it up. If
21 * the memory allocator is ever changed, this test will start failing, at which
22 * point, it may not be worth the cost of keeping it around.
31 #include <sys/sysmacros.h>
33 #include <sys/debug.h>
44 static const alloc_test_t alloc_tests
[] = {
45 { 0, sizeof (long), EINVAL
, "zero alignment fails with EINVAL" },
46 { sizeof (long), 0, EINVAL
, "zero size fails with EINVAL" },
47 { 128, 3, EINVAL
, "3-byte alignment fails with EINVAL" },
48 { 128, 7777, EINVAL
, "7777-byte alignment fails with EINVAL" },
49 { 128, 23, EINVAL
, "23-byte alignment fails with EINVAL" },
50 { sizeof (char), alignof (char), 0, "alignof (char), 1 byte" },
51 { 5, alignof (char), 0, "alignof (char), multiple bytes" },
52 { 1, alignof (short), 0, "alignof (short), 1 byte" },
53 { 16, alignof (short), 0, "alignof (short), 16 byte" },
54 { 1, alignof (int), 0, "alignof (int), 1 byte" },
55 { 4, alignof (int), 0, "alignof (int), 4 bytes" },
56 { 22, alignof (int), 0, "alignof (int), 22 bytes" },
57 /* We skip long here because it varies between ILP32/LP64 */
58 { 7, alignof (long long), 0, "alignof (long long), 7 bytes" },
59 { 128, alignof (long long), 0, "alignof (long long), 128 bytes" },
60 { 511, alignof (long long), 0, "alignof (long long), 511 bytes" },
61 { 16, 16, 0, "16-byte alignment), 16 bytes" },
62 { 256, 16, 0, "16-byte alignment), 256 bytes" },
63 { 256, 4096, 0, "4096-byte alignment), 256 bytes" },
64 { 4096, 4096, 0, "4096-byte alignment), 4096 bytes" },
68 * Disable the per-thread caches and enable debugging if launched with umem.
71 _umem_debug_init(void)
73 return ("default,verbose");
77 _umem_options_init(void)
79 return ("perthreadcache=0");
83 alloc_test_one(const alloc_test_t
*test
)
86 void *buf
= aligned_alloc(test
->at_align
, test
->at_size
);
89 if (test
->at_errno
== 0) {
90 warnx("TEST FAILED: %s: allocation failed with %s, but "
91 "expected success", test
->at_desc
,
92 strerrorname_np(errno
));
93 } else if (errno
!= test
->at_errno
) {
94 warnx("TEST FAILED: %s: allocation failed with %s, but "
95 "expected errno %s", test
->at_desc
,
96 strerrorname_np(errno
),
97 strerrorname_np(test
->at_errno
));
99 (void) printf("TEST PASSED: %s\n", test
->at_desc
);
102 } else if (test
->at_errno
!= 0) {
103 warnx("TEST FAILED: %s: allocation succeeded, but expected "
104 "errno %s", test
->at_desc
, strerrorname_np(test
->at_errno
));
106 (void) printf("TEST PASSED: %s\n", test
->at_desc
);
115 alloc_test_enomem(const alloc_test_t
*test
)
118 void *buf
= aligned_alloc(test
->at_align
, test
->at_size
);
121 warnx("TEST FAILED: %s (forced ENOMEM/EAGAIN): succeeded, but "
122 "expected ENOMEM", test
->at_desc
);
123 } else if (errno
!= ENOMEM
&& errno
!= EAGAIN
) {
124 warnx("TEST FAILED: %s (forced ENOMEM/EAGAIN): failed with %s, "
125 "but expected ENOMEM", test
->at_desc
,
126 strerrordesc_np(errno
));
128 (void) printf("TEST PASSED: %s: ENOMEM/EAGAIN forced\n",
141 VERIFY0(proc_get_status(getpid(), &status
));
142 VERIFY3P(mmap((caddr_t
)P2ROUNDUP(status
.pr_brkbase
+
143 status
.pr_brksize
, 0x1000), 0x1000,
144 PROT_READ
, MAP_ANON
| MAP_FIXED
| MAP_PRIVATE
, -1, 0),
148 if (malloc(16) == NULL
)
153 if (aligned_alloc(sizeof (void *), 16) == NULL
)
159 * Because this test is leveraging LD_PRELOAD in the test runner to test
160 * different malloc libraries, we can't call umem_setmtbf() directly. Instead we
161 * ask rtld to find it for us, which is a bit gross, but works.
166 void (*mtbf
)(uint32_t) = dlsym(RTLD_DEFAULT
, "umem_setmtbf");
168 errx(EXIT_FAILURE
, "failed to find umem_setmtbf: %s",
179 int ret
= EXIT_SUCCESS
;
181 for (size_t i
= 0; i
< ARRAY_SIZE(alloc_tests
); i
++) {
182 if (!alloc_test_one(&alloc_tests
[i
])) {
188 * To catch failure tests, we need to know what memory allocator we're
189 * using which we expect to be indicated via an LD_PRELOAD environment
190 * variable. If it's not set, assume libc.
192 preload
= getenv("LD_PRELOAD");
193 if (preload
!= NULL
) {
194 if (strstr(preload
, "umem") != NULL
) {
197 warnx("malloc(3C) library %s not supported, skipping "
198 "ENOMEM tests", preload
);
205 for (size_t i
= 0; i
< ARRAY_SIZE(alloc_tests
); i
++) {
206 if (alloc_tests
[i
].at_errno
!= 0)
208 if (!alloc_test_enomem(&alloc_tests
[i
])) {
214 if (ret
== EXIT_SUCCESS
) {
215 (void) printf("All tests passed successfully\n");