1/* xmalloc.c -- malloc with out of memory checking
2
3   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
4   1999, 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software Foundation,
18   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20#if HAVE_CONFIG_H
21# include <config.h>
22#endif
23
24#include "xalloc.h"
25
26#include <stdlib.h>
27#include <string.h>
28
29#ifndef SIZE_MAX
30# define SIZE_MAX ((size_t) -1)
31#endif
32
33/* Allocate an array of N objects, each with S bytes of memory,
34   dynamically, with error checking.  S must be nonzero.  */
35
36static inline void *
37xnmalloc_inline (size_t n, size_t s)
38{
39  void *p;
40  if (xalloc_oversized (n, s) || (! (p = malloc (n * s)) && n != 0))
41    xalloc_die ();
42  return p;
43}
44
45void *
46xnmalloc (size_t n, size_t s)
47{
48  return xnmalloc_inline (n, s);
49}
50
51/* Allocate N bytes of memory dynamically, with error checking.  */
52
53void *
54xmalloc (size_t n)
55{
56  return xnmalloc_inline (n, 1);
57}
58
59/* Change the size of an allocated block of memory P to an array of N
60   objects each of S bytes, with error checking.  S must be nonzero.  */
61
62static inline void *
63xnrealloc_inline (void *p, size_t n, size_t s)
64{
65  if (xalloc_oversized (n, s) || (! (p = realloc (p, n * s)) && n != 0))
66    xalloc_die ();
67  return p;
68}
69
70void *
71xnrealloc (void *p, size_t n, size_t s)
72{
73  return xnrealloc_inline (p, n, s);
74}
75
76/* Change the size of an allocated block of memory P to N bytes,
77   with error checking.  */
78
79void *
80xrealloc (void *p, size_t n)
81{
82  return xnrealloc_inline (p, n, 1);
83}
84
85
86/* If P is null, allocate a block of at least *PN such objects;
87   otherwise, reallocate P so that it contains more than *PN objects
88   each of S bytes.  *PN must be nonzero unless P is null, and S must
89   be nonzero.  Set *PN to the new number of objects, and return the
90   pointer to the new block.  *PN is never set to zero, and the
91   returned pointer is never null.
92
93   Repeated reallocations are guaranteed to make progress, either by
94   allocating an initial block with a nonzero size, or by allocating a
95   larger block.
96
97   In the following implementation, nonzero sizes are doubled so that
98   repeated reallocations have O(N log N) overall cost rather than
99   O(N**2) cost, but the specification for this function does not
100   guarantee that sizes are doubled.
101
102   Here is an example of use:
103
104     int *p = NULL;
105     size_t used = 0;
106     size_t allocated = 0;
107
108     void
109     append_int (int value)
110       {
111	 if (used == allocated)
112	   p = x2nrealloc (p, &allocated, sizeof *p);
113	 p[used++] = value;
114       }
115
116   This causes x2nrealloc to allocate a block of some nonzero size the
117   first time it is called.
118
119   To have finer-grained control over the initial size, set *PN to a
120   nonzero value before calling this function with P == NULL.  For
121   example:
122
123     int *p = NULL;
124     size_t used = 0;
125     size_t allocated = 0;
126     size_t allocated1 = 1000;
127
128     void
129     append_int (int value)
130       {
131	 if (used == allocated)
132	   {
133	     p = x2nrealloc (p, &allocated1, sizeof *p);
134	     allocated = allocated1;
135	   }
136	 p[used++] = value;
137       }
138
139   */
140
141static inline void *
142x2nrealloc_inline (void *p, size_t *pn, size_t s)
143{
144  size_t n = *pn;
145
146  if (! p)
147    {
148      if (! n)
149	{
150	  /* The approximate size to use for initial small allocation
151	     requests, when the invoking code specifies an old size of
152	     zero.  64 bytes is the largest "small" request for the
153	     GNU C library malloc.  */
154	  enum { DEFAULT_MXFAST = 64 };
155
156	  n = DEFAULT_MXFAST / s;
157	  n += !n;
158	}
159    }
160  else
161    {
162      if (SIZE_MAX / 2 / s < n)
163	xalloc_die ();
164      n *= 2;
165    }
166
167  *pn = n;
168  return xrealloc (p, n * s);
169}
170
171void *
172x2nrealloc (void *p, size_t *pn, size_t s)
173{
174  return x2nrealloc_inline (p, pn, s);
175}
176
177/* If P is null, allocate a block of at least *PN bytes; otherwise,
178   reallocate P so that it contains more than *PN bytes.  *PN must be
179   nonzero unless P is null.  Set *PN to the new block's size, and
180   return the pointer to the new block.  *PN is never set to zero, and
181   the returned pointer is never null.  */
182
183void *
184x2realloc (void *p, size_t *pn)
185{
186  return x2nrealloc_inline (p, pn, 1);
187}
188
189/* Allocate S bytes of zeroed memory dynamically, with error checking.
190   There's no need for xnzalloc (N, S), since it would be equivalent
191   to xcalloc (N, S).  */
192
193void *
194xzalloc (size_t s)
195{
196  return memset (xmalloc (s), 0, s);
197}
198
199/* Allocate zeroed memory for N elements of S bytes, with error
200   checking.  S must be nonzero.  */
201
202void *
203xcalloc (size_t n, size_t s)
204{
205  void *p;
206  /* Test for overflow, since some calloc implementations don't have
207     proper overflow checks.  */
208  if (xalloc_oversized (n, s) || (! (p = calloc (n, s)) && n != 0))
209    xalloc_die ();
210  return p;
211}
212
213/* Clone an object P of size S, with error checking.  There's no need
214   for xnclone (P, N, S), since xclone (P, N * S) works without any
215   need for an arithmetic overflow check.  */
216
217void *
218xclone (void const *p, size_t s)
219{
220  return memcpy (xmalloc (s), p, s);
221}
222