From: Paul Eggert Date: Wed, 30 Oct 2024 19:47:02 +0000 (-0700) Subject: posix_memalign: check for GNU behavior with size 0 X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=99bbb61c05e95658cde543b69a2429c6bd33998a;p=gnulib.git posix_memalign: check for GNU behavior with size 0 * lib/posix_memalign.c: Include stdckdint.h. (posix_memalign): Test for overflow more straightforwardly, and more portably to unlikely platforms where SIZE_MAX <= INT_MAX. Treat a zero size as if it were alignment. * m4/posix_memalign.m4 (gl_FUNC_POSIX_MEMALIGN): * tests/test-posix_memalign.c (main): Test zero size too. Use volatile to avoid compiler optimizations. * modules/posix_memalign (Depends-on): Add stdckdint. --- diff --git a/ChangeLog b/ChangeLog index 61296ba779..6ce890f5cc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,15 @@ 2024-10-30 Paul Eggert + posix_memalign: check for GNU behavior with size 0 + * lib/posix_memalign.c: Include stdckdint.h. + (posix_memalign): Test for overflow more straightforwardly, + and more portably to unlikely platforms where SIZE_MAX <= INT_MAX. + Treat a zero size as if it were alignment. + * m4/posix_memalign.m4 (gl_FUNC_POSIX_MEMALIGN): + * tests/test-posix_memalign.c (main): + Test zero size too. Use volatile to avoid compiler optimizations. + * modules/posix_memalign (Depends-on): Add stdckdint. + aligned_alloc: check for GNU behavior with size 0 If someone ever needs to distinguish between GNU and merely POSIX behavior we can split this into two modules, but for now just diff --git a/doc/posix-functions/posix_memalign.texi b/doc/posix-functions/posix_memalign.texi index 6585513548..d802fd6ebe 100644 --- a/doc/posix-functions/posix_memalign.texi +++ b/doc/posix-functions/posix_memalign.texi @@ -14,6 +14,9 @@ it is more portable to older systems that do not support C11. Portability problems fixed by Gnulib: @itemize @item +This function returns a null pointer if the size argument is zero: +AIX 7.3. +@item This function produces misaligned results on some platforms: OpenBSD 6.1. @end itemize diff --git a/lib/posix_memalign.c b/lib/posix_memalign.c index 6a13c56710..6dd713bdb5 100644 --- a/lib/posix_memalign.c +++ b/lib/posix_memalign.c @@ -20,16 +20,17 @@ #include #include +#include int posix_memalign (void **memptr, size_t alignment, size_t size) #undef posix_memalign { - /* Round up SIZE to the next multiple of ALIGNMENT, namely - (SIZE + ALIGNMENT - 1) & ~(ALIGNMENT - 1). */ - size += alignment - 1; - if (size >= alignment - 1) /* no overflow? */ - return posix_memalign (memptr, alignment, size & ~(size_t)(alignment - 1)); - else + /* Round SIZE up to the next multiple of ALIGNMENT. + However, treat a zero size as if it were ALIGNMENT. */ + size_t aligned_size; + if (ckd_add (&aligned_size, size, alignment - !!size)) return ENOMEM; + aligned_size &= -alignment; + return posix_memalign (memptr, alignment, aligned_size); } diff --git a/m4/posix_memalign.m4 b/m4/posix_memalign.m4 index e814ec1560..37c40a528d 100644 --- a/m4/posix_memalign.m4 +++ b/m4/posix_memalign.m4 @@ -1,5 +1,5 @@ # posix_memalign.m4 -# serial 4 +# serial 5 dnl Copyright (C) 2020-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -18,15 +18,22 @@ AC_DEFUN([gl_FUNC_POSIX_MEMALIGN], if test $ac_cv_func_posix_memalign = yes; then dnl On OpenBSD 6.1, posix_memalign (&p, 32, 2406) stores a pointer dnl that is not a multiple of 32. - AC_CACHE_CHECK([whether posix_memalign works for large alignments], + dnl On AIX 7.3, aligned_alloc with a zero size returns NULL. + AC_CACHE_CHECK( + [whether posix_memalign works for large alignment or zero size], [gl_cv_func_posix_memalign_works], [AC_RUN_IFELSE( [AC_LANG_PROGRAM( [[#include - ]], + /* Use pposix_memalign to test; 'volatile' prevents the compiler + from optimizing the malloc call away. */ + int (*volatile pposix_memalign) (void **, size_t, size_t) + = posix_memalign;]], [[void *p; + if (pposix_memalign (&p, 0, sizeof (void *)) != 0) + return 1; if (32 % sizeof (void *) == 0 - && posix_memalign (&p, 32, 2406) == 0 + && pposix_memalign (&p, 32, 2406) == 0 && (unsigned long) p % 32 != 0) return 1; return 0; @@ -36,6 +43,8 @@ AC_DEFUN([gl_FUNC_POSIX_MEMALIGN], [gl_cv_func_posix_memalign_works=no], [case "$host_os" in changequote(,)dnl + # Guess no on AIX. + aix*) gl_cv_func_aligned_alloc_works="guessing no" ;; # Guess no on OpenBSD through 6.1. openbsd[1-5].* | openbsd6.[01] | openbsd6.[01].*) gl_cv_func_posix_memalign_works="guessing no" ;; diff --git a/modules/posix_memalign b/modules/posix_memalign index 0bcdf18414..e50e44ef23 100644 --- a/modules/posix_memalign +++ b/modules/posix_memalign @@ -7,6 +7,7 @@ m4/posix_memalign.m4 Depends-on: extensions +stdckdint [test $REPLACE_POSIX_MEMALIGN = 1] stdlib configure.ac: diff --git a/tests/test-posix_memalign.c b/tests/test-posix_memalign.c index 160e55b177..b61ac4e2a0 100644 --- a/tests/test-posix_memalign.c +++ b/tests/test-posix_memalign.c @@ -33,7 +33,10 @@ main (int argc, char *argv[]) { #if HAVE_POSIX_MEMALIGN static size_t sizes[] = - { 13, 8, 17, 450, 320, 1, 99, 4, 15, 16, 2, 76, 37, 127, 2406, 641, 5781 }; + { + 13, 8, 17, 450, 320, 1, 99, 4, 15, 16, + 2, 76, 37, 127, 2406, 641, 5781, 0 + }; void *aligned2_blocks[SIZEOF (sizes)]; void *aligned4_blocks[SIZEOF (sizes)]; void *aligned8_blocks[SIZEOF (sizes)];