Module Name: src Committed By: martin Date: Sat Aug 24 16:24:05 UTC 2024
Modified Files: src/tests/lib/libc/stdlib [netbsd-10]: Makefile t_posix_memalign.c Log Message: Pull up following revision(s) (requested by riastradh in ticket #808): tests/lib/libc/stdlib/t_posix_memalign.c: revision 1.6 tests/lib/libc/stdlib/t_posix_memalign.c: revision 1.7 tests/lib/libc/stdlib/Makefile: revision 1.34 t_posix_memalign: Expand test cases and properties. - Test cartesian product of a sampling of sizes and a sampling of alignments. - Verify all the edge cases I could find in posix_memalign and aligned_alloc, including failure modes. - Test an unreasonably large (but aligned) allocation size. - Use ATF_CHECK_* instead of ATF_REQUIRE_* so all failures will be reported, not just the first one. - While here, build with -fno-builtin-aligned_alloc and with -fno-builtin-posix_memalign to make sure the compiler doesn't try any shenanigans. t_posix_memalign: Fix this to reflect restriction lifted in C17. To generate a diff of this commit: cvs rdiff -u -r1.33 -r1.33.6.1 src/tests/lib/libc/stdlib/Makefile cvs rdiff -u -r1.5 -r1.5.10.1 src/tests/lib/libc/stdlib/t_posix_memalign.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/tests/lib/libc/stdlib/Makefile diff -u src/tests/lib/libc/stdlib/Makefile:1.33 src/tests/lib/libc/stdlib/Makefile:1.33.6.1 --- src/tests/lib/libc/stdlib/Makefile:1.33 Wed Jul 1 07:16:37 2020 +++ src/tests/lib/libc/stdlib/Makefile Sat Aug 24 16:24:04 2024 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.33 2020/07/01 07:16:37 jruoho Exp $ +# $NetBSD: Makefile,v 1.33.6.1 2024/08/24 16:24:04 martin Exp $ .include <bsd.own.mk> @@ -31,6 +31,9 @@ BINDIR= ${TESTSDIR} PROGS+= h_atexit PROGS+= h_getopt h_getopt_long +CFLAGS.t_posix_memalign.c+= -fno-builtin-posix_memalign +CFLAGS.t_posix_memalign.c+= -fno-builtin-aligned_alloc + CPPFLAGS.t_strtod.c+= -D__TEST_FENV LDADD.t_strtod= -lm DPADD.t_strtod+= ${LIBM} Index: src/tests/lib/libc/stdlib/t_posix_memalign.c diff -u src/tests/lib/libc/stdlib/t_posix_memalign.c:1.5 src/tests/lib/libc/stdlib/t_posix_memalign.c:1.5.10.1 --- src/tests/lib/libc/stdlib/t_posix_memalign.c:1.5 Sun Jul 29 01:45:25 2018 +++ src/tests/lib/libc/stdlib/t_posix_memalign.c Sat Aug 24 16:24:04 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: t_posix_memalign.c,v 1.5 2018/07/29 01:45:25 maya Exp $ */ +/* $NetBSD: t_posix_memalign.c,v 1.5.10.1 2024/08/24 16:24:04 martin Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -32,7 +32,7 @@ #include <sys/cdefs.h> __COPYRIGHT("@(#) Copyright (c) 2008\ The NetBSD Foundation, inc. All rights reserved."); -__RCSID("$NetBSD: t_posix_memalign.c,v 1.5 2018/07/29 01:45:25 maya Exp $"); +__RCSID("$NetBSD: t_posix_memalign.c,v 1.5.10.1 2024/08/24 16:24:04 martin Exp $"); #include <atf-c.h> @@ -43,6 +43,8 @@ __RCSID("$NetBSD: t_posix_memalign.c,v 1 #include <stdlib.h> #include <string.h> +#define rounddown(x, n) (((x) / (n)) * (n)) + ATF_TC(posix_memalign_basic); ATF_TC_HEAD(posix_memalign_basic, tc) { @@ -50,32 +52,77 @@ ATF_TC_HEAD(posix_memalign_basic, tc) } ATF_TC_BODY(posix_memalign_basic, tc) { - static const size_t size[] = { - 1, 2, 3, 4, 10, 100, 16384, 32768, 65536 - }; + enum { maxaligntest = 16384 }; static const size_t align[] = { - 512, 1024, 16, 32, 64, 4, 2048, 16, 2 + 0, 1, 2, 3, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, + 8192, maxaligntest, + }; + static const size_t size[] = { + 0, 1, 2, 3, 4, 10, 100, 10000, 16384, 32768, 65536, + rounddown(SIZE_MAX, maxaligntest), }; + size_t i, j; - size_t i; - void *p; + for (i = 0; i < __arraycount(align); i++) { + for (j = 0; j < __arraycount(size); j++) { + void *p = (void *)0x1; + const int ret = posix_memalign(&p, align[i], size[j]); + + if (align[i] == 0 || + (align[i] & (align[i] - 1)) != 0 || + align[i] < sizeof(void *)) { + ATF_CHECK_EQ_MSG(ret, EINVAL, + "posix_memalign(&p, %zu, %zu): %s", + align[i], size[j], strerror(ret)); + continue; + } + if (size[j] == rounddown(SIZE_MAX, maxaligntest) && + ret != EINVAL) { + /* + * If obscenely large alignment isn't + * rejected as EINVAL, we can't + * allocate that much memory anyway. + */ + ATF_CHECK_EQ_MSG(ret, ENOMEM, + "posix_memalign(&p, %zu, %zu): %s", + align[i], size[j], strerror(ret)); + continue; + } + + /* + * Allocation should fail only if the alignment + * isn't supported, in which case it will fail + * with EINVAL. No standard criterion for what + * alignments are supported, so just stop here + * on EINVAL. + */ + if (ret == EINVAL) + continue; + + ATF_CHECK_EQ_MSG(ret, 0, + "posix_memalign(&p, %zu, %zu): %s", + align[i], size[j], strerror(ret)); + ATF_CHECK_EQ_MSG((intptr_t)p & (align[i] - 1), 0, + "posix_memalign(&p, %zu, %zu): %p", + align[i], size[j], p); + + if (size[j] != 0) { + if (p == NULL) { + atf_tc_fail_nonfatal( + "%s:%d:" + "posix_memalign(&p, %zu, %zu):" + " %p", + __FILE__, __LINE__, + align[i], size[j], p); + } + } else { + /* + * No guarantees about whether + * zero-size allocation yields null + * pointer or something else. + */ + } - for (i = 0; i < __arraycount(size); i++) { - int ret; - p = (void*)0x1; - - (void)printf("Checking posix_memalign(&p, %zu, %zu)...\n", - align[i], size[i]); - ret = posix_memalign(&p, align[i], size[i]); - - if ( align[i] < sizeof(void *)) - ATF_REQUIRE_EQ_MSG(ret, EINVAL, - "posix_memalign: %s", strerror(ret)); - else { - ATF_REQUIRE_EQ_MSG(ret, 0, - "posix_memalign: %s", strerror(ret)); - ATF_REQUIRE_EQ_MSG(((intptr_t)p) & (align[i] - 1), 0, - "p = %p", p); free(p); } } @@ -89,40 +136,106 @@ ATF_TC_HEAD(aligned_alloc_basic, tc) } ATF_TC_BODY(aligned_alloc_basic, tc) { - static const size_t size[] = { - 1, 2, 3, 4, 10, 100, 16384, 32768, 65536, 10000, 0 - }; + enum { maxaligntest = 16384 }; static const size_t align[] = { - 512, 1024, 16, 32, 64, 4, 2048, 16, 2, 2048, 0 + 0, 1, 2, 3, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, + 8192, maxaligntest, + }; + static const size_t size[] = { + 0, 1, 2, 3, 4, 10, 100, 10000, 16384, 32768, 65536, + rounddown(SIZE_MAX, maxaligntest), }; + size_t i, j; + + for (i = 0; i < __arraycount(align); i++) { + for (j = 0; j < __arraycount(size); j++) { + void *const p = aligned_alloc(align[i], size[j]); + + /* + * C17, 6.2.8 Alignment of objects, paragraph + * 4, p. 37: + * + * Every valid alignment value shall be a + * nonnegative integral power of two. + * + * C17, 7.22.3.1 The aligned_alloc function, + * paragraph 2, p. 348: + * + * If the value of alignment is not a + * valid alignment supported by the + * implementation the function shall fail + * by returning a null pointer. + * + * Setting errno to EINVAL is a NetBSD + * extension. The last clause appears to rule + * out aligned_alloc(n, 0) for any n, but it's + * not clear. + */ + if (align[i] == 0 || + (align[i] & (align[i] - 1)) != 0) { + if (p != NULL) { + ATF_CHECK_EQ_MSG(p, NULL, + "aligned_alloc(%zu, %zu): %p", + align[i], size[j], p); + continue; + } + ATF_CHECK_EQ_MSG(errno, EINVAL, + "aligned_alloc(%zu, %zu): %s", + align[i], size[j], strerror(errno)); + continue; + } - size_t i; - void *p; + if (size[j] == rounddown(SIZE_MAX, maxaligntest)) { + ATF_CHECK_EQ_MSG(p, NULL, + "aligned_alloc(%zu, %zu): %p, %s", + align[i], size[j], p, strerror(errno)); + switch (errno) { + case EINVAL: + case ENOMEM: + break; + default: + atf_tc_fail_nonfatal( + "%s:%d:" + " aligned_alloc(%zu, %zu): %s", + __FILE__, __LINE__, + align[i], size[j], + strerror(errno)); + break; + } + continue; + } + + /* + * Allocation should fail only if the alignment + * isn't supported, in which case it will fail + * with EINVAL. No standard criterion for what + * alignments are supported, so just stop here + * on EINVAL. + */ + if (p == NULL && errno == EINVAL) + continue; + + ATF_CHECK_EQ_MSG((intptr_t)p & (align[i] - 1), 0, + "aligned_alloc(%zu, %zu): %p", + align[i], size[j], p); + if (size[j] != 0) { + if (p == NULL) { + atf_tc_fail_nonfatal( + "%s:%d:" + " aligned_alloc(&p, %zu, %zu):" + " %p, %s", + __FILE__, __LINE__, + align[i], size[j], p, + strerror(errno)); + } + } else { + /* + * No guarantees about whether + * zero-size allocation yields null + * pointer or something else. + */ + } - for (i = 0; i < __arraycount(size); i++) { - (void)printf("Checking aligned_alloc(%zu, %zu)...\n", - align[i], size[i]); - p = aligned_alloc(align[i], size[i]); - if (p == NULL) { - if (align[i] == 0 || ((align[i] - 1) & align[i]) != 0 || - size[i] % align[i] != 0) { - ATF_REQUIRE_EQ_MSG(errno, EINVAL, - "aligned_alloc: %s", strerror(errno)); - } - else { - ATF_REQUIRE_EQ_MSG(errno, ENOMEM, - "aligned_alloc: %s", strerror(errno)); - } - } - else { - ATF_REQUIRE_EQ_MSG(align[i] == 0, false, - "aligned_alloc: success when alignment was not " - "a power of 2"); - ATF_REQUIRE_EQ_MSG((align[i] - 1) & align[i], 0, - "aligned_alloc: success when alignment was not " - "a power of 2"); - ATF_REQUIRE_EQ_MSG(((intptr_t)p) & (align[i] - 1), 0, - "p = %p", p); free(p); } } @@ -131,8 +244,9 @@ ATF_TC_BODY(aligned_alloc_basic, tc) ATF_TP_ADD_TCS(tp) { + ATF_TP_ADD_TC(tp, posix_memalign_basic); - ATF_TP_ADD_TC(tp, aligned_alloc_basic); - + ATF_TP_ADD_TC(tp, aligned_alloc_basic); + return atf_no_error(); }