* lib/xalloc.h (x2nrealloc): Fix an unlikely bug in the overflow
[gnulib.git] / lib / xalloc.h
index 6881ea6..0c6d8dc 100644 (file)
@@ -1,7 +1,7 @@
 /* xalloc.h -- malloc with out-of-memory checking
 
    Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2003, 2004, 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
@@ -46,13 +46,10 @@ extern "C" {
 extern void xalloc_die (void) ATTRIBUTE_NORETURN;
 
 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 s);
-void *xnrealloc (void *p, size_t n, size_t s);
 void *x2realloc (void *p, size_t *pn);
-void *x2nrealloc (void *p, size_t *pn, size_t s);
 void *xmemdup (void const *p, size_t s);
 char *xstrdup (char const *str);
 
@@ -71,59 +68,166 @@ char *xstrdup (char const *str);
 # define xalloc_oversized(n, s) \
     ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n))
 
+
 /* In the following macros, T must be an elementary or structure/union or
    typedef'ed type, or a pointer to such a type.  To apply one of the
    following macros to a function pointer or array type, you need to typedef
    it first and use the typedef name.  */
 
 /* Allocate an object of type T dynamically, with error checking.  */
-/* extern T *XMALLOC (typename T); */
-#define XMALLOC(T) \
-  ((T *) xmalloc (sizeof (T)))
-
-/* Allocate memory for NMEMB elements of type T, with error checking.  */
-/* extern T *XNMALLOC (size_t nmemb, typename T); */
-#if HAVE_INLINE
-/* xnmalloc performs a division and multiplication by sizeof (T).  Arrange to
-   perform the division at compile-time and the multiplication with a factor
-   known at compile-time.  */
-# define XNMALLOC(N,T) \
-   ((T *) (sizeof (T) == 1 \
-          ? xmalloc (N) \
-          : xnboundedmalloc(N, (size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / sizeof (T), sizeof (T))))
-static inline void *
-xnboundedmalloc (size_t n, size_t bound, size_t s)
+/* extern t *XMALLOC (typename t); */
+# define XMALLOC(t) ((t *) xmalloc (sizeof (t)))
+
+/* Allocate memory for N elements of type T, with error checking.  */
+/* extern t *XNMALLOC (size_t n, typename t); */
+# define XNMALLOC(n, t) \
+    ((t *) (sizeof (t) == 1 ? xmalloc (n) : xnmalloc (n, sizeof (t))))
+
+/* Allocate an object of type T dynamically, with error checking,
+   and zero it.  */
+/* extern t *XZALLOC (typename t); */
+# define XZALLOC(t) ((t *) xzalloc (sizeof (t)))
+
+/* Allocate memory for N elements of type T, with error checking,
+   and zero it.  */
+/* extern t *XCALLOC (size_t n, typename t); */
+# define XCALLOC(n, t) \
+    ((t *) (sizeof (t) == 1 ? xzalloc (n) : xcalloc (n, sizeof (t))))
+
+
+# if HAVE_INLINE
+#  define static_inline static inline
+# else
+   void *xnmalloc (size_t n, size_t s);
+   void *xnrealloc (void *p, size_t n, size_t s);
+   void *x2nrealloc (void *p, size_t *pn, size_t s);
+   char *xcharalloc (size_t n);
+# endif
+
+# ifdef static_inline
+
+/* Allocate an array of N objects, each with S bytes of memory,
+   dynamically, with error checking.  S must be nonzero.  */
+
+static_inline void *
+xnmalloc (size_t n, size_t s)
 {
-  if (n > bound)
+  if (xalloc_oversized (n, s))
     xalloc_die ();
   return xmalloc (n * s);
 }
-#else
-# define XNMALLOC(N,T) \
-   ((T *) (sizeof (T) == 1 ? xmalloc (N) : xnmalloc (N, sizeof (T))))
-#endif
 
-/* Allocate an object of type T dynamically, with error checking,
-   and zero it.  */
-/* extern T *XZALLOC (typename T); */
-#define XZALLOC(T) \
-  ((T *) xzalloc (sizeof (T)))
+/* 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.  */
 
-/* Allocate memory for NMEMB elements of type T, with error checking,
-   and zero it.  */
-/* extern T *XCALLOC (size_t nmemb, typename T); */
-#define XCALLOC(N,T) \
-  ((T *) xcalloc (N, sizeof (T)))
+static_inline void *
+xnrealloc (void *p, size_t n, size_t s)
+{
+  if (xalloc_oversized (n, s))
+    xalloc_die ();
+  return xrealloc (p, n * s);
+}
+
+/* If P is null, allocate a block of at least *PN such objects;
+   otherwise, reallocate P so that it contains more than *PN objects
+   each of S bytes.  *PN must be nonzero unless P is null, and S must
+   be nonzero.  Set *PN to the new number of objects, and return the
+   pointer to the new block.  *PN is never set to zero, and the
+   returned pointer is never null.
+
+   Repeated reallocations are guaranteed to make progress, either by
+   allocating an initial block with a nonzero size, or by allocating a
+   larger block.
+
+   In the following implementation, nonzero sizes are increased by a
+   factor of approximately 1.5 so that repeated reallocations have
+   O(N) overall cost rather than O(N**2) cost, but the
+   specification for this function does not guarantee that rate.
+
+   Here is an example of use:
+
+     int *p = NULL;
+     size_t used = 0;
+     size_t allocated = 0;
+
+     void
+     append_int (int value)
+       {
+        if (used == allocated)
+          p = x2nrealloc (p, &allocated, sizeof *p);
+        p[used++] = value;
+       }
+
+   This causes x2nrealloc to allocate a block of some nonzero size the
+   first time it is called.
+
+   To have finer-grained control over the initial size, set *PN to a
+   nonzero value before calling this function with P == NULL.  For
+   example:
+
+     int *p = NULL;
+     size_t used = 0;
+     size_t allocated = 0;
+     size_t allocated1 = 1000;
+
+     void
+     append_int (int value)
+       {
+        if (used == allocated)
+          {
+            p = x2nrealloc (p, &allocated1, sizeof *p);
+            allocated = allocated1;
+          }
+        p[used++] = value;
+       }
+
+   */
+
+static_inline void *
+x2nrealloc (void *p, size_t *pn, size_t s)
+{
+  size_t n = *pn;
+
+  if (! p)
+    {
+      if (! n)
+       {
+         /* The approximate size to use for initial small allocation
+            requests, when the invoking code specifies an old size of
+            zero.  64 bytes is the largest "small" request for the
+            GNU C library malloc.  */
+         enum { DEFAULT_MXFAST = 64 };
+
+         n = DEFAULT_MXFAST / s;
+         n += !n;
+       }
+    }
+  else
+    {
+      /* Set N = ceil (1.5 * N) so that progress is made if N == 1.
+        Check for overflow, so that N * S stays in size_t range.
+        The check is slightly conservative, but an exact check isn't
+        worth the trouble.  */
+      if ((size_t) -1 / 3 * 2 / s <= n)
+       xalloc_die ();
+      n += (n + 1) / 2;
+    }
+
+  *pn = n;
+  return xrealloc (p, n * s);
+}
 
 /* Return a pointer to a new buffer of N bytes.  This is like xmalloc,
-   except it returns char *.
-   xcharalloc (N) is equivalent to XNMALLOC (N, char).  */
-static inline char *
+   except it returns char *.  */
+
+static_inline char *
 xcharalloc (size_t n)
 {
-  return (char *) xmalloc (n);
+  return XNMALLOC (n, char);
 }
 
+# endif
+
 # ifdef __cplusplus
 }