xref: /freebsd/contrib/diff/lib/xmalloc.c (revision e757cb8ecb9710e553d3010e96c5f2217c4cac6d)
1  /* xmalloc.c -- malloc with out of memory checking
2  
3     Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2003,
4     1999, 2000, 2002, 2003 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  #include "gettext.h"
30  #define _(msgid) gettext (msgid)
31  #define N_(msgid) msgid
32  
33  #include "error.h"
34  #include "exitfail.h"
35  
36  #ifndef SIZE_MAX
37  # define SIZE_MAX ((size_t) -1)
38  #endif
39  
40  #ifndef HAVE_MALLOC
41  "you must run the autoconf test for a GNU libc compatible malloc"
42  #endif
43  
44  #ifndef HAVE_REALLOC
45  "you must run the autoconf test for a GNU libc compatible realloc"
46  #endif
47  
48  /* If non NULL, call this function when memory is exhausted. */
49  void (*xalloc_fail_func) (void) = 0;
50  
51  /* If XALLOC_FAIL_FUNC is NULL, or does return, display this message
52     before exiting when memory is exhausted.  Goes through gettext. */
53  char const xalloc_msg_memory_exhausted[] = N_("memory exhausted");
54  
55  void
56  xalloc_die (void)
57  {
58    if (xalloc_fail_func)
59      (*xalloc_fail_func) ();
60    error (exit_failure, 0, "%s", _(xalloc_msg_memory_exhausted));
61    /* The `noreturn' cannot be given to error, since it may return if
62       its first argument is 0.  To help compilers understand the
63       xalloc_die does terminate, call abort.  */
64    abort ();
65  }
66  
67  /* Allocate an array of N objects, each with S bytes of memory,
68     dynamically, with error checking.  S must be nonzero.  */
69  
70  static inline void *
71  xnmalloc_inline (size_t n, size_t s)
72  {
73    void *p;
74    if (xalloc_oversized (n, s) || ! (p = malloc (n * s)))
75      xalloc_die ();
76    return p;
77  }
78  
79  void *
80  xnmalloc (size_t n, size_t s)
81  {
82    return xnmalloc_inline (n, s);
83  }
84  
85  /* Allocate N bytes of memory dynamically, with error checking.  */
86  
87  void *
88  xmalloc (size_t n)
89  {
90    return xnmalloc_inline (n, 1);
91  }
92  
93  /* Change the size of an allocated block of memory P to an array of N
94     objects each of S bytes, with error checking.  S must be nonzero.  */
95  
96  static inline void *
97  xnrealloc_inline (void *p, size_t n, size_t s)
98  {
99    if (xalloc_oversized (n, s) || ! (p = realloc (p, n * s)))
100      xalloc_die ();
101    return p;
102  }
103  
104  void *
105  xnrealloc (void *p, size_t n, size_t s)
106  {
107    return xnrealloc_inline (p, n, s);
108  }
109  
110  /* Change the size of an allocated block of memory P to N bytes,
111     with error checking.  */
112  
113  void *
114  xrealloc (void *p, size_t n)
115  {
116    return xnrealloc_inline (p, n, 1);
117  }
118  
119  
120  /* If P is null, allocate a block of at least *PN such objects;
121     otherwise, reallocate P so that it contains more than *PN objects
122     each of S bytes.  *PN must be nonzero unless P is null, and S must
123     be nonzero.  Set *PN to the new number of objects, and return the
124     pointer to the new block.  *PN is never set to zero, and the
125     returned pointer is never null.
126  
127     Repeated reallocations are guaranteed to make progress, either by
128     allocating an initial block with a nonzero size, or by allocating a
129     larger block.
130  
131     In the following implementation, nonzero sizes are doubled so that
132     repeated reallocations have O(N log N) overall cost rather than
133     O(N**2) cost, but the specification for this function does not
134     guarantee that sizes are doubled.
135  
136     Here is an example of use:
137  
138       int *p = NULL;
139       size_t used = 0;
140       size_t allocated = 0;
141  
142       void
143       append_int (int value)
144         {
145  	 if (used == allocated)
146  	   p = x2nrealloc (p, &allocated, sizeof *p);
147  	 p[used++] = value;
148         }
149  
150     This causes x2nrealloc to allocate a block of some nonzero size the
151     first time it is called.
152  
153     To have finer-grained control over the initial size, set *PN to a
154     nonzero value before calling this function with P == NULL.  For
155     example:
156  
157       int *p = NULL;
158       size_t used = 0;
159       size_t allocated = 0;
160       size_t allocated1 = 1000;
161  
162       void
163       append_int (int value)
164         {
165  	 if (used == allocated)
166  	   {
167  	     p = x2nrealloc (p, &allocated1, sizeof *p);
168  	     allocated = allocated1;
169  	   }
170  	 p[used++] = value;
171         }
172  
173     */
174  
175  static inline void *
176  x2nrealloc_inline (void *p, size_t *pn, size_t s)
177  {
178    size_t n = *pn;
179  
180    if (! p)
181      {
182        if (! n)
183  	{
184  	  /* The approximate size to use for initial small allocation
185  	     requests, when the invoking code specifies an old size of
186  	     zero.  64 bytes is the largest "small" request for the
187  	     GNU C library malloc.  */
188  	  enum { DEFAULT_MXFAST = 64 };
189  
190  	  n = DEFAULT_MXFAST / s;
191  	  n += !n;
192  	}
193      }
194    else
195      {
196        if (SIZE_MAX / 2 / s < n)
197  	xalloc_die ();
198        n *= 2;
199      }
200  
201    *pn = n;
202    return xrealloc (p, n * s);
203  }
204  
205  void *
206  x2nrealloc (void *p, size_t *pn, size_t s)
207  {
208    return x2nrealloc_inline (p, pn, s);
209  }
210  
211  /* If P is null, allocate a block of at least *PN bytes; otherwise,
212     reallocate P so that it contains more than *PN bytes.  *PN must be
213     nonzero unless P is null.  Set *PN to the new block's size, and
214     return the pointer to the new block.  *PN is never set to zero, and
215     the returned pointer is never null.  */
216  
217  void *
218  x2realloc (void *p, size_t *pn)
219  {
220    return x2nrealloc_inline (p, pn, 1);
221  }
222  
223  /* Allocate S bytes of zeroed memory dynamically, with error checking.
224     There's no need for xnzalloc (N, S), since it would be equivalent
225     to xcalloc (N, S).  */
226  
227  void *
228  xzalloc (size_t s)
229  {
230    return memset (xmalloc (s), 0, s);
231  }
232  
233  /* Allocate zeroed memory for N elements of S bytes, with error
234     checking.  S must be nonzero.  */
235  
236  void *
237  xcalloc (size_t n, size_t s)
238  {
239    void *p;
240    /* Test for overflow, since some calloc implementations don't have
241       proper overflow checks.  */
242    if (xalloc_oversized (n, s) || ! (p = calloc (n, s)))
243      xalloc_die ();
244    return p;
245  }
246  
247  /* Clone an object P of size S, with error checking.  There's no need
248     for xnclone (P, N, S), since xclone (P, N * S) works without any
249     need for an arithmetic overflow check.  */
250  
251  void *
252  xclone (void const *p, size_t s)
253  {
254    return memcpy (xmalloc (s), p, s);
255  }
256