1 /*        $NetBSD: t_posix_memalign.c,v 1.8 2023/07/05 12:09:39 riastradh Exp $ */
2 
3 /*-
4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Christos Zoulas.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __COPYRIGHT("@(#) Copyright (c) 2008\
34  The NetBSD Foundation, inc. All rights reserved.");
35 __RCSID("$NetBSD: t_posix_memalign.c,v 1.8 2023/07/05 12:09:39 riastradh Exp $");
36 
37 #include <atf-c.h>
38 
39 #include <errno.h>
40 #include <stdbool.h>
41 #include <stdint.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 
46 #define   rounddown(x, n)     (((x) / (n)) * (n))
47 
48 ATF_TC(posix_memalign_basic);
ATF_TC_HEAD(posix_memalign_basic,tc)49 ATF_TC_HEAD(posix_memalign_basic, tc)
50 {
51           atf_tc_set_md_var(tc, "descr", "Checks posix_memalign(3)");
52 }
ATF_TC_BODY(posix_memalign_basic,tc)53 ATF_TC_BODY(posix_memalign_basic, tc)
54 {
55           enum { maxaligntest = 16384 };
56           static const size_t align[] = {
57                     0, 1, 2, 3, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096,
58                     8192, maxaligntest,
59           };
60           static const size_t size[] = {
61                     0, 1, 2, 3, 4, 10, 100, 10000, 16384, 32768, 65536,
62                     rounddown(SIZE_MAX, maxaligntest),
63           };
64           size_t i, j;
65 
66           for (i = 0; i < __arraycount(align); i++) {
67                     for (j = 0; j < __arraycount(size); j++) {
68                               void *p = (void *)0x1;
69                               const int ret = posix_memalign(&p, align[i], size[j]);
70 
71                               if (align[i] == 0 ||
72                                   (align[i] & (align[i] - 1)) != 0 ||
73                                   align[i] < sizeof(void *)) {
74                                         ATF_CHECK_EQ_MSG(ret, EINVAL,
75                                             "posix_memalign(&p, %zu, %zu): %s",
76                                             align[i], size[j], strerror(ret));
77                                         continue;
78                               }
79                               if (size[j] == rounddown(SIZE_MAX, maxaligntest) &&
80                                   ret != EINVAL) {
81                                         /*
82                                          * If obscenely large alignment isn't
83                                          * rejected as EINVAL, we can't
84                                          * allocate that much memory anyway.
85                                          */
86                                         ATF_CHECK_EQ_MSG(ret, ENOMEM,
87                                             "posix_memalign(&p, %zu, %zu): %s",
88                                             align[i], size[j], strerror(ret));
89                                         continue;
90                               }
91 
92                               /*
93                                * Allocation should fail only if the alignment
94                                * isn't supported, in which case it will fail
95                                * with EINVAL.  No standard criterion for what
96                                * alignments are supported, so just stop here
97                                * on EINVAL.
98                                */
99                               if (ret == EINVAL)
100                                         continue;
101 
102                               ATF_CHECK_EQ_MSG(ret, 0,
103                                   "posix_memalign(&p, %zu, %zu): %s",
104                                   align[i], size[j], strerror(ret));
105                               ATF_CHECK_EQ_MSG((intptr_t)p & (align[i] - 1), 0,
106                                   "posix_memalign(&p, %zu, %zu): %p",
107                                   align[i], size[j], p);
108 
109                               if (size[j] != 0) {
110                                         if (p == NULL) {
111                                                   atf_tc_fail_nonfatal(
112                                                       "%s:%d:"
113                                                       "posix_memalign(&p, %zu, %zu):"
114                                                       " %p",
115                                                       __FILE__, __LINE__,
116                                                       align[i], size[j], p);
117                                         }
118                               } else {
119                                         /*
120                                          * No guarantees about whether
121                                          * zero-size allocation yields null
122                                          * pointer or something else.
123                                          */
124                               }
125 
126                               free(p);
127                     }
128           }
129 }
130 
131 
132 ATF_TC(aligned_alloc_basic);
ATF_TC_HEAD(aligned_alloc_basic,tc)133 ATF_TC_HEAD(aligned_alloc_basic, tc)
134 {
135           atf_tc_set_md_var(tc, "descr", "Checks aligned_alloc(3)");
136 }
ATF_TC_BODY(aligned_alloc_basic,tc)137 ATF_TC_BODY(aligned_alloc_basic, tc)
138 {
139           enum { maxaligntest = 16384 };
140           static const size_t align[] = {
141                     0, 1, 2, 3, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096,
142                     8192, maxaligntest,
143           };
144           static const size_t size[] = {
145                     0, 1, 2, 3, 4, 10, 100, 10000, 16384, 32768, 65536,
146                     rounddown(SIZE_MAX, maxaligntest),
147           };
148           size_t i, j;
149 
150           for (i = 0; i < __arraycount(align); i++) {
151                     for (j = 0; j < __arraycount(size); j++) {
152                               void *const p = aligned_alloc(align[i], size[j]);
153 
154                               /*
155                                * C17, 6.2.8 Alignment of objects, paragraph
156                                * 4, p. 37:
157                                *
158                                *        Every valid alignment value shall be a
159                                *        nonnegative integral power of two.
160                                *
161                                * C17, 7.22.3.1 The aligned_alloc function,
162                                * paragraph 2, p. 348:
163                                *
164                                *        If the value of alignment is not a
165                                *        valid alignment supported by the
166                                *        implementation the function shall fail
167                                *        by returning a null pointer.
168                                *
169                                * Setting errno to EINVAL is a NetBSD
170                                * extension.  The last clause appears to rule
171                                * out aligned_alloc(n, 0) for any n, but it's
172                                * not clear.
173                                */
174                               if (align[i] == 0 ||
175                                   (align[i] & (align[i] - 1)) != 0) {
176                                         if (p != NULL) {
177                                                   ATF_CHECK_EQ_MSG(p, NULL,
178                                                       "aligned_alloc(%zu, %zu): %p",
179                                                       align[i], size[j], p);
180                                                   continue;
181                                         }
182                                         ATF_CHECK_EQ_MSG(errno, EINVAL,
183                                             "aligned_alloc(%zu, %zu): %s",
184                                             align[i], size[j], strerror(errno));
185                                         continue;
186                               }
187 
188                               if (size[j] == rounddown(SIZE_MAX, maxaligntest)) {
189                                         ATF_CHECK_EQ_MSG(p, NULL,
190                                             "aligned_alloc(%zu, %zu): %p, %s",
191                                             align[i], size[j], p, strerror(errno));
192                                         ATF_CHECK_MSG((errno == EINVAL ||
193                                                   errno == ENOMEM),
194                                             "aligned_alloc(%zu, %zu): %s",
195                                             align[i], size[j],
196                                             strerror(errno));
197                                         continue;
198                               }
199 
200                               /*
201                                * Allocation should fail only if the alignment
202                                * isn't supported, in which case it will fail
203                                * with EINVAL.  No standard criterion for what
204                                * alignments are supported, so just stop here
205                                * on EINVAL.
206                                */
207                               if (p == NULL && errno == EINVAL)
208                                         continue;
209 
210                               ATF_CHECK_EQ_MSG((intptr_t)p & (align[i] - 1), 0,
211                                   "aligned_alloc(%zu, %zu): %p",
212                                   align[i], size[j], p);
213                               if (size[j] != 0) {
214                                         ATF_CHECK_MSG(p != NULL,
215                                             "aligned_alloc(&p, %zu, %zu): %p, %s",
216                                             align[i], size[j], p,
217                                             strerror(errno));
218                               } else {
219                                         /*
220                                          * No guarantees about whether
221                                          * zero-size allocation yields null
222                                          * pointer or something else.
223                                          */
224                               }
225 
226                               free(p);
227                     }
228           }
229 }
230 
231 
ATF_TP_ADD_TCS(tp)232 ATF_TP_ADD_TCS(tp)
233 {
234 
235           ATF_TP_ADD_TC(tp, posix_memalign_basic);
236           ATF_TP_ADD_TC(tp, aligned_alloc_basic);
237 
238           return atf_no_error();
239 }
240