* lib/free.c (rpl_free): Preserve errno. Check for null only if CANNOT_FREE_NULL is defined, as an optimization for POSIX 2008 platforms that do not preserve errno. * m4/free.m4 (gl_FUNC_FREE): Check whether free preserves errno. Also, define CANNOT_FREE_NULL if free cannot free NULL. * modules/free (configure.ac): Also replace 'free' if it does not preserve errno. --- ChangeLog | 9 +++++++++ lib/free.c | 12 ++++++++++-- m4/free.m4 | 35 ++++++++++++++++++++++++++++++++++- modules/free | 12 ++++++------ 4 files changed, 59 insertions(+), 9 deletions(-)
diff --git a/ChangeLog b/ChangeLog index 445e2c074..e97d82aa6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2020-12-17 Paul Eggert <egg...@cs.ucla.edu> + free: preserve errno + * lib/free.c (rpl_free): Preserve errno. Check for null only if + CANNOT_FREE_NULL is defined, as an optimization for POSIX 2008 + platforms that do not preserve errno. + * m4/free.m4 (gl_FUNC_FREE): Check whether free preserves errno. + Also, define CANNOT_FREE_NULL if free cannot free NULL. + * modules/free (configure.ac): Also replace 'free' if + it does not preserve errno. + idx: simplify IDX_MAX, remove IDX_WIDTH * lib/idx.h (IDX_MAX): Simplify by removing obsolete reference to UNSIGNED_IDX_T. diff --git a/lib/free.c b/lib/free.c index 50a300ffa..843ce4816 100644 --- a/lib/free.c +++ b/lib/free.c @@ -22,9 +22,17 @@ #include <stdlib.h> +#include <errno.h> + void rpl_free (void *p) { - if (p) - free (p); +#ifdef CANNOT_FREE_NULL + if (!p) + return; +#endif + + int err = errno; + free (p); + errno = err; } diff --git a/m4/free.m4 b/m4/free.m4 index a62214cd1..62daa8ecc 100644 --- a/m4/free.m4 +++ b/m4/free.m4 @@ -35,10 +35,43 @@ AC_DEFUN([gl_FUNC_FREE], esac ]) + dnl In the next release of POSIX, free must preserve errno. + dnl https://www.austingroupbugs.net/view.php?id=385 + dnl https://sourceware.org/bugzilla/show_bug.cgi?id=17924 + dnl For now, assume implementations other than glibc do not preserve errno + dnl unless they set _POSIX_VERSION to the next release number, + dnl whatever that happens to be. + AC_CACHE_CHECK([whether free is known to preserve errno], + [gl_cv_func_free_preserves_errno], + [case $host_os in + *-gnu* | gnu*) + gl_cv_func_free_preserves_errno=yes;; + *) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include <unistd.h> + ]], + [[#if _POSIX_VERSION <= 200809 + #error "'free' is not known to preserve errno" + #endif + ]])], + [gl_cv_func_free_preserves_errno=yes], + [gl_cv_func_free_preserves_errno=no]);; + esac + ]) + if test $gl_cv_func_free = no; then + AC_DEFINE([CANNOT_FREE_NULL], [1], + [Define to 1 if free (NULL) does not work.]) + fi + + case $gl_cv_func_free,$gl_cv_func_free_preserves_errno in + *yes,*yes) ;; + *) AC_DEFINE([free], [rpl_free], [Define to rpl_free if the replacement function should be used.]) - fi + ;; + esac ]) # Prerequisites of lib/free.c. diff --git a/modules/free b/modules/free index ec91f8889..ea2509821 100644 --- a/modules/free +++ b/modules/free @@ -1,8 +1,5 @@ Description: -Work around incompatibility on older systems where free (NULL) fails. - -Notice: -This module is obsolete. +Work around systems where free sets errno or free (NULL) fails. Files: lib/free.c @@ -12,10 +9,13 @@ Depends-on: configure.ac: gl_FUNC_FREE -if test $gl_cv_func_free = no; then +case $gl_cv_func_free,$gl_cv_func_free_errno in + *yes,*yes) ;; + *) AC_LIBOBJ([free]) gl_PREREQ_FREE -fi + ;; +esac Makefile.am: -- 2.27.0