Paul Eggert wrote: > I installed the attached patches into Gnulib to make its malloc > replacements ptrdiff_t safe.
When testing m4-1.4.18b on IRIX 6.5, I get a test failure: FAIL: test-reallocarray Let's look in detail: $ ./test-reallocarray ; echo $? 2 There is a call p = realloc (NULL, 2*1073741824); which returns NULL with errno being 0. Since the 'reallocarray' module depends on 'realloc-gnu', and the 'realloc-gnu' and 'realloc-posix' documentation says: Portability problems fixed by Gnulib: @itemize @item Upon failure, the function does not set @code{errno} to @code{ENOMEM} on some platforms: mingw, MSVC 14. @item On some platforms, @code{realloc (p, n)} can succeed even if @code{n} exceeds @code{PTRDIFF_MAX}. Although this behavior is arguably allowed by POSIX it can lead to behavior not defined by POSIX later, so @code{realloc-posix} does not allow going over the limit. @end itemize So, what the documentation implies and what the reallocarray unit test verifies is that realloc (NULL, n) where n > PTRDIFF_MAX 1) returns NULL and 2) sets errno to ENOMEM. On IRIX (in n32 ABI), expectation 1) is fulfilled but 2) is not. Likewise for malloc and calloc. I'm adding two patches - to make sure that the 'realloc-gnu' unit test already fails in this situation, - to fix 'realloc-gnu' on IRIX, so that it actually compiles the replacement code lib/realloc.c. 2021-05-09 Bruno Haible <br...@clisp.org> malloc-gnu, realloc-gnu, calloc-gnu: Ensure errno gets set on IRIX. * m4/malloc.m4 (gl_CHECK_MALLOC_POSIX): Require AC_CANONICAL_HOST. Set gl_cv_func_malloc_posix to 'no' also on IRIX. malloc-gnu, realloc-gnu, calloc-gnu tests: Verify errno is set. * tests/test-malloc-gnu.c: Include <errno.h>. (main): Verify that, when an allocation larger than PTRDIFF_MAX failed, errno is ENOMEM. * tests/test-realloc-gnu.c: Likewise. * tests/test-calloc-gnu.c: Likewise.
>From 3189c490ec29a74e91e1b800d63fb7c9f9b47d2b Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sun, 9 May 2021 18:34:58 +0200 Subject: [PATCH 1/2] malloc-gnu, realloc-gnu, calloc-gnu tests: Verify errno is set. * tests/test-malloc-gnu.c: Include <errno.h>. (main): Verify that, when an allocation larger than PTRDIFF_MAX failed, errno is ENOMEM. * tests/test-realloc-gnu.c: Likewise. * tests/test-calloc-gnu.c: Likewise. --- ChangeLog | 9 +++++++++ tests/test-calloc-gnu.c | 6 ++++-- tests/test-malloc-gnu.c | 4 +++- tests/test-realloc-gnu.c | 4 +++- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index e84bc51..e69f447 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2021-05-09 Bruno Haible <br...@clisp.org> + malloc-gnu, realloc-gnu, calloc-gnu tests: Verify errno is set. + * tests/test-malloc-gnu.c: Include <errno.h>. + (main): Verify that, when an allocation larger than PTRDIFF_MAX failed, + errno is ENOMEM. + * tests/test-realloc-gnu.c: Likewise. + * tests/test-calloc-gnu.c: Likewise. + +2021-05-09 Bruno Haible <br...@clisp.org> + getrandom: Fail with ENOSYS when the system has no randomness source. * lib/getrandom.c (getrandom): When open() fails, set errno to ENOSYS. diff --git a/tests/test-calloc-gnu.c b/tests/test-calloc-gnu.c index b46e788..dbef019 100644 --- a/tests/test-calloc-gnu.c +++ b/tests/test-calloc-gnu.c @@ -17,6 +17,8 @@ #include <config.h> #include <stdlib.h> + +#include <errno.h> #include <stdint.h> /* Return N. @@ -56,10 +58,10 @@ main () for (size_t n = 2; n != 0; n <<= 1) { void *volatile p = calloc (PTRDIFF_MAX / n + 1, identity (n)); - if (p != NULL) + if (!(p == NULL && errno == ENOMEM)) return 2; p = calloc (SIZE_MAX / n + 1, identity (n)); - if (p != NULL) + if (!(p == NULL && errno == ENOMEM)) return 3; } } diff --git a/tests/test-malloc-gnu.c b/tests/test-malloc-gnu.c index d8e7b04..13217c1 100644 --- a/tests/test-malloc-gnu.c +++ b/tests/test-malloc-gnu.c @@ -17,6 +17,8 @@ #include <config.h> #include <stdlib.h> + +#include <errno.h> #include <stdint.h> int @@ -33,7 +35,7 @@ main (int argc, char **argv) { size_t one = argc != 12345; p = malloc (PTRDIFF_MAX + one); - if (p != NULL) + if (!(p == NULL && errno == ENOMEM)) return 1; } diff --git a/tests/test-realloc-gnu.c b/tests/test-realloc-gnu.c index f4c00c0..a366738 100644 --- a/tests/test-realloc-gnu.c +++ b/tests/test-realloc-gnu.c @@ -17,6 +17,8 @@ #include <config.h> #include <stdlib.h> + +#include <errno.h> #include <stdint.h> int @@ -33,7 +35,7 @@ main (int argc, char **argv) { size_t one = argc != 12345; p = realloc (p, PTRDIFF_MAX + one); - if (p != NULL) + if (!(p == NULL && errno == ENOMEM)) return 1; } -- 2.7.4
>From bad7a098679f6bfd8573d14e1722765977436643 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sun, 9 May 2021 18:36:41 +0200 Subject: [PATCH 2/2] malloc-gnu, realloc-gnu, calloc-gnu: Ensure errno gets set on IRIX. * m4/malloc.m4 (gl_CHECK_MALLOC_POSIX): Require AC_CANONICAL_HOST. Set gl_cv_func_malloc_posix to 'no' also on IRIX. --- ChangeLog | 4 ++++ m4/malloc.m4 | 56 +++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index e69f447..b24976a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2021-05-09 Bruno Haible <br...@clisp.org> + malloc-gnu, realloc-gnu, calloc-gnu: Ensure errno gets set on IRIX. + * m4/malloc.m4 (gl_CHECK_MALLOC_POSIX): Require AC_CANONICAL_HOST. Set + gl_cv_func_malloc_posix to 'no' also on IRIX. + malloc-gnu, realloc-gnu, calloc-gnu tests: Verify errno is set. * tests/test-malloc-gnu.c: Include <errno.h>. (main): Verify that, when an allocation larger than PTRDIFF_MAX failed, diff --git a/m4/malloc.m4 b/m4/malloc.m4 index c09006d..de1b2c6 100644 --- a/m4/malloc.m4 +++ b/m4/malloc.m4 @@ -1,4 +1,4 @@ -# malloc.m4 serial 24 +# malloc.m4 serial 25 dnl Copyright (C) 2007, 2009-2021 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -115,20 +115,54 @@ AC_DEFUN([gl_FUNC_MALLOC_POSIX], # Set gl_cv_func_malloc_posix to yes or no accordingly. AC_DEFUN([gl_CHECK_MALLOC_POSIX], [ + AC_REQUIRE([AC_CANONICAL_HOST]) AC_CACHE_CHECK([whether malloc, realloc, calloc set errno on failure], [gl_cv_func_malloc_posix], [ dnl It is too dangerous to try to allocate a large amount of memory: dnl some systems go to their knees when you do that. So assume that - dnl all Unix implementations of the function set errno on failure. - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [[]], - [[#if defined _WIN32 && ! defined __CYGWIN__ - choke me - #endif - ]])], - [gl_cv_func_malloc_posix=yes], - [gl_cv_func_malloc_posix=no]) + dnl all Unix implementations of the function set errno on failure, + dnl except on those platforms where we have seen 'test-malloc-gnu', + dnl 'test-realloc-gnu', 'test-calloc-gnu' fail. + case "$host_os" in + mingw*) + gl_cv_func_malloc_posix=no ;; + irix*) + dnl The three functions return NULL with errno unset when the + dnl argument is larger than PTRDIFF_MAX. Here is a test program: +m4_divert_push([KILL]) +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#define ptrdiff_t long +#ifndef PTRDIFF_MAX +# define PTRDIFF_MAX ((ptrdiff_t) ((1UL << (8 * sizeof (ptrdiff_t) - 1)) - 1)) +#endif + +int main () +{ + void *p; + + fprintf (stderr, "PTRDIFF_MAX = %lu\n", (unsigned long) PTRDIFF_MAX); + + errno = 0; + p = malloc ((unsigned long) PTRDIFF_MAX + 1); + fprintf (stderr, "p=%p errno=%d\n", p, errno); + + errno = 0; + p = calloc (PTRDIFF_MAX / 2 + 1, 2); + fprintf (stderr, "p=%p errno=%d\n", p, errno); + + errno = 0; + p = realloc (NULL, (unsigned long) PTRDIFF_MAX + 1); + fprintf (stderr, "p=%p errno=%d\n", p, errno); + + return 0; +} +m4_divert_pop([KILL]) + gl_cv_func_malloc_posix=no ;; + *) + gl_cv_func_malloc_posix=yes ;; + esac ]) ]) -- 2.7.4