t_posix_memalign.c revision 1.7
1/*	$NetBSD: t_posix_memalign.c,v 1.7 2023/07/05 11:43:05 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.7 2023/07/05 11:43:05 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
48ATF_TC(posix_memalign_basic);
49ATF_TC_HEAD(posix_memalign_basic, tc)
50{
51	atf_tc_set_md_var(tc, "descr", "Checks posix_memalign(3)");
52}
53ATF_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
132ATF_TC(aligned_alloc_basic);
133ATF_TC_HEAD(aligned_alloc_basic, tc)
134{
135	atf_tc_set_md_var(tc, "descr", "Checks aligned_alloc(3)");
136}
137ATF_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				switch (errno) {
193				case EINVAL:
194				case ENOMEM:
195					break;
196				default:
197					atf_tc_fail_nonfatal(
198					    "%s:%d:"
199					    " aligned_alloc(%zu, %zu): %s",
200					    __FILE__, __LINE__,
201					    align[i], size[j],
202					    strerror(errno));
203					break;
204				}
205				continue;
206			}
207
208			/*
209			 * Allocation should fail only if the alignment
210			 * isn't supported, in which case it will fail
211			 * with EINVAL.  No standard criterion for what
212			 * alignments are supported, so just stop here
213			 * on EINVAL.
214			 */
215			if (p == NULL && errno == EINVAL)
216				continue;
217
218			ATF_CHECK_EQ_MSG((intptr_t)p & (align[i] - 1), 0,
219			    "aligned_alloc(%zu, %zu): %p",
220			    align[i], size[j], p);
221			if (size[j] != 0) {
222				if (p == NULL) {
223					atf_tc_fail_nonfatal(
224					    "%s:%d:"
225					    " aligned_alloc(&p, %zu, %zu):"
226					    " %p, %s",
227					    __FILE__, __LINE__,
228					    align[i], size[j], p,
229					    strerror(errno));
230				}
231			} else {
232				/*
233				 * No guarantees about whether
234				 * zero-size allocation yields null
235				 * pointer or something else.
236				 */
237			}
238
239			free(p);
240		}
241	}
242}
243
244
245ATF_TP_ADD_TCS(tp)
246{
247
248	ATF_TP_ADD_TC(tp, posix_memalign_basic);
249	ATF_TP_ADD_TC(tp, aligned_alloc_basic);
250
251	return atf_no_error();
252}
253