/src/gettext/gettext-tools/libgettextpo/xmalloc.c
Line | Count | Source |
1 | | /* xmalloc.c -- malloc with out of memory checking |
2 | | |
3 | | Copyright (C) 1990-2000, 2002-2006, 2008-2026 Free Software 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 | | #define XALLOC_INLINE _GL_EXTERN_INLINE |
19 | | #include <config.h> |
20 | | #include "xalloc.h" |
21 | | |
22 | | #include "ialloc.h" |
23 | | #include "minmax.h" |
24 | | |
25 | | #include <stdckdint.h> |
26 | | #include <stdlib.h> |
27 | | #include <stdint.h> |
28 | | #include <string.h> |
29 | | |
30 | | /* Pacify GCC up to at least 15.2, which otherwise would incorrectly |
31 | | complain about check_nonnull. */ |
32 | | #if _GL_GNUC_PREREQ (4, 6) |
33 | | # pragma GCC diagnostic ignored "-Wsuggest-attribute=pure" |
34 | | #endif |
35 | | |
36 | | static void * |
37 | | check_nonnull (void *p) |
38 | 7.85M | { |
39 | 7.85M | if (!p) |
40 | 0 | xalloc_die (); |
41 | 7.85M | return p; |
42 | 7.85M | } |
43 | | |
44 | | /* Allocate S bytes of memory dynamically, with error checking. */ |
45 | | |
46 | | void * |
47 | | xmalloc (size_t s) |
48 | 6.82M | { |
49 | 6.82M | return check_nonnull (malloc (s)); |
50 | 6.82M | } |
51 | | |
52 | | void * |
53 | | ximalloc (idx_t s) |
54 | 0 | { |
55 | 0 | return check_nonnull (imalloc (s)); |
56 | 0 | } |
57 | | |
58 | | char * |
59 | | xcharalloc (size_t n) |
60 | 0 | { |
61 | 0 | return XNMALLOC (n, char); |
62 | 0 | } |
63 | | |
64 | | /* Change the size of an allocated block of memory P to S bytes, |
65 | | with error checking. */ |
66 | | |
67 | | void * |
68 | | xrealloc (void *p, size_t s) |
69 | 1.00M | { |
70 | 1.00M | return check_nonnull (realloc (p, s)); |
71 | 1.00M | } |
72 | | |
73 | | void * |
74 | | xirealloc (void *p, idx_t s) |
75 | 0 | { |
76 | 0 | return check_nonnull (irealloc (p, s)); |
77 | 0 | } |
78 | | |
79 | | /* Change the size of an allocated block of memory P to an array of N |
80 | | objects each of S bytes, with error checking. */ |
81 | | |
82 | | void * |
83 | | xreallocarray (void *p, size_t n, size_t s) |
84 | 11.9k | { |
85 | 11.9k | return check_nonnull (reallocarray (p, n, s)); |
86 | 11.9k | } |
87 | | |
88 | | void * |
89 | | xireallocarray (void *p, idx_t n, idx_t s) |
90 | 0 | { |
91 | 0 | return check_nonnull (ireallocarray (p, n, s)); |
92 | 0 | } |
93 | | |
94 | | /* Allocate an array of N objects, each with S bytes of memory, |
95 | | dynamically, with error checking. S must be nonzero. */ |
96 | | |
97 | | void * |
98 | | xnmalloc (size_t n, size_t s) |
99 | 11.9k | { |
100 | 11.9k | return xreallocarray (NULL, n, s); |
101 | 11.9k | } |
102 | | |
103 | | void * |
104 | | xinmalloc (idx_t n, idx_t s) |
105 | 0 | { |
106 | 0 | return xireallocarray (NULL, n, s); |
107 | 0 | } |
108 | | |
109 | | /* If P is null, allocate a block of at least *PS bytes; otherwise, |
110 | | reallocate P so that it contains more than *PS bytes. *PS must be |
111 | | nonzero unless P is null. Set *PS to the new block's size, and |
112 | | return the pointer to the new block. *PS is never set to zero, and |
113 | | the returned pointer is never null. */ |
114 | | |
115 | | void * |
116 | | x2realloc (void *p, size_t *ps) |
117 | 0 | { |
118 | 0 | return x2nrealloc (p, ps, 1); |
119 | 0 | } |
120 | | |
121 | | /* If P is null, allocate a block of at least *PN such objects; |
122 | | otherwise, reallocate P so that it contains more than *PN objects |
123 | | each of S bytes. S must be nonzero. Set *PN to the new number of |
124 | | objects, and return the pointer to the new block. *PN is never set |
125 | | to zero, and the 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 increased by a |
132 | | factor of approximately 1.5 so that repeated reallocations have |
133 | | O(N) overall cost rather than O(N**2) cost, but the |
134 | | specification for this function does not guarantee that rate. |
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 | | void * |
176 | | x2nrealloc (void *p, size_t *pn, size_t s) |
177 | 0 | { |
178 | 0 | size_t n = *pn; |
179 | |
|
180 | 0 | if (! p) |
181 | 0 | { |
182 | 0 | if (! n) |
183 | 0 | { |
184 | | /* The approximate size to use for initial small allocation |
185 | | requests, when the invoking code specifies an old size of |
186 | | zero. This is the largest "small" request for the GNU C |
187 | | library malloc. */ |
188 | 0 | enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 }; |
189 | |
|
190 | 0 | n = DEFAULT_MXFAST / s; |
191 | 0 | n += !n; |
192 | 0 | } |
193 | 0 | } |
194 | 0 | else |
195 | 0 | { |
196 | | /* Set N = floor (1.5 * N) + 1 to make progress even if N == 0. */ |
197 | 0 | if (ckd_add (&n, n, (n >> 1) + 1)) |
198 | 0 | xalloc_die (); |
199 | 0 | } |
200 | |
|
201 | 0 | p = xreallocarray (p, n, s); |
202 | 0 | *pn = n; |
203 | 0 | return p; |
204 | 0 | } |
205 | | |
206 | | /* Grow PA, which points to an array of *PN items, and return the |
207 | | location of the reallocated array, updating *PN to reflect its |
208 | | new size. The new array will contain at least N_INCR_MIN more |
209 | | items, but will not contain more than N_MAX items total. |
210 | | S is the size of each item, in bytes. |
211 | | |
212 | | S and N_INCR_MIN must be positive. *PN must be |
213 | | nonnegative. If N_MAX is -1, it is treated as if it were |
214 | | infinity. |
215 | | |
216 | | If PA is null, then allocate a new array instead of reallocating |
217 | | the old one. |
218 | | |
219 | | Thus, to grow an array A without saving its old contents, do |
220 | | { free (A); A = xpalloc (NULL, &AITEMS, ...); }. */ |
221 | | |
222 | | void * |
223 | | xpalloc (void *pa, idx_t *pn, idx_t n_incr_min, ptrdiff_t n_max, idx_t s) |
224 | 0 | { |
225 | | /* The approximate size to use for initial small allocation |
226 | | requests. This is the largest "small" request for the GNU C |
227 | | library malloc. */ |
228 | 0 | enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 }; |
229 | |
|
230 | 0 | idx_t n0 = *pn; |
231 | | |
232 | | /* If the array is tiny, grow it to about (but no greater than) |
233 | | DEFAULT_MXFAST bytes. Otherwise, grow it by about 50%. |
234 | | Adjust the growth according to three constraints: N_INCR_MIN, |
235 | | N_MAX, and what the C language can represent safely. */ |
236 | |
|
237 | 0 | idx_t n; |
238 | 0 | if (ckd_add (&n, n0, n0 >> 1)) |
239 | 0 | n = IDX_MAX; |
240 | 0 | if (0 <= n_max && n_max < n) |
241 | 0 | n = n_max; |
242 | | |
243 | | /* NBYTES is of a type suitable for holding the count of bytes in an object. |
244 | | This is typically idx_t, but it should be size_t on (theoretical?) |
245 | | platforms where SIZE_MAX < IDX_MAX so xpalloc does not pass |
246 | | values greater than SIZE_MAX to xrealloc. */ |
247 | 0 | #if IDX_MAX <= SIZE_MAX |
248 | 0 | idx_t nbytes; |
249 | | #else |
250 | | size_t nbytes; |
251 | | #endif |
252 | 0 | idx_t adjusted_nbytes |
253 | 0 | = (ckd_mul (&nbytes, n, s) |
254 | 0 | ? MIN (IDX_MAX, SIZE_MAX) |
255 | 0 | : nbytes < DEFAULT_MXFAST ? DEFAULT_MXFAST : 0); |
256 | 0 | if (adjusted_nbytes) |
257 | 0 | { |
258 | 0 | n = adjusted_nbytes / s; |
259 | 0 | nbytes = adjusted_nbytes - adjusted_nbytes % s; |
260 | 0 | } |
261 | |
|
262 | 0 | if (! pa) |
263 | 0 | *pn = 0; |
264 | 0 | if (n - n0 < n_incr_min |
265 | 0 | && (ckd_add (&n, n0, n_incr_min) |
266 | 0 | || (0 <= n_max && n_max < n) |
267 | 0 | || ckd_mul (&nbytes, n, s))) |
268 | 0 | xalloc_die (); |
269 | 0 | pa = xrealloc (pa, nbytes); |
270 | 0 | *pn = n; |
271 | 0 | return pa; |
272 | 0 | } |
273 | | |
274 | | /* Allocate S bytes of zeroed memory dynamically, with error checking. |
275 | | There's no need for xnzalloc (N, S), since it would be equivalent |
276 | | to xcalloc (N, S). */ |
277 | | |
278 | | void * |
279 | | xzalloc (size_t s) |
280 | 0 | { |
281 | 0 | return xcalloc (s, 1); |
282 | 0 | } |
283 | | |
284 | | void * |
285 | | xizalloc (idx_t s) |
286 | 0 | { |
287 | 0 | return xicalloc (s, 1); |
288 | 0 | } |
289 | | |
290 | | /* Allocate zeroed memory for N elements of S bytes, with error |
291 | | checking. S must be nonzero. */ |
292 | | |
293 | | void * |
294 | | xcalloc (size_t n, size_t s) |
295 | 15.2k | { |
296 | 15.2k | return check_nonnull (calloc (n, s)); |
297 | 15.2k | } |
298 | | |
299 | | void * |
300 | | xicalloc (idx_t n, idx_t s) |
301 | 0 | { |
302 | 0 | return check_nonnull (icalloc (n, s)); |
303 | 0 | } |
304 | | |
305 | | /* Clone an object P of size S, with error checking. There's no need |
306 | | for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any |
307 | | need for an arithmetic overflow check. */ |
308 | | |
309 | | void * |
310 | | xmemdup (void const *p, size_t s) |
311 | 6.44M | { |
312 | 6.44M | return memcpy (xmalloc (s), p, s); |
313 | 6.44M | } |
314 | | |
315 | | void * |
316 | | ximemdup (void const *p, idx_t s) |
317 | 0 | { |
318 | 0 | return memcpy (ximalloc (s), p, s); |
319 | 0 | } |
320 | | |
321 | | /* Clone an object P of size S, with error checking. Append |
322 | | a terminating NUL byte. */ |
323 | | |
324 | | char * |
325 | | ximemdup0 (void const *p, idx_t s) |
326 | 0 | { |
327 | 0 | char *result = ximalloc (s + 1); |
328 | 0 | result[s] = 0; |
329 | 0 | return memcpy (result, p, s); |
330 | 0 | } |
331 | | |
332 | | /* Clone STRING. */ |
333 | | |
334 | | char * |
335 | | xstrdup (char const *string) |
336 | 6.44M | { |
337 | 6.44M | return xmemdup (string, strlen (string) + 1); |
338 | 6.44M | } |