Coverage Report

Created: 2026-03-12 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}