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