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

Reply via email to