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); 49 ATF_TC_HEAD(posix_memalign_basic, tc) 50 { 51 atf_tc_set_md_var(tc, "descr", "Checks posix_memalign(3)"); 52 } 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); 133 ATF_TC_HEAD(aligned_alloc_basic, tc) 134 { 135 atf_tc_set_md_var(tc, "descr", "Checks aligned_alloc(3)"); 136 } 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 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