Paul Eggert wrote:
> +      void *result = realloc (p, 1);
> +      return result ? result : p;

Unfortunately, this patch does not guarantee that errno is set to ENOMEM
upon failure. This was the original raison d'ĂȘtre of the 'realloc-posix'
module.

The first patch of this series restores the errno = ENOMEM behaviour.

Patches 0002 to 0005 add corresponding unit tests, that check errno
in the "normal" case of failure of malloc / realloc / calloc.

Since I see that these tests succeed with MSVC 14, it means that the
Windows UCRT already sets errno = ENOMEM and does not need the Gnulib
workarounds, at least since 2015. Patch 0006 deals with that.


2024-10-31  Bruno Haible  <br...@clisp.org>

        malloc-posix, calloc-posix, realloc-posix: Optimize on MSVC.
        * m4/malloc.m4 (gl_CHECK_MALLOC_POSIX): Assume that malloc sets errno
        upon failure if UCRT is in use.

2024-10-31  Bruno Haible  <br...@clisp.org>

        realloc-posix tests: Enhance tests.
        * tests/test-realloc-posix.c (main): Check errno also after normal
        failing realloc calls.

2024-10-31  Bruno Haible  <br...@clisp.org>

        realloc-posix tests: Fix memory leak.
        * tests/test-realloc-posix.c (main): Don't clobber variable 'p' in
        failing call.

2024-10-31  Bruno Haible  <br...@clisp.org>

        calloc-posix: Add tests.
        * tests/test-calloc-posix.c: New file.
        * modules/calloc-posix-tests: New file.

2024-10-31  Bruno Haible  <br...@clisp.org>

        malloc-posix: Add tests.
        * tests/test-malloc-posix.c: New file.
        * modules/malloc-posix-tests: New file.

2024-10-31  Bruno Haible  <br...@clisp.org>

        realloc-posix: Set errno when failing (regression 2029-10-29).
        * lib/realloc.c (rpl_realloc): When failing, with HAVE_MALLOC_POSIX not
        defined, set errno.

>From 5c3bd571060e13d25aec57973b66a75923554b6f Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Thu, 31 Oct 2024 20:53:17 +0100
Subject: [PATCH 1/6] realloc-posix: Set errno when failing (regression
 2029-10-29).

* lib/realloc.c (rpl_realloc): When failing, with HAVE_MALLOC_POSIX not
defined, set errno.
---
 ChangeLog     |  6 ++++++
 lib/realloc.c | 11 +++++++++--
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 711d08f058..b80e728c2a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2024-10-31  Bruno Haible  <br...@clisp.org>
+
+	realloc-posix: Set errno when failing (regression 2029-10-29).
+	* lib/realloc.c (rpl_realloc): When failing, with HAVE_MALLOC_POSIX not
+	defined, set errno.
+
 2024-10-31  Bruno Haible  <br...@clisp.org>
 
 	crc: Avoid potential conflict with other configure.ac files.
diff --git a/lib/realloc.c b/lib/realloc.c
index b8570f3929..a94e230232 100644
--- a/lib/realloc.c
+++ b/lib/realloc.c
@@ -64,12 +64,19 @@ rpl_realloc (void *p, size_t n)
          Quite possibly future versions of POSIX will change,
          due either to C23 or to (a)'s semantics being messy.
          Act like (b), as that's easy, matches GNU, BSD and V7 malloc,
-         matches BSD and V7 realloc, and is convenient for Gnulib.
+         matches BSD and V7 realloc, and requires no extra code at
+         caller sites.
          Do not fail if P is nonnull, though, as it's natural for callers
          to assume that realloc (P, 0) can fail only when P is null.  */
 
       void *result = realloc (p, 1);
-      return result ? result : p;
+      if (result != NULL)
+        return result;
+#if !HAVE_MALLOC_POSIX
+      if (p == NULL)
+        errno = ENOMEM;
+#endif
+      return p;
     }
 
   ptrdiff_t signed_n;
-- 
2.34.1

>From 7a80523ef2293bed38c108dc3a2d7391f3295e1d Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Thu, 31 Oct 2024 20:54:15 +0100
Subject: [PATCH 2/6] malloc-posix: Add tests.

* tests/test-malloc-posix.c: New file.
* modules/malloc-posix-tests: New file.
---
 ChangeLog                  |  6 +++++
 modules/malloc-posix-tests | 12 +++++++++
 tests/test-malloc-posix.c  | 55 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 73 insertions(+)
 create mode 100644 modules/malloc-posix-tests
 create mode 100644 tests/test-malloc-posix.c

diff --git a/ChangeLog b/ChangeLog
index b80e728c2a..9d20e29f96 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2024-10-31  Bruno Haible  <br...@clisp.org>
+
+	malloc-posix: Add tests.
+	* tests/test-malloc-posix.c: New file.
+	* modules/malloc-posix-tests: New file.
+
 2024-10-31  Bruno Haible  <br...@clisp.org>
 
 	realloc-posix: Set errno when failing (regression 2029-10-29).
diff --git a/modules/malloc-posix-tests b/modules/malloc-posix-tests
new file mode 100644
index 0000000000..17f9b6fb80
--- /dev/null
+++ b/modules/malloc-posix-tests
@@ -0,0 +1,12 @@
+Files:
+tests/test-malloc-posix.c
+tests/macros.h
+
+Depends-on:
+stdint
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-malloc-posix
+check_PROGRAMS += test-malloc-posix
diff --git a/tests/test-malloc-posix.c b/tests/test-malloc-posix.c
new file mode 100644
index 0000000000..7a89b0ab79
--- /dev/null
+++ b/tests/test-malloc-posix.c
@@ -0,0 +1,55 @@
+/* Test of malloc function.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <stdlib.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include "macros.h"
+
+int
+main ()
+{
+  /* Check that malloc sets errno when it fails.
+     Do this only in 64-bit processes, because there are many bi-arch systems
+     nowadays where a 32-bit process can actually allocate 2 GiB of RAM.  */
+  if (sizeof (size_t) >= 8)
+    {
+      void *volatile p;
+
+      errno = 0;
+      p = malloc (SIZE_MAX / 10);
+      ASSERT (p == NULL);
+      ASSERT (errno == ENOMEM);
+
+      errno = 0;
+      p = malloc (SIZE_MAX / 3);
+      ASSERT (p == NULL);
+      ASSERT (errno == ENOMEM);
+
+      return test_exit_status;
+    }
+  else
+    {
+      fputs ("Skipping test: size_t is not 64-bits wide\n", stderr);
+      return 77;
+    }
+}
-- 
2.34.1

>From 2f63858fb19fd49fb1876ba9482fe7444e7c67b2 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Thu, 31 Oct 2024 20:54:36 +0100
Subject: [PATCH 3/6] calloc-posix: Add tests.

* tests/test-calloc-posix.c: New file.
* modules/calloc-posix-tests: New file.
---
 ChangeLog                  |  6 +++++
 modules/calloc-posix-tests | 12 +++++++++
 tests/test-calloc-posix.c  | 55 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 73 insertions(+)
 create mode 100644 modules/calloc-posix-tests
 create mode 100644 tests/test-calloc-posix.c

diff --git a/ChangeLog b/ChangeLog
index 9d20e29f96..c239e373fe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2024-10-31  Bruno Haible  <br...@clisp.org>
+
+	calloc-posix: Add tests.
+	* tests/test-calloc-posix.c: New file.
+	* modules/calloc-posix-tests: New file.
+
 2024-10-31  Bruno Haible  <br...@clisp.org>
 
 	malloc-posix: Add tests.
diff --git a/modules/calloc-posix-tests b/modules/calloc-posix-tests
new file mode 100644
index 0000000000..591258d6cc
--- /dev/null
+++ b/modules/calloc-posix-tests
@@ -0,0 +1,12 @@
+Files:
+tests/test-calloc-posix.c
+tests/macros.h
+
+Depends-on:
+stdint
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-calloc-posix
+check_PROGRAMS += test-calloc-posix
diff --git a/tests/test-calloc-posix.c b/tests/test-calloc-posix.c
new file mode 100644
index 0000000000..d75a255cf5
--- /dev/null
+++ b/tests/test-calloc-posix.c
@@ -0,0 +1,55 @@
+/* Test of calloc function.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <stdlib.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include "macros.h"
+
+int
+main ()
+{
+  /* Check that calloc sets errno when it fails.
+     Do this only in 64-bit processes, because there are many bi-arch systems
+     nowadays where a 32-bit process can actually allocate 2 GiB of RAM.  */
+  if (sizeof (size_t) >= 8)
+    {
+      void *volatile p;
+
+      errno = 0;
+      p = calloc (SIZE_MAX / 20, 2);
+      ASSERT (p == NULL);
+      ASSERT (errno == ENOMEM);
+
+      errno = 0;
+      p = calloc (SIZE_MAX / 6, 2);
+      ASSERT (p == NULL);
+      ASSERT (errno == ENOMEM);
+
+      return test_exit_status;
+    }
+  else
+    {
+      fputs ("Skipping test: size_t is not 64-bits wide\n", stderr);
+      return 77;
+    }
+}
-- 
2.34.1

>From e4424a2c65fee72dd06955f23d68dfd889fb191a Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Thu, 31 Oct 2024 20:54:41 +0100
Subject: [PATCH 4/6] realloc-posix tests: Fix memory leak.

* tests/test-realloc-posix.c (main): Don't clobber variable 'p' in
failing call.
---
 ChangeLog                  | 6 ++++++
 tests/test-realloc-posix.c | 4 ++--
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index c239e373fe..8cc43c210d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2024-10-31  Bruno Haible  <br...@clisp.org>
+
+	realloc-posix tests: Fix memory leak.
+	* tests/test-realloc-posix.c (main): Don't clobber variable 'p' in
+	failing call.
+
 2024-10-31  Bruno Haible  <br...@clisp.org>
 
 	calloc-posix: Add tests.
diff --git a/tests/test-realloc-posix.c b/tests/test-realloc-posix.c
index 79d430b95a..0deb78c699 100644
--- a/tests/test-realloc-posix.c
+++ b/tests/test-realloc-posix.c
@@ -52,8 +52,8 @@ main (int argc, _GL_UNUSED char **argv)
   if (PTRDIFF_MAX < SIZE_MAX)
     {
       size_t one = argc != 12345;
-      p = realloc (p, PTRDIFF_MAX + one);
-      ASSERT (p == NULL);
+      void *volatile r = realloc (p, PTRDIFF_MAX + one);
+      ASSERT (r == NULL);
       /* Avoid a test failure due to glibc bug
          <https://sourceware.org/bugzilla/show_bug.cgi?id=27870>.  */
       if (!getenv ("MALLOC_CHECK_"))
-- 
2.34.1

>From cf3ce55dbb24d9438e4f7ba74646087be1b3288a Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Thu, 31 Oct 2024 20:54:45 +0100
Subject: [PATCH 5/6] realloc-posix tests: Enhance tests.

* tests/test-realloc-posix.c (main): Check errno also after normal
failing realloc calls.
---
 ChangeLog                  |  6 ++++++
 tests/test-realloc-posix.c | 18 ++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 8cc43c210d..79df4886b7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2024-10-31  Bruno Haible  <br...@clisp.org>
+
+	realloc-posix tests: Enhance tests.
+	* tests/test-realloc-posix.c (main): Check errno also after normal
+	failing realloc calls.
+
 2024-10-31  Bruno Haible  <br...@clisp.org>
 
 	realloc-posix tests: Fix memory leak.
diff --git a/tests/test-realloc-posix.c b/tests/test-realloc-posix.c
index 0deb78c699..804d8f24e5 100644
--- a/tests/test-realloc-posix.c
+++ b/tests/test-realloc-posix.c
@@ -60,6 +60,24 @@ main (int argc, _GL_UNUSED char **argv)
         ASSERT (errno == ENOMEM);
     }
 
+  /* Check that realloc sets errno when it fails.
+     Do this only in 64-bit processes, because there are many bi-arch systems
+     nowadays where a 32-bit process can actually allocate 2 GiB of RAM.  */
+  if (sizeof (size_t) >= 8)
+    {
+      void *volatile r;
+
+      errno = 0;
+      r = realloc (p, SIZE_MAX / 10);
+      ASSERT (r == NULL);
+      ASSERT (errno == ENOMEM);
+
+      errno = 0;
+      r = realloc (p, SIZE_MAX / 3);
+      ASSERT (r == NULL);
+      ASSERT (errno == ENOMEM);
+    }
+
   free (p);
   return test_exit_status;
 }
-- 
2.34.1

>From ea0babb11240a9ebeb73133697fccaa6e77b708a Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Thu, 31 Oct 2024 20:54:52 +0100
Subject: [PATCH 6/6] malloc-posix, calloc-posix, realloc-posix: Optimize on
 MSVC.

* m4/malloc.m4 (gl_CHECK_MALLOC_POSIX): Assume that malloc sets errno
upon failure if UCRT is in use.
---
 ChangeLog    |  6 ++++++
 m4/malloc.m4 | 18 ++++++++++++++++--
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 79df4886b7..dc16a1fda9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2024-10-31  Bruno Haible  <br...@clisp.org>
+
+	malloc-posix, calloc-posix, realloc-posix: Optimize on MSVC.
+	* m4/malloc.m4 (gl_CHECK_MALLOC_POSIX): Assume that malloc sets errno
+	upon failure if UCRT is in use.
+
 2024-10-31  Bruno Haible  <br...@clisp.org>
 
 	realloc-posix tests: Enhance tests.
diff --git a/m4/malloc.m4 b/m4/malloc.m4
index df3a492d40..d7684f418c 100644
--- a/m4/malloc.m4
+++ b/m4/malloc.m4
@@ -1,5 +1,5 @@
 # malloc.m4
-# serial 36
+# serial 37
 dnl Copyright (C) 2007, 2009-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,
@@ -146,7 +146,21 @@ AC_DEFUN([gl_CHECK_MALLOC_POSIX]
       dnl 'test-realloc-posix', 'test-calloc-gnu' fail.
       case "$host_os" in
         mingw* | windows*)
-          gl_cv_func_malloc_posix=no ;;
+          dnl Old MSVCRT from 2001 did not set errno=ENOMEM when malloc failed.
+          dnl More recent MSVCRT from 2019 does so.
+          dnl UCRT is the successor of MSVCRT. Assume that UCRT does so as well.
+          AC_COMPILE_IFELSE(
+            [AC_LANG_PROGRAM(
+              [[#include <stdio.h>
+                #ifndef _UCRT
+                msvcrt yuck
+                #endif
+              ]],
+              [[]])
+            ],
+            [gl_cv_func_malloc_posix=yes],
+            [gl_cv_func_malloc_posix=no])
+          ;;
         irix* | solaris*)
           dnl On IRIX 6.5, the three functions return NULL with errno unset
           dnl when the argument is larger than PTRDIFF_MAX.
-- 
2.34.1

Reply via email to