On Wed, Oct 30, 2024 at 3:51 PM Paul Eggert <[email protected]> wrote:
>
> * 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.
> ---
> ChangeLog | 10 ++++++++++
> doc/posix-functions/posix_memalign.texi | 3 +++
> lib/posix_memalign.c | 13 +++++++------
> m4/posix_memalign.m4 | 17 +++++++++++++----
> modules/posix_memalign | 1 +
> tests/test-posix_memalign.c | 5 ++++-
> 6 files changed, 38 insertions(+), 11 deletions(-)
>
> diff --git a/ChangeLog b/ChangeLog
> index 61296ba779..6ce890f5cc 100644
> --- a/ChangeLog
> +++ b/ChangeLog
> @@ -1,5 +1,15 @@
> 2024-10-30 Paul Eggert <[email protected]>
>
> + 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 <stdlib.h>
>
> #include <errno.h>
> +#include <stdckdint.h>
>
> 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;
I don't think ENOMEM is a good error for the condition. I guess you
can't return EOVERFLOW or ERANGE? Maybe EINVAL would be better if
that's the case.
> + 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 <stdlib.h>
> - ]],
> + /* 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)];
> --
> 2.43.0
Jeff