Eric Blake wrote: > > I would somewhat like this idea - it is much nicer assuming that malloc > > reliably sets errno to ENOMEM on failure than having to patch all callers > > of malloc to do the same.
Jim Meyering confirmed: > Yes. This is a fundamental goal of gnulib: > If there is some portability problem, don't penalize *all* software and > all systems. Instead, keep the client software clean, and penalize > only the systems that have the problem. The losing system (mingw, > in this case) can endure a little overhead in malloc/realloc wrappers. Hmm, I was hesitating, because adding runtime overhead to _all_ malloc/realloc calls for the (rare) case of failure seems like overkill. But now I stumble on the need to set errno = ENOMEM even in totally unsuspected modules like 'xreadlink', so I come to agree that handling this in all callers is practically infeasible. So I propose to add three modules 'malloc-posix', 'realloc-posix', 'calloc-posix' (using the '-posix' suffix that we already know from 'fnmatch-posix'/'fnmatch-gnu' and 'printf-posix'). Since 'calloc' is a little simpler to handle than 'malloc' and 'realloc', here is first a proposal for 'calloc'. Also, I would propose to rename the modules 'malloc' -> 'malloc-gnu', 'realloc' -> 'realloc-gnu', 'calloc' -> 'calloc-gnu', similar to the naming of the fnmatch-* modules. (Only the modules. The file names and autoconf macro names can be left untouched.) Objections? 2007-09-02 Bruno Haible <[EMAIL PROTECTED]> * modules/calloc-posix: New file. * lib/calloc.c: Include errno.h. (rpl_calloc): Merge the requirements of a glibc-compatible calloc and a POSIX-compatible calloc into a single function. Set ENOMEM when returning NULL. * m4/calloc.m4 (gl_FUNC_CALLOC_POSIX): New macro. * doc/functions/calloc.texi: Mention the calloc-posix module. * lib/stdlib_.h (calloc): New declaration. * m4/stdlib_h.m4 (gl_STDLIB_H_DEFAULTS): Initialize GNULIB_CALLOC_POSIX and HAVE_CALLOC_POSIX. * modules/stdlib (stdlib.h): Substitute also GNULIB_CALLOC_POSIX and HAVE_CALLOC_POSIX. ======================= modules/calloc-posix ============================= Description: calloc() function: allocate memory with indefinite extent. Files: lib/calloc.c m4/calloc.m4 Depends-on: stdlib configure.ac: gl_FUNC_CALLOC_POSIX gl_STDLIB_MODULE_INDICATOR([calloc-posix]) Makefile.am: Include: <stdlib.h> License: LGPL Maintainer: Bruno Haible ========================================================================== *** lib/calloc.c 13 Sep 2006 22:38:14 -0000 1.6 --- lib/calloc.c 2 Sep 2007 23:16:14 -0000 *************** *** 1,6 **** /* calloc() function that is glibc compatible. ! This wrapper function is required at least on Tru64 UNIX 5.1. ! Copyright (C) 2004, 2005, 2006 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 --- 1,6 ---- /* calloc() function that is glibc compatible. ! This wrapper function is required at least on Tru64 UNIX 5.1 and mingw. ! Copyright (C) 2004, 2005, 2006, 2007 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 *************** *** 16,44 **** along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ ! /* written by Jim Meyering */ #include <config.h> ! #undef calloc #include <stdlib.h> /* Allocate and zero-fill an NxS-byte block of memory from the heap. If N or S is zero, allocate and zero-fill a 1-byte block. */ void * rpl_calloc (size_t n, size_t s) { ! size_t bytes; if (n == 0 || s == 0) ! return calloc (1, 1); ! ! /* Defend against buggy calloc implementations that mishandle ! size_t overflow. */ ! bytes = n * s; ! if (bytes / s != n) ! return NULL; ! return calloc (n, s); } --- 16,68 ---- along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ ! /* written by Jim Meyering and Bruno Haible*/ #include <config.h> ! /* Only the AC_FUNC_CALLOC macro defines 'calloc' already in config.h. */ ! #ifdef calloc ! # define NEED_CALLOC_GNU ! # undef calloc ! #endif + /* Specification. */ #include <stdlib.h> + #include <errno.h> + /* Allocate and zero-fill an NxS-byte block of memory from the heap. If N or S is zero, allocate and zero-fill a 1-byte block. */ void * rpl_calloc (size_t n, size_t s) { ! void *result; + #ifdef NEED_CALLOC_GNU if (n == 0 || s == 0) ! { ! n = 1; ! s = 1; ! } ! else ! { ! /* Defend against buggy calloc implementations that mishandle ! size_t overflow. */ ! size_t bytes = n * s; ! if (bytes / s != n) ! { ! errno = ENOMEM; ! return NULL; ! } ! } ! #endif ! ! result = calloc (n, s); ! ! #if !HAVE_CALLOC_POSIX ! if (result == NULL) ! errno = ENOMEM; ! #endif ! return result; } *** m4/calloc.m4 5 Jul 2006 23:35:19 -0000 1.6 --- m4/calloc.m4 2 Sep 2007 23:16:14 -0000 *************** *** 1,6 **** ! # calloc.m4 serial 6 ! # Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. --- 1,6 ---- ! # calloc.m4 serial 7 ! # Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. *************** *** 41,43 **** --- 41,73 ---- AC_DEFINE([calloc], [rpl_calloc], [Define to rpl_calloc if the replacement function should be used.])]) ])# AC_FUNC_CALLOC + + + # gl_FUNC_CALLOC_POSIX + # -------------------- + # Test whether 'calloc' is POSIX compliant (sets errno to ENOMEM when it + # fails), and replace calloc if it is not. + AC_DEFUN([gl_FUNC_CALLOC_POSIX], + [ + AC_CACHE_CHECK([whether calloc is POSIX compliant], + [gl_cv_func_calloc_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 are POSIX compliant. + AC_TRY_COMPILE([], + [#if !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__) + choke me + #endif + ], [gl_cv_func_calloc_posix=yes], [gl_cv_func_calloc_posix=no]) + ]) + if test $gl_cv_func_calloc_posix = yes; then + HAVE_CALLOC_POSIX=1 + AC_DEFINE([HAVE_CALLOC_POSIX], 1, + [Define if the 'calloc' function is POSIX compliant.]) + else + AC_LIBOBJ([calloc]) + HAVE_CALLOC_POSIX=0 + fi + AC_SUBST([HAVE_CALLOC_POSIX]) + ]) *** doc/functions/calloc.texi 1 May 2007 15:11:37 -0000 1.1 --- doc/functions/calloc.texi 2 Sep 2007 23:16:14 -0000 *************** *** 4,13 **** POSIX specification: @url{http://www.opengroup.org/susv3xsh/calloc.html} ! Gnulib module: --- Portability problems fixed by Gnulib: @itemize @end itemize Portability problems not fixed by Gnulib: --- 4,17 ---- POSIX specification: @url{http://www.opengroup.org/susv3xsh/calloc.html} ! Gnulib module: calloc-posix Portability problems fixed by Gnulib: @itemize + @item + Upon failure, the function does not set @code{errno} to @code{ENOMEM} on + some platforms: + mingw. @end itemize Portability problems not fixed by Gnulib: *** lib/stdlib_.h 21 Jun 2007 04:39:10 -0000 1.13 --- lib/stdlib_.h 2 Sep 2007 23:16:14 -0000 *************** *** 55,60 **** --- 55,75 ---- #endif + #if @GNULIB_CALLOC_POSIX@ + # if [EMAIL PROTECTED]@ + # undef calloc + # define calloc rpl_calloc + extern void * calloc (size_t nmemb, size_t size); + # endif + #elif defined GNULIB_POSIXCHECK + # undef calloc + # define calloc(n,s) \ + (GL_LINK_WARNING ("calloc is not POSIX compliant everywhere - " \ + "use gnulib module calloc-posix for portability"), \ + calloc (n, s)) + #endif + + #if @GNULIB_GETSUBOPT@ /* Assuming *OPTIONP is a comma separated list of elements of the form "token" or "token=value", getsubopt parses the first of these elements. *** m4/stdlib_h.m4 21 Jun 2007 04:39:10 -0000 1.3 --- m4/stdlib_h.m4 2 Sep 2007 23:16:14 -0000 *************** *** 1,4 **** ! # stdlib_h.m4 serial 2 dnl Copyright (C) 2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, --- 1,4 ---- ! # stdlib_h.m4 serial 3 dnl Copyright (C) 2007 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, *************** *** 19,29 **** AC_DEFUN([gl_STDLIB_H_DEFAULTS], [ ! GNULIB_GETSUBOPT=0; AC_SUBST([GNULIB_GETSUBOPT]) ! GNULIB_MKDTEMP=0; AC_SUBST([GNULIB_MKDTEMP]) ! GNULIB_MKSTEMP=0; AC_SUBST([GNULIB_MKSTEMP]) dnl Assume proper GNU behavior unless another module says otherwise. ! HAVE_GETSUBOPT=1; AC_SUBST([HAVE_GETSUBOPT]) ! HAVE_MKDTEMP=1; AC_SUBST([HAVE_MKDTEMP]) ! REPLACE_MKSTEMP=0; AC_SUBST([REPLACE_MKSTEMP]) ]) --- 19,31 ---- AC_DEFUN([gl_STDLIB_H_DEFAULTS], [ ! GNULIB_CALLOC_POSIX=0; AC_SUBST([GNULIB_CALLOC_POSIX]) ! GNULIB_GETSUBOPT=0; AC_SUBST([GNULIB_GETSUBOPT]) ! GNULIB_MKDTEMP=0; AC_SUBST([GNULIB_MKDTEMP]) ! GNULIB_MKSTEMP=0; AC_SUBST([GNULIB_MKSTEMP]) dnl Assume proper GNU behavior unless another module says otherwise. ! HAVE_CALLOC_POSIX=1; AC_SUBST([HAVE_CALLOC_POSIX]) ! HAVE_GETSUBOPT=1; AC_SUBST([HAVE_GETSUBOPT]) ! HAVE_MKDTEMP=1; AC_SUBST([HAVE_MKDTEMP]) ! REPLACE_MKSTEMP=0; AC_SUBST([REPLACE_MKSTEMP]) ]) *** modules/stdlib 21 Jun 2007 04:39:11 -0000 1.5 --- modules/stdlib 2 Sep 2007 23:16:14 -0000 *************** *** 23,31 **** --- 23,33 ---- { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \ sed -e 's/@''INCLUDE_NEXT''@/$(INCLUDE_NEXT)/g' \ -e 's|@''NEXT_STDLIB_H''@|$(NEXT_STDLIB_H)|g' \ + -e 's|@''GNULIB_CALLOC_POSIX''@|$(GNULIB_CALLOC_POSIX)|g' \ -e 's|@''GNULIB_GETSUBOPT''@|$(GNULIB_GETSUBOPT)|g' \ -e 's|@''GNULIB_MKDTEMP''@|$(GNULIB_MKDTEMP)|g' \ -e 's|@''GNULIB_MKSTEMP''@|$(GNULIB_MKSTEMP)|g' \ + -e 's|@''HAVE_CALLOC_POSIX''@|$(HAVE_CALLOC_POSIX)|g' \ -e 's|@''HAVE_GETSUBOPT''@|$(HAVE_GETSUBOPT)|g' \ -e 's|@''HAVE_MKDTEMP''@|$(HAVE_MKDTEMP)|g' \ -e 's|@''REPLACE_MKSTEMP''@|$(REPLACE_MKSTEMP)|g' \