Revamp xalloc interface so that it can check for address arithmetic overflow.
authorPaul Eggert <eggert@cs.ucla.edu>
Mon, 13 Oct 2003 06:07:10 +0000 (06:07 +0000)
committerPaul Eggert <eggert@cs.ucla.edu>
Mon, 13 Oct 2003 06:07:10 +0000 (06:07 +0000)
ChangeLog
lib/ChangeLog
lib/xalloc.h
lib/xmalloc.c
lib/xstrdup.c
m4/ChangeLog
m4/xalloc.m4
modules/xalloc

index 1357c21..558b81e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2003-10-12  Paul Eggert  <eggert@twinsun.com>
+
+       * modules/xalloc: Do not depend on 'exit'.  Depend on 'stdbool'.
+       Change maintainer from Bruno Haible to 'all'.
+
 2003-10-10  Simon Josefsson  <jas@extundo.com>
 
        * modules/argp (Depends-on): Add restrict and strcase.
index 2837085..44630d5 100644 (file)
@@ -1,3 +1,18 @@
+2003-10-12  Paul Eggert  <eggert@twinsun.com>
+
+       * lib/xalloc.h (xnmalloc, xzalloc, xnrealloc, xclone): New decls.
+       (XMALLOC, XCALLOC, XREALLOC, XFREE, CCLONE, CLONE): Deprecate,
+       and define in terms of the other primitives.
+       * lib/xmalloc.c: Include stdbool.h; do not include exit.h.
+       (SIZE_MAX): Define if not already defined.
+       (array_size_overflow): New function.
+       (xalloc_die): Abort instead of exiting if 'error' returns.
+       (xnmalloc, xnrealloc, xzalloc, xclone): New functions.
+       (xmalloc, xrealloc): Use them.
+       (xcalloc): Check for address arithmetic overflow.
+       * lib/xstrdup.c (xstrdup): Use xclone, since memcpy should be
+       a bit faster than strcpy.
+
 2003-10-08  Paul Eggert  <eggert@twinsun.com>
 
        Merge getpass from libc, plus a few fixes.
index c6ca117..03c4306 100644 (file)
@@ -48,31 +48,23 @@ extern char const xalloc_msg_memory_exhausted[];
    memory allocation failure.  */
 extern void xalloc_die (void) ATTRIBUTE_NORETURN;
 
-void *xmalloc (size_t n);
+void *xmalloc (size_t s);
+void *xnmalloc (size_t n, size_t s);
+void *xzalloc (size_t s);
 void *xcalloc (size_t n, size_t s);
-void *xrealloc (void *p, size_t n);
+void *xrealloc (void *p, size_t s);
+void *xnrealloc (void *p, size_t n, size_t s);
+void *xclone (void const *p, size_t s);
 char *xstrdup (const char *str);
 
-# define XMALLOC(Type, N_items) xmalloc (sizeof (Type) * (N_items))
-# define XCALLOC(Type, N_items) xcalloc (sizeof (Type), N_items)
-# define XREALLOC(Ptr, Type, N_items) xrealloc (Ptr, sizeof (Type) * (N_items))
-
-/* Declare and alloc memory for VAR of type TYPE. */
-# define NEW(Type, Var)  Type *(Var) = XMALLOC (Type, 1)
-
-/* Free VAR only if non NULL. */
-# define XFREE(Var)    \
-   do {                 \
-      if (Var)          \
-        free (Var);     \
-   } while (0)
-
-/* Return a pointer to a malloc'ed copy of the array SRC of NUM elements. */
-# define CCLONE(Src, Num) \
-  (memcpy (xmalloc (sizeof *(Src) * (Num)), Src, sizeof *(Src) * (Num)))
-
-/* Return a malloc'ed copy of SRC. */
-# define CLONE(Src) CCLONE (Src, 1)
-
+/* These macros are deprecated; they will go away soon, and are retained
+   temporarily only to ease conversion to the functions described above.  */
+# define CCLONE(p, n) xclone (p, (n) * sizeof *(p))
+# define CLONE(p) xclone (p, sizeof *(p))
+# define NEW(type, var) type *var = xmalloc (sizeof (type))
+# define XCALLOC(type, n) xcalloc (n, sizeof (type))
+# define XMALLOC(type, n) xnmalloc (n, sizeof (type))
+# define XREALLOC(p, type, n) xnrealloc (p, n, sizeof (type))
+# define XFREE(p) free (p)
 
 #endif /* !XALLOC_H_ */
index 3adf5dd..f2fddb7 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "xalloc.h"
 
+#include <stdbool.h>
 #include <stdlib.h>
 
 #include "gettext.h"
 #define N_(msgid) msgid
 
 #include "error.h"
-#include "exit.h"
 #include "exitfail.h"
 
-/* The following tests require AC_PREREQ(2.54).  */
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
 
 #ifndef HAVE_MALLOC
 "you must run the autoconf test for a GNU libc compatible malloc"
 /* If non NULL, call this function when memory is exhausted. */
 void (*xalloc_fail_func) (void) = 0;
 
+/* Return true if array of N objects, each of size S, cannot exist due
+   to arithmetic overflow.  S must be nonzero.  */
+
+static inline bool
+array_size_overflow (size_t n, size_t s)
+{
+  return SIZE_MAX / s < n;
+}
+
 /* If XALLOC_FAIL_FUNC is NULL, or does return, display this message
    before exiting when memory is exhausted.  Goes through gettext. */
 char const xalloc_msg_memory_exhausted[] = N_("memory exhausted");
@@ -58,8 +69,20 @@ xalloc_die (void)
   error (exit_failure, 0, "%s", _(xalloc_msg_memory_exhausted));
   /* The `noreturn' cannot be given to error, since it may return if
      its first argument is 0.  To help compilers understand the
-     xalloc_die does terminate, call exit. */
-  exit (EXIT_FAILURE);
+     xalloc_die does terminate, call abort.  */
+  abort ();
+}
+
+/* Allocate an array of N objects, each with S bytes of memory,
+   dynamically, with error checking.  S must be nonzero.  */
+
+inline void *
+xnmalloc (size_t n, size_t s)
+{
+  void *p;
+  if (array_size_overflow (n, s) || ! (p = malloc (n * s)))
+    xalloc_die ();
+  return p;
 }
 
 /* Allocate N bytes of memory dynamically, with error checking.  */
@@ -67,10 +90,16 @@ xalloc_die (void)
 void *
 xmalloc (size_t n)
 {
-  void *p;
+  return xnmalloc (n, 1);
+}
+
+/* Change the size of an allocated block of memory P to an array of N
+   objects each of S bytes, with error checking.  S must be nonzero.  */
 
-  p = malloc (n);
-  if (p == 0)
+inline void *
+xnrealloc (void *p, size_t n, size_t s)
+{
+  if (array_size_overflow (n, s) || ! (p = realloc (p, n * s)))
     xalloc_die ();
   return p;
 }
@@ -81,21 +110,39 @@ xmalloc (size_t n)
 void *
 xrealloc (void *p, size_t n)
 {
-  p = realloc (p, n);
-  if (p == 0)
-    xalloc_die ();
-  return p;
+  return xnrealloc (p, n, 1);
+}
+
+/* Allocate S bytes of zeroed memory dynamically, with error checking.
+   There's no need for xnzalloc (N, S), since it would be equivalent
+   to xcalloc (N, S).  */
+
+void *
+xzalloc (size_t s)
+{
+  return memset (xmalloc (s), 0, s);
 }
 
-/* Allocate memory for N elements of S bytes, with error checking.  */
+/* Allocate zeroed memory for N elements of S bytes, with error
+   checking.  S must be nonzero.  */
 
 void *
 xcalloc (size_t n, size_t s)
 {
   void *p;
-
-  p = calloc (n, s);
-  if (p == 0)
+  /* Test for overflow, since some calloc implementations don't have
+     proper overflow checks.  */
+  if (array_size_overflow (n, s) || ! (p = calloc (n, s)))
     xalloc_die ();
   return p;
 }
+
+/* Clone an object P of size S, with error checking.  There's no need
+   for xnclone (P, N, S), since xclone (P, N * S) works without any
+   need for an arithmetic overflow check.  */
+
+void *
+xclone (void const *p, size_t s)
+{
+  return memcpy (xmalloc (s), p, s);
+}
index 1182c59..58f18be 100644 (file)
@@ -29,5 +29,5 @@
 char *
 xstrdup (const char *string)
 {
-  return strcpy (xmalloc (strlen (string) + 1), string);
+  return xclone (string, strlen (string) + 1);
 }
index 7b1a69b..443297a 100644 (file)
@@ -1,3 +1,7 @@
+2003-10-12  Paul Eggert  <eggert@twinsun.com>
+
+       * xalloc.m4 (gl_PREREQ_XMALLOC): Require AC_C_INLINE.
+
 2003-10-10  Simon Josefsson  <jas@extundo.com>
 
        * argp.m4: Add AC_C_INLINE.
index 9f6e87d..27c0a7b 100644 (file)
@@ -1,4 +1,4 @@
-# xalloc.m4 serial 3
+# xalloc.m4 serial 4
 dnl Copyright (C) 2002-2003 Free Software Foundation, Inc.
 dnl This file is free software, distributed under the terms of the GNU
 dnl General Public License.  As a special exception to the GNU General
@@ -14,8 +14,10 @@ AC_DEFUN([gl_XALLOC],
 
 # Prerequisites of lib/xmalloc.c.
 AC_DEFUN([gl_PREREQ_XMALLOC], [
+  AC_REQUIRE([AC_C_INLINE])
   AC_REQUIRE([jm_FUNC_MALLOC])
   AC_REQUIRE([jm_FUNC_REALLOC])
+  :
 ])
 
 # Prerequisites of lib/xstrdup.c.
index 3a9ea12..46482cc 100644 (file)
@@ -13,7 +13,7 @@ realloc
 error
 gettext
 exitfail
-exit
+stdbool
 
 configure.ac:
 gl_XALLOC
@@ -25,5 +25,5 @@ Include:
 "xalloc.h"
 
 Maintainer:
-Bruno Haible
+all