summaryrefslogtreecommitdiffstats
path: root/gl/xmalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/xmalloc.c')
-rw-r--r--gl/xmalloc.c306
1 files changed, 262 insertions, 44 deletions
diff --git a/gl/xmalloc.c b/gl/xmalloc.c
index 57e34b7c..289cbd05 100644
--- a/gl/xmalloc.c
+++ b/gl/xmalloc.c
@@ -1,10 +1,10 @@
1/* xmalloc.c -- malloc with out of memory checking 1/* xmalloc.c -- malloc with out of memory checking
2 2
3 Copyright (C) 1990-2000, 2002-2006, 2008-2013 Free Software Foundation, Inc. 3 Copyright (C) 1990-2000, 2002-2006, 2008-2023 Free Software Foundation, Inc.
4 4
5 This program is free software: you can redistribute it and/or modify 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 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 7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version. 8 (at your option) any later version.
9 9
10 This program is distributed in the hope that it will be useful, 10 This program is distributed in the hope that it will be useful,
@@ -13,7 +13,7 @@
13 GNU General Public License for more details. 13 GNU General Public License for more details.
14 14
15 You should have received a copy of the GNU General Public License 15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 17
18#include <config.h> 18#include <config.h>
19 19
@@ -21,59 +21,256 @@
21 21
22#include "xalloc.h" 22#include "xalloc.h"
23 23
24#include "ialloc.h"
25#include "minmax.h"
26
27#include <stdckdint.h>
24#include <stdlib.h> 28#include <stdlib.h>
29#include <stdint.h>
25#include <string.h> 30#include <string.h>
26 31
27/* 1 if calloc is known to be compatible with GNU calloc. This 32static void * _GL_ATTRIBUTE_PURE
28 matters if we are not also using the calloc module, which defines 33nonnull (void *p)
29 HAVE_CALLOC_GNU and supports the GNU API even on non-GNU platforms. */ 34{
30#if defined HAVE_CALLOC_GNU || (defined __GLIBC__ && !defined __UCLIBC__) 35 if (!p)
31enum { HAVE_GNU_CALLOC = 1 }; 36 xalloc_die ();
32#else 37 return p;
33enum { HAVE_GNU_CALLOC = 0 }; 38}
34#endif
35 39
36/* Allocate N bytes of memory dynamically, with error checking. */ 40/* Allocate S bytes of memory dynamically, with error checking. */
37 41
38void * 42void *
39xmalloc (size_t n) 43xmalloc (size_t s)
40{ 44{
41 void *p = malloc (n); 45 return nonnull (malloc (s));
42 if (!p && n != 0) 46}
43 xalloc_die (); 47
44 return p; 48void *
49ximalloc (idx_t s)
50{
51 return nonnull (imalloc (s));
45} 52}
46 53
47/* Change the size of an allocated block of memory P to N bytes, 54char *
55xcharalloc (size_t n)
56{
57 return XNMALLOC (n, char);
58}
59
60/* Change the size of an allocated block of memory P to S bytes,
48 with error checking. */ 61 with error checking. */
49 62
50void * 63void *
51xrealloc (void *p, size_t n) 64xrealloc (void *p, size_t s)
65{
66 void *r = realloc (p, s);
67 if (!r && (!p || s))
68 xalloc_die ();
69 return r;
70}
71
72void *
73xirealloc (void *p, idx_t s)
74{
75 return nonnull (irealloc (p, s));
76}
77
78/* Change the size of an allocated block of memory P to an array of N
79 objects each of S bytes, with error checking. */
80
81void *
82xreallocarray (void *p, size_t n, size_t s)
83{
84 void *r = reallocarray (p, n, s);
85 if (!r && (!p || (n && s)))
86 xalloc_die ();
87 return r;
88}
89
90void *
91xireallocarray (void *p, idx_t n, idx_t s)
92{
93 return nonnull (ireallocarray (p, n, s));
94}
95
96/* Allocate an array of N objects, each with S bytes of memory,
97 dynamically, with error checking. S must be nonzero. */
98
99void *
100xnmalloc (size_t n, size_t s)
101{
102 return xreallocarray (NULL, n, s);
103}
104
105void *
106xinmalloc (idx_t n, idx_t s)
107{
108 return xireallocarray (NULL, n, s);
109}
110
111/* If P is null, allocate a block of at least *PS bytes; otherwise,
112 reallocate P so that it contains more than *PS bytes. *PS must be
113 nonzero unless P is null. Set *PS to the new block's size, and
114 return the pointer to the new block. *PS is never set to zero, and
115 the returned pointer is never null. */
116
117void *
118x2realloc (void *p, size_t *ps)
119{
120 return x2nrealloc (p, ps, 1);
121}
122
123/* If P is null, allocate a block of at least *PN such objects;
124 otherwise, reallocate P so that it contains more than *PN objects
125 each of S bytes. S must be nonzero. Set *PN to the new number of
126 objects, and return the pointer to the new block. *PN is never set
127 to zero, and the returned pointer is never null.
128
129 Repeated reallocations are guaranteed to make progress, either by
130 allocating an initial block with a nonzero size, or by allocating a
131 larger block.
132
133 In the following implementation, nonzero sizes are increased by a
134 factor of approximately 1.5 so that repeated reallocations have
135 O(N) overall cost rather than O(N**2) cost, but the
136 specification for this function does not guarantee that rate.
137
138 Here is an example of use:
139
140 int *p = NULL;
141 size_t used = 0;
142 size_t allocated = 0;
143
144 void
145 append_int (int value)
146 {
147 if (used == allocated)
148 p = x2nrealloc (p, &allocated, sizeof *p);
149 p[used++] = value;
150 }
151
152 This causes x2nrealloc to allocate a block of some nonzero size the
153 first time it is called.
154
155 To have finer-grained control over the initial size, set *PN to a
156 nonzero value before calling this function with P == NULL. For
157 example:
158
159 int *p = NULL;
160 size_t used = 0;
161 size_t allocated = 0;
162 size_t allocated1 = 1000;
163
164 void
165 append_int (int value)
166 {
167 if (used == allocated)
168 {
169 p = x2nrealloc (p, &allocated1, sizeof *p);
170 allocated = allocated1;
171 }
172 p[used++] = value;
173 }
174
175 */
176
177void *
178x2nrealloc (void *p, size_t *pn, size_t s)
52{ 179{
53 if (!n && p) 180 size_t n = *pn;
181
182 if (! p)
54 { 183 {
55 /* The GNU and C99 realloc behaviors disagree here. Act like 184 if (! n)
56 GNU, even if the underlying realloc is C99. */ 185 {
57 free (p); 186 /* The approximate size to use for initial small allocation
58 return NULL; 187 requests, when the invoking code specifies an old size of
188 zero. This is the largest "small" request for the GNU C
189 library malloc. */
190 enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 };
191
192 n = DEFAULT_MXFAST / s;
193 n += !n;
194 }
195 }
196 else
197 {
198 /* Set N = floor (1.5 * N) + 1 to make progress even if N == 0. */
199 if (ckd_add (&n, n, (n >> 1) + 1))
200 xalloc_die ();
59 } 201 }
60 202
61 p = realloc (p, n); 203 p = xreallocarray (p, n, s);
62 if (!p && n) 204 *pn = n;
63 xalloc_die ();
64 return p; 205 return p;
65} 206}
66 207
67/* If P is null, allocate a block of at least *PN bytes; otherwise, 208/* Grow PA, which points to an array of *PN items, and return the
68 reallocate P so that it contains more than *PN bytes. *PN must be 209 location of the reallocated array, updating *PN to reflect its
69 nonzero unless P is null. Set *PN to the new block's size, and 210 new size. The new array will contain at least N_INCR_MIN more
70 return the pointer to the new block. *PN is never set to zero, and 211 items, but will not contain more than N_MAX items total.
71 the returned pointer is never null. */ 212 S is the size of each item, in bytes.
213
214 S and N_INCR_MIN must be positive. *PN must be
215 nonnegative. If N_MAX is -1, it is treated as if it were
216 infinity.
217
218 If PA is null, then allocate a new array instead of reallocating
219 the old one.
220
221 Thus, to grow an array A without saving its old contents, do
222 { free (A); A = xpalloc (NULL, &AITEMS, ...); }. */
72 223
73void * 224void *
74x2realloc (void *p, size_t *pn) 225xpalloc (void *pa, idx_t *pn, idx_t n_incr_min, ptrdiff_t n_max, idx_t s)
75{ 226{
76 return x2nrealloc (p, pn, 1); 227 idx_t n0 = *pn;
228
229 /* The approximate size to use for initial small allocation
230 requests. This is the largest "small" request for the GNU C
231 library malloc. */
232 enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 };
233
234 /* If the array is tiny, grow it to about (but no greater than)
235 DEFAULT_MXFAST bytes. Otherwise, grow it by about 50%.
236 Adjust the growth according to three constraints: N_INCR_MIN,
237 N_MAX, and what the C language can represent safely. */
238
239 idx_t n;
240 if (ckd_add (&n, n0, n0 >> 1))
241 n = IDX_MAX;
242 if (0 <= n_max && n_max < n)
243 n = n_max;
244
245 /* NBYTES is of a type suitable for holding the count of bytes in an object.
246 This is typically idx_t, but it should be size_t on (theoretical?)
247 platforms where SIZE_MAX < IDX_MAX so xpalloc does not pass
248 values greater than SIZE_MAX to xrealloc. */
249#if IDX_MAX <= SIZE_MAX
250 idx_t nbytes;
251#else
252 size_t nbytes;
253#endif
254 idx_t adjusted_nbytes
255 = (ckd_mul (&nbytes, n, s)
256 ? MIN (IDX_MAX, SIZE_MAX)
257 : nbytes < DEFAULT_MXFAST ? DEFAULT_MXFAST : 0);
258 if (adjusted_nbytes)
259 {
260 n = adjusted_nbytes / s;
261 nbytes = adjusted_nbytes - adjusted_nbytes % s;
262 }
263
264 if (! pa)
265 *pn = 0;
266 if (n - n0 < n_incr_min
267 && (ckd_add (&n, n0, n_incr_min)
268 || (0 <= n_max && n_max < n)
269 || ckd_mul (&nbytes, n, s)))
270 xalloc_die ();
271 pa = xrealloc (pa, nbytes);
272 *pn = n;
273 return pa;
77} 274}
78 275
79/* Allocate S bytes of zeroed memory dynamically, with error checking. 276/* Allocate S bytes of zeroed memory dynamically, with error checking.
@@ -83,7 +280,13 @@ x2realloc (void *p, size_t *pn)
83void * 280void *
84xzalloc (size_t s) 281xzalloc (size_t s)
85{ 282{
86 return memset (xmalloc (s), 0, s); 283 return xcalloc (s, 1);
284}
285
286void *
287xizalloc (idx_t s)
288{
289 return xicalloc (s, 1);
87} 290}
88 291
89/* Allocate zeroed memory for N elements of S bytes, with error 292/* Allocate zeroed memory for N elements of S bytes, with error
@@ -92,15 +295,13 @@ xzalloc (size_t s)
92void * 295void *
93xcalloc (size_t n, size_t s) 296xcalloc (size_t n, size_t s)
94{ 297{
95 void *p; 298 return nonnull (calloc (n, s));
96 /* Test for overflow, since some calloc implementations don't have 299}
97 proper overflow checks. But omit overflow and size-zero tests if 300
98 HAVE_GNU_CALLOC, since GNU calloc catches overflow and never 301void *
99 returns NULL if successful. */ 302xicalloc (idx_t n, idx_t s)
100 if ((! HAVE_GNU_CALLOC && xalloc_oversized (n, s)) 303{
101 || (! (p = calloc (n, s)) && (HAVE_GNU_CALLOC || n != 0))) 304 return nonnull (icalloc (n, s));
102 xalloc_die ();
103 return p;
104} 305}
105 306
106/* Clone an object P of size S, with error checking. There's no need 307/* Clone an object P of size S, with error checking. There's no need
@@ -113,6 +314,23 @@ xmemdup (void const *p, size_t s)
113 return memcpy (xmalloc (s), p, s); 314 return memcpy (xmalloc (s), p, s);
114} 315}
115 316
317void *
318ximemdup (void const *p, idx_t s)
319{
320 return memcpy (ximalloc (s), p, s);
321}
322
323/* Clone an object P of size S, with error checking. Append
324 a terminating NUL byte. */
325
326char *
327ximemdup0 (void const *p, idx_t s)
328{
329 char *result = ximalloc (s + 1);
330 result[s] = 0;
331 return memcpy (result, p, s);
332}
333
116/* Clone STRING. */ 334/* Clone STRING. */
117 335
118char * 336char *