1 /* xmalloc.c -- malloc with out of memory checking
2 Copyright (C) 1990-1996, 2000-2003, 2005-2007, 2012 Free Software
3 Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17
18 #include <config.h>
19
20 /* Specification. */
21 #include "xalloc.h"
22
23 #include <stdlib.h>
24
25 #include "error.h"
26 #include "gettext.h"
27
28 #define _(str) gettext (str)
29
30
31 /* Exit value when the requested amount of memory is not available.
32 The caller may set it to some other value. */
33 int xmalloc_exit_failure = EXIT_FAILURE;
34
35 void
xalloc_die()36 xalloc_die ()
37 {
38 error (xmalloc_exit_failure, 0, _("memory exhausted"));
39 /* _Noreturn cannot be given to error, since it may return if
40 its first argument is 0. To help compilers understand the
41 xalloc_die does terminate, call exit. */
42 exit (EXIT_FAILURE);
43 }
44
45 static void *
fixup_null_alloc(size_t n)46 fixup_null_alloc (size_t n)
47 {
48 void *p;
49
50 p = NULL;
51 if (n == 0)
52 p = malloc ((size_t) 1);
53 if (p == NULL)
54 xalloc_die ();
55 return p;
56 }
57
58 /* Allocate N bytes of memory dynamically, with error checking. */
59
60 void *
xmalloc(size_t n)61 xmalloc (size_t n)
62 {
63 void *p;
64
65 p = malloc (n);
66 if (p == NULL)
67 p = fixup_null_alloc (n);
68 return p;
69 }
70
71 /* Allocate memory for NMEMB elements of SIZE bytes, with error checking.
72 SIZE must be > 0. */
73
74 void *
xnmalloc(size_t nmemb,size_t size)75 xnmalloc (size_t nmemb, size_t size)
76 {
77 size_t n;
78 void *p;
79
80 if (xalloc_oversized (nmemb, size))
81 xalloc_die ();
82 n = nmemb * size;
83 p = malloc (n);
84 if (p == NULL)
85 p = fixup_null_alloc (n);
86 return p;
87 }
88
89 /* Allocate SIZE bytes of memory dynamically, with error checking,
90 and zero it. */
91
92 void *
xzalloc(size_t size)93 xzalloc (size_t size)
94 {
95 void *p;
96
97 p = xmalloc (size);
98 memset (p, 0, size);
99 return p;
100 }
101
102 /* Allocate memory for N elements of S bytes, with error checking,
103 and zero it. */
104
105 void *
xcalloc(size_t n,size_t s)106 xcalloc (size_t n, size_t s)
107 {
108 void *p;
109
110 p = calloc (n, s);
111 if (p == NULL)
112 p = fixup_null_alloc (n);
113 return p;
114 }
115
116 /* Change the size of an allocated block of memory P to N bytes,
117 with error checking.
118 If P is NULL, run xmalloc. */
119
120 void *
xrealloc(void * p,size_t n)121 xrealloc (void *p, size_t n)
122 {
123 if (p == NULL)
124 return xmalloc (n);
125 p = realloc (p, n);
126 if (p == NULL)
127 p = fixup_null_alloc (n);
128 return p;
129 }
130
131 /* If P is null, allocate a block of at least *PN such objects;
132 otherwise, reallocate P so that it contains more than *PN objects
133 each of S bytes. S must be nonzero. Set *PN to the new number of
134 objects, and return the pointer to the new block. *PN is never set
135 to zero, and the returned pointer is never null.
136
137 Repeated reallocations are guaranteed to make progress, either by
138 allocating an initial block with a nonzero size, or by allocating a
139 larger block.
140
141 In the following implementation, nonzero sizes are increased by a
142 factor of approximately 1.5 so that repeated reallocations have
143 O(N) overall cost rather than O(N**2) cost, but the
144 specification for this function does not guarantee that rate.
145
146 Here is an example of use:
147
148 int *p = NULL;
149 size_t used = 0;
150 size_t allocated = 0;
151
152 void
153 append_int (int value)
154 {
155 if (used == allocated)
156 p = x2nrealloc (p, &allocated, sizeof *p);
157 p[used++] = value;
158 }
159
160 This causes x2nrealloc to allocate a block of some nonzero size the
161 first time it is called.
162
163 To have finer-grained control over the initial size, set *PN to a
164 nonzero value before calling this function with P == NULL. For
165 example:
166
167 int *p = NULL;
168 size_t used = 0;
169 size_t allocated = 0;
170 size_t allocated1 = 1000;
171
172 void
173 append_int (int value)
174 {
175 if (used == allocated)
176 {
177 p = x2nrealloc (p, &allocated1, sizeof *p);
178 allocated = allocated1;
179 }
180 p[used++] = value;
181 }
182
183 */
184
185 static inline void *
x2nrealloc(void * p,size_t * pn,size_t s)186 x2nrealloc (void *p, size_t *pn, size_t s)
187 {
188 size_t n = *pn;
189
190 if (! p)
191 {
192 if (! n)
193 {
194 /* The approximate size to use for initial small allocation
195 requests, when the invoking code specifies an old size of
196 zero. This is the largest "small" request for the GNU C
197 library malloc. */
198 enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 };
199
200 n = DEFAULT_MXFAST / s;
201 n += !n;
202 }
203 if (xalloc_oversized (n, s))
204 xalloc_die ();
205 }
206 else
207 {
208 /* Set N = floor (1.5 * N) + 1 so that progress is made even if N == 0.
209 Check for overflow, so that N * S stays in both ptrdiff_t and
210 size_t range. The check may be slightly conservative, but an
211 exact check isn't worth the trouble. */
212 if ((PTRDIFF_MAX < SIZE_MAX ? PTRDIFF_MAX : SIZE_MAX) / 3 * 2 / s
213 <= n)
214 xalloc_die ();
215 n += n / 2 + 1;
216 }
217
218 *pn = n;
219 return xrealloc (p, n * s);
220 }
221
222 /* If P is null, allocate a block of at least *PN bytes; otherwise,
223 reallocate P so that it contains more than *PN bytes. *PN must be
224 nonzero unless P is null. Set *PN to the new block's size, and
225 return the pointer to the new block. *PN is never set to zero, and
226 the returned pointer is never null. */
227
228 void *
x2realloc(void * p,size_t * pn)229 x2realloc (void *p, size_t *pn)
230 {
231 return x2nrealloc (p, pn, 1);
232 }
233