| # malloc.m4 |
| # serial 46 |
| dnl Copyright (C) 2007, 2009-2026 Free Software Foundation, Inc. |
| dnl This file is free software; the Free Software Foundation |
| dnl gives unlimited permission to copy and/or distribute it, |
| dnl with or without modifications, as long as this notice is preserved. |
| dnl This file is offered as-is, without any warranty. |
| |
| m4_version_prereq([2.73], [], [ |
| # Modules that use this macro directly or indirectly should depend |
| # on extensions-aix, so that _LINUX_SOURCE_COMPAT gets defined |
| # before this macro gets invoked. This helps on AIX 7.2 and earlier |
| # if !(__VEC__ || __AIXVEC), and doesn't hurt otherwise. |
| # |
| # This is copied from upstream Autoconf here: |
| # https://git.savannah.gnu.org/cgit/autoconf.git/tree/lib/autoconf/functions.m4?id=1f38316f6af7bf63e5e7dd187ff6456e07ad743e#n971 |
| # _AC_FUNC_MALLOC_IF(IF-WORKS, IF-NOT[, UNKNOWN-ASSUME]) |
| # ------------------------------------------------------ |
| # If 'malloc (0)' returns nonnull, run IF-WORKS, otherwise, IF-NOT. |
| # If it is not known whether it works, assume the shell word UNKNOWN-ASSUME, |
| # which should end in "yes" or in something else (the latter is the default). |
| AC_DEFUN([_AC_FUNC_MALLOC_IF], |
| [ |
| AC_REQUIRE([AC_CANONICAL_HOST])dnl for cross-compiles |
| AC_CACHE_CHECK([whether malloc (0) returns nonnull], |
| [ac_cv_func_malloc_0_nonnull], |
| [AC_RUN_IFELSE( |
| [AC_LANG_PROGRAM( |
| [[#include <stdlib.h> |
| /* Use pmalloc to test; 'volatile' prevents the compiler |
| from optimizing the malloc call away. */ |
| void *(*volatile pmalloc) (size_t) = malloc;]], |
| [[void *p = pmalloc (0); |
| int result = !p; |
| free (p); |
| return result;]])], |
| [ac_cv_func_malloc_0_nonnull=yes], |
| [ac_cv_func_malloc_0_nonnull=no], |
| [AS_CASE([$host_os], |
| [# Guess yes on platforms where we know the result. |
| *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \ |
| | gnu* | *-musl* | midipix* | midnightbsd* \ |
| | hpux* | solaris* | cygwin* | mingw* | windows* | msys*], |
| [ac_cv_func_malloc_0_nonnull="guessing yes"], |
| [# Guess as follows if we don't know. |
| ac_cv_func_malloc_0_nonnull=m4_default([$3], ["guessing no"])])])]) |
| AS_CASE([$ac_cv_func_malloc_0_nonnull], [*yes], [$1], [$2]) |
| ])# _AC_FUNC_MALLOC_IF |
| ]) |
| |
| # gl_FUNC_MALLOC_0_NONNULL |
| # ------------------------ |
| # If 'malloc (0)' returns nonnull define HAVE_MALLOC_0_NONNULL. |
| # Also, set ac_cv_func_malloc_0_nonnull to a string that ends in |
| # "yes", otherwise set it to something else. If unknown whether |
| # malloc (0) works, guess as normal for cross-builds. |
| AC_DEFUN([gl_FUNC_MALLOC_0_NONNULL], |
| [ |
| _AC_FUNC_MALLOC_IF( |
| [AC_DEFINE([HAVE_MALLOC_0_NONNULL], [1], |
| [Define to 1 if malloc (0) returns nonnull.])], |
| [], |
| ["$gl_cross_guess_normal"]) |
| ]) |
| |
| # gl_FUNC_MALLOC_GNU |
| # ------------------ |
| # Test whether malloc (0) is compatible with GNU libc. |
| # Replace malloc if not. |
| # Define HAVE_MALLOC_0_NONNULL if malloc (0) returns nonnull (except upon |
| # out-of-memory). |
| # Define HAVE_MALLOC_PTRDIFF if malloc (N) reliably fails when N exceeds |
| # PTRDIFF_MAX. |
| AC_DEFUN([gl_FUNC_MALLOC_GNU], |
| [ |
| AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) |
| AC_REQUIRE([gl_FUNC_MALLOC_POSIX]) |
| AC_REQUIRE([gl_FUNC_MALLOC_0_NONNULL]) |
| |
| AS_CASE([$ac_cv_func_malloc_0_nonnull], |
| [*yes], |
| [REPLACE_MALLOC_FOR_MALLOC_GNU=$REPLACE_MALLOC_FOR_MALLOC_POSIX], |
| [REPLACE_MALLOC_FOR_MALLOC_GNU=1]) |
| ]) |
| |
| # gl_FUNC_MALLOC_PTRDIFF |
| # ---------------------- |
| # Test whether malloc (N) reliably fails when N exceeds PTRDIFF_MAX. |
| # Define HAVE_MALLOC_PTRDIFF if yes. |
| # Replace malloc if not. |
| AC_DEFUN([gl_FUNC_MALLOC_PTRDIFF], |
| [ |
| AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) |
| AC_REQUIRE([gl_CHECK_MALLOC_PTRDIFF]) |
| AS_IF([test "$gl_cv_malloc_ptrdiff" = yes], |
| [AC_DEFINE([HAVE_MALLOC_PTRDIFF], 1, |
| [Define to 1 if malloc-like functions do not allocate objects |
| larger than PTRDIFF_MAX bytes.])], |
| [REPLACE_MALLOC_FOR_MALLOC_POSIX=1]) |
| ]) |
| |
| # Test whether malloc, calloc refuse to create objects |
| # larger than what can be expressed in ptrdiff_t. |
| # Set gl_cv_func_malloc_gnu. |
| AC_DEFUN([gl_CHECK_MALLOC_PTRDIFF], |
| [ |
| AC_CACHE_CHECK([whether malloc is ptrdiff_t safe], |
| [gl_cv_malloc_ptrdiff], |
| [AC_COMPILE_IFELSE( |
| [AC_LANG_PROGRAM( |
| [[#include <stdint.h> |
| ]], |
| [[/* 64-bit ptrdiff_t is so wide that no practical platform |
| can exceed it. */ |
| #define WIDE_PTRDIFF (PTRDIFF_MAX >> 31 >> 31 != 0) |
| |
| /* On rare machines where size_t fits in ptrdiff_t there |
| is no problem. */ |
| #define NARROW_SIZE (SIZE_MAX <= PTRDIFF_MAX) |
| |
| /* glibc 2.30 and later malloc refuses to exceed ptrdiff_t |
| bounds even on 32-bit platforms. We don't know which |
| non-glibc systems are safe. */ |
| #define KNOWN_SAFE (2 < __GLIBC__ + (30 <= __GLIBC_MINOR__)) |
| |
| #if WIDE_PTRDIFF || NARROW_SIZE || KNOWN_SAFE |
| return 0; |
| #else |
| #error "malloc might not be ptrdiff_t safe" |
| syntax error |
| #endif |
| ]])], |
| [gl_cv_malloc_ptrdiff=yes], |
| [gl_cv_malloc_ptrdiff=no]) |
| ]) |
| ]) |
| |
| # gl_FUNC_MALLOC_POSIX |
| # -------------------- |
| # Test whether 'malloc' is POSIX compliant (sets errno to ENOMEM when it |
| # fails, and doesn't mess up with ptrdiff_t overflow), and replace |
| # malloc if it is not. |
| AC_DEFUN([gl_FUNC_MALLOC_POSIX], |
| [ |
| AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) |
| AC_REQUIRE([gl_FUNC_MALLOC_PTRDIFF]) |
| AC_REQUIRE([gl_CHECK_MALLOC_POSIX]) |
| case "$gl_cv_func_malloc_posix" in |
| *yes) |
| AC_DEFINE([HAVE_MALLOC_POSIX], [1], |
| [Define if malloc and calloc set errno on allocation failure.]) |
| ;; |
| *) |
| REPLACE_MALLOC_FOR_MALLOC_POSIX=1 |
| ;; |
| esac |
| ]) |
| |
| # Test whether malloc, calloc set errno to ENOMEM on failure. |
| # 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, 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, |
| dnl except on those platforms where we have seen 'test-malloc-gnu', |
| dnl 'test-realloc-posix', 'test-calloc-gnu' fail. For platforms |
| dnl where only 'test-realloc-posix', see realloc.m4. |
| case "$host_os" in |
| mingw* | windows*) |
| 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="guessing yes"], |
| [gl_cv_func_malloc_posix="guessing no"]) |
| ;; |
| solaris*) |
| dnl On Solaris 11.3, the three functions might fail with errno set |
| dnl to EAGAIN, not ENOMEM, when the argument is larger than |
| dnl PTRDIFF_MAX. See: |
| dnl https://lists.gnu.org/r/bug-gnulib/2021-05/msg00052.html |
| dnl Here is a test program: |
| |
| m4_divert_push([KILL]) |
| #include <errno.h> |
| #include <stddef.h> |
| #include <stdio.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| |
| #define TEST_CALL(call) \ |
| do { \ |
| void *p = call; \ |
| if (p) \ |
| fprintf (stderr, "returned %p (incorrect success)\n", p); \ |
| else if (errno == ENOMEM) \ |
| perror ("correct failure"); \ |
| else \ |
| perror ("incorrect failure (wrong errno)"); \ |
| free (p); \ |
| } while (0) |
| |
| int |
| main () |
| { |
| size_t big = PTRDIFF_MAX; |
| TEST_CALL (malloc (big + 1)); |
| TEST_CALL (calloc (big / 2 + 1, 2)); |
| TEST_CALL (realloc (NULL, big + 1)); |
| void *small = malloc (1); |
| TEST_CALL (realloc (small, big + 1)); |
| free (small); |
| return 0; |
| } |
| m4_divert_pop([KILL]) |
| gl_cv_func_malloc_posix=no ;; |
| *) |
| gl_cv_func_malloc_posix=yes ;; |
| esac |
| ]) |
| ]) |