Blame lib/xalloc.h

Packit 33f14e
/* xalloc.h -- malloc with out-of-memory checking
Packit 33f14e
Packit 33f14e
   Copyright (C) 1990-2000, 2003-2004, 2006-2017 Free Software Foundation, Inc.
Packit 33f14e
Packit 33f14e
   This program is free software: you can redistribute it and/or modify
Packit 33f14e
   it under the terms of the GNU General Public License as published by
Packit 33f14e
   the Free Software Foundation; either version 3 of the License, or
Packit 33f14e
   (at your option) any later version.
Packit 33f14e
Packit 33f14e
   This program is distributed in the hope that it will be useful,
Packit 33f14e
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 33f14e
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 33f14e
   GNU General Public License for more details.
Packit 33f14e
Packit 33f14e
   You should have received a copy of the GNU General Public License
Packit 33f14e
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit 33f14e
Packit 33f14e
#ifndef XALLOC_H_
Packit 33f14e
#define XALLOC_H_
Packit 33f14e
Packit 33f14e
#include <stddef.h>
Packit 33f14e
#include <stdint.h>
Packit 33f14e
Packit 33f14e
#include "xalloc-oversized.h"
Packit 33f14e
Packit 33f14e
#ifndef _GL_INLINE_HEADER_BEGIN
Packit 33f14e
 #error "Please include config.h first."
Packit 33f14e
#endif
Packit 33f14e
_GL_INLINE_HEADER_BEGIN
Packit 33f14e
#ifndef XALLOC_INLINE
Packit 33f14e
# define XALLOC_INLINE _GL_INLINE
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
#ifdef __cplusplus
Packit 33f14e
extern "C" {
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
Packit 33f14e
#if __GNUC__ >= 3
Packit 33f14e
# define _GL_ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
Packit 33f14e
#else
Packit 33f14e
# define _GL_ATTRIBUTE_MALLOC
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
#if ! defined __clang__ && \
Packit 33f14e
    (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
Packit 33f14e
# define _GL_ATTRIBUTE_ALLOC_SIZE(args) __attribute__ ((__alloc_size__ args))
Packit 33f14e
#else
Packit 33f14e
# define _GL_ATTRIBUTE_ALLOC_SIZE(args)
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
/* This function is always triggered when memory is exhausted.
Packit 33f14e
   It must be defined by the application, either explicitly
Packit 33f14e
   or by using gnulib's xalloc-die module.  This is the
Packit 33f14e
   function to call when one wants the program to die because of a
Packit 33f14e
   memory allocation failure.  */
Packit 33f14e
extern _Noreturn void xalloc_die (void);
Packit 33f14e
Packit 33f14e
void *xmalloc (size_t s)
Packit 33f14e
      _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1));
Packit 33f14e
void *xzalloc (size_t s)
Packit 33f14e
      _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1));
Packit 33f14e
void *xcalloc (size_t n, size_t s)
Packit 33f14e
      _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1, 2));
Packit 33f14e
void *xrealloc (void *p, size_t s)
Packit 33f14e
      _GL_ATTRIBUTE_ALLOC_SIZE ((2));
Packit 33f14e
void *x2realloc (void *p, size_t *pn);
Packit 33f14e
void *xmemdup (void const *p, size_t s)
Packit 33f14e
      _GL_ATTRIBUTE_ALLOC_SIZE ((2));
Packit 33f14e
char *xstrdup (char const *str)
Packit 33f14e
      _GL_ATTRIBUTE_MALLOC;
Packit 33f14e
Packit 33f14e
/* In the following macros, T must be an elementary or structure/union or
Packit 33f14e
   typedef'ed type, or a pointer to such a type.  To apply one of the
Packit 33f14e
   following macros to a function pointer or array type, you need to typedef
Packit 33f14e
   it first and use the typedef name.  */
Packit 33f14e
Packit 33f14e
/* Allocate an object of type T dynamically, with error checking.  */
Packit 33f14e
/* extern t *XMALLOC (typename t); */
Packit 33f14e
#define XMALLOC(t) ((t *) xmalloc (sizeof (t)))
Packit 33f14e
Packit 33f14e
/* Allocate memory for N elements of type T, with error checking.  */
Packit 33f14e
/* extern t *XNMALLOC (size_t n, typename t); */
Packit 33f14e
#define XNMALLOC(n, t) \
Packit 33f14e
   ((t *) (sizeof (t) == 1 ? xmalloc (n) : xnmalloc (n, sizeof (t))))
Packit 33f14e
Packit 33f14e
/* Allocate an object of type T dynamically, with error checking,
Packit 33f14e
   and zero it.  */
Packit 33f14e
/* extern t *XZALLOC (typename t); */
Packit 33f14e
#define XZALLOC(t) ((t *) xzalloc (sizeof (t)))
Packit 33f14e
Packit 33f14e
/* Allocate memory for N elements of type T, with error checking,
Packit 33f14e
   and zero it.  */
Packit 33f14e
/* extern t *XCALLOC (size_t n, typename t); */
Packit 33f14e
#define XCALLOC(n, t) \
Packit 33f14e
   ((t *) (sizeof (t) == 1 ? xzalloc (n) : xcalloc (n, sizeof (t))))
Packit 33f14e
Packit 33f14e
Packit 33f14e
/* Allocate an array of N objects, each with S bytes of memory,
Packit 33f14e
   dynamically, with error checking.  S must be nonzero.  */
Packit 33f14e
Packit 33f14e
XALLOC_INLINE void *xnmalloc (size_t n, size_t s)
Packit 33f14e
                    _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1, 2));
Packit 33f14e
XALLOC_INLINE void *
Packit 33f14e
xnmalloc (size_t n, size_t s)
Packit 33f14e
{
Packit 33f14e
  if (xalloc_oversized (n, s))
Packit 33f14e
    xalloc_die ();
Packit 33f14e
  return xmalloc (n * s);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Change the size of an allocated block of memory P to an array of N
Packit 33f14e
   objects each of S bytes, with error checking.  S must be nonzero.  */
Packit 33f14e
Packit 33f14e
XALLOC_INLINE void *xnrealloc (void *p, size_t n, size_t s)
Packit 33f14e
                    _GL_ATTRIBUTE_ALLOC_SIZE ((2, 3));
Packit 33f14e
XALLOC_INLINE void *
Packit 33f14e
xnrealloc (void *p, size_t n, size_t s)
Packit 33f14e
{
Packit 33f14e
  if (xalloc_oversized (n, s))
Packit 33f14e
    xalloc_die ();
Packit 33f14e
  return xrealloc (p, n * s);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* If P is null, allocate a block of at least *PN such objects;
Packit 33f14e
   otherwise, reallocate P so that it contains more than *PN objects
Packit 33f14e
   each of S bytes.  S must be nonzero.  Set *PN to the new number of
Packit 33f14e
   objects, and return the pointer to the new block.  *PN is never set
Packit 33f14e
   to zero, and the returned pointer is never null.
Packit 33f14e
Packit 33f14e
   Repeated reallocations are guaranteed to make progress, either by
Packit 33f14e
   allocating an initial block with a nonzero size, or by allocating a
Packit 33f14e
   larger block.
Packit 33f14e
Packit 33f14e
   In the following implementation, nonzero sizes are increased by a
Packit 33f14e
   factor of approximately 1.5 so that repeated reallocations have
Packit 33f14e
   O(N) overall cost rather than O(N**2) cost, but the
Packit 33f14e
   specification for this function does not guarantee that rate.
Packit 33f14e
Packit 33f14e
   Here is an example of use:
Packit 33f14e
Packit 33f14e
     int *p = NULL;
Packit 33f14e
     size_t used = 0;
Packit 33f14e
     size_t allocated = 0;
Packit 33f14e
Packit 33f14e
     void
Packit 33f14e
     append_int (int value)
Packit 33f14e
       {
Packit 33f14e
         if (used == allocated)
Packit 33f14e
           p = x2nrealloc (p, &allocated, sizeof *p);
Packit 33f14e
         p[used++] = value;
Packit 33f14e
       }
Packit 33f14e
Packit 33f14e
   This causes x2nrealloc to allocate a block of some nonzero size the
Packit 33f14e
   first time it is called.
Packit 33f14e
Packit 33f14e
   To have finer-grained control over the initial size, set *PN to a
Packit 33f14e
   nonzero value before calling this function with P == NULL.  For
Packit 33f14e
   example:
Packit 33f14e
Packit 33f14e
     int *p = NULL;
Packit 33f14e
     size_t used = 0;
Packit 33f14e
     size_t allocated = 0;
Packit 33f14e
     size_t allocated1 = 1000;
Packit 33f14e
Packit 33f14e
     void
Packit 33f14e
     append_int (int value)
Packit 33f14e
       {
Packit 33f14e
         if (used == allocated)
Packit 33f14e
           {
Packit 33f14e
             p = x2nrealloc (p, &allocated1, sizeof *p);
Packit 33f14e
             allocated = allocated1;
Packit 33f14e
           }
Packit 33f14e
         p[used++] = value;
Packit 33f14e
       }
Packit 33f14e
Packit 33f14e
   */
Packit 33f14e
Packit 33f14e
XALLOC_INLINE void *
Packit 33f14e
x2nrealloc (void *p, size_t *pn, size_t s)
Packit 33f14e
{
Packit 33f14e
  size_t n = *pn;
Packit 33f14e
Packit 33f14e
  if (! p)
Packit 33f14e
    {
Packit 33f14e
      if (! n)
Packit 33f14e
        {
Packit 33f14e
          /* The approximate size to use for initial small allocation
Packit 33f14e
             requests, when the invoking code specifies an old size of
Packit 33f14e
             zero.  This is the largest "small" request for the GNU C
Packit 33f14e
             library malloc.  */
Packit 33f14e
          enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 };
Packit 33f14e
Packit 33f14e
          n = DEFAULT_MXFAST / s;
Packit 33f14e
          n += !n;
Packit 33f14e
        }
Packit 33f14e
      if (xalloc_oversized (n, s))
Packit 33f14e
        xalloc_die ();
Packit 33f14e
    }
Packit 33f14e
  else
Packit 33f14e
    {
Packit 33f14e
      /* Set N = floor (1.5 * N) + 1 so that progress is made even if N == 0.
Packit 33f14e
         Check for overflow, so that N * S stays in both ptrdiff_t and
Packit 33f14e
         size_t range.  The check may be slightly conservative, but an
Packit 33f14e
         exact check isn't worth the trouble.  */
Packit 33f14e
      if ((PTRDIFF_MAX < SIZE_MAX ? PTRDIFF_MAX : SIZE_MAX) / 3 * 2 / s
Packit 33f14e
          <= n)
Packit 33f14e
        xalloc_die ();
Packit 33f14e
      n += n / 2 + 1;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  *pn = n;
Packit 33f14e
  return xrealloc (p, n * s);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Return a pointer to a new buffer of N bytes.  This is like xmalloc,
Packit 33f14e
   except it returns char *.  */
Packit 33f14e
Packit 33f14e
XALLOC_INLINE char *xcharalloc (size_t n)
Packit 33f14e
                    _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1));
Packit 33f14e
XALLOC_INLINE char *
Packit 33f14e
xcharalloc (size_t n)
Packit 33f14e
{
Packit 33f14e
  return XNMALLOC (n, char);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
#ifdef __cplusplus
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* C++ does not allow conversions from void * to other pointer types
Packit 33f14e
   without a cast.  Use templates to work around the problem when
Packit 33f14e
   possible.  */
Packit 33f14e
Packit 33f14e
template <typename T> inline T *
Packit 33f14e
xrealloc (T *p, size_t s)
Packit 33f14e
{
Packit 33f14e
  return (T *) xrealloc ((void *) p, s);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
template <typename T> inline T *
Packit 33f14e
xnrealloc (T *p, size_t n, size_t s)
Packit 33f14e
{
Packit 33f14e
  return (T *) xnrealloc ((void *) p, n, s);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
template <typename T> inline T *
Packit 33f14e
x2realloc (T *p, size_t *pn)
Packit 33f14e
{
Packit 33f14e
  return (T *) x2realloc ((void *) p, pn);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
template <typename T> inline T *
Packit 33f14e
x2nrealloc (T *p, size_t *pn, size_t s)
Packit 33f14e
{
Packit 33f14e
  return (T *) x2nrealloc ((void *) p, pn, s);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
template <typename T> inline T *
Packit 33f14e
xmemdup (T const *p, size_t s)
Packit 33f14e
{
Packit 33f14e
  return (T *) xmemdup ((void const *) p, s);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
_GL_INLINE_HEADER_END
Packit 33f14e
Packit 33f14e
#endif /* !XALLOC_H_ */