Bug Summary

File:build-scan/../src/basic/escape.c
Warning:line 33, column 34
Use of zero-allocated memory

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name escape.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I src/basic/libbasic.a.p -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I . -I .. -I /usr/include/blkid -I /usr/include/libmount -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility default -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/basic/escape.c

../src/basic/escape.c

1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <errno(*__errno_location ()).h>
4#include <stdlib.h>
5#include <string.h>
6
7#include "alloc-util.h"
8#include "escape.h"
9#include "hexdecoct.h"
10#include "macro.h"
11#include "utf8.h"
12
13int cescape_char(char c, char *buf) {
14 char *buf_old = buf;
15
16 /* Needs space for 4 characters in the buffer */
17
18 switch (c) {
15
Control jumps to 'case 10:' at line 32
19
20 case '\a':
21 *(buf++) = '\\';
22 *(buf++) = 'a';
23 break;
24 case '\b':
25 *(buf++) = '\\';
26 *(buf++) = 'b';
27 break;
28 case '\f':
29 *(buf++) = '\\';
30 *(buf++) = 'f';
31 break;
32 case '\n':
33 *(buf++) = '\\';
16
Use of zero-allocated memory
34 *(buf++) = 'n';
35 break;
36 case '\r':
37 *(buf++) = '\\';
38 *(buf++) = 'r';
39 break;
40 case '\t':
41 *(buf++) = '\\';
42 *(buf++) = 't';
43 break;
44 case '\v':
45 *(buf++) = '\\';
46 *(buf++) = 'v';
47 break;
48 case '\\':
49 *(buf++) = '\\';
50 *(buf++) = '\\';
51 break;
52 case '"':
53 *(buf++) = '\\';
54 *(buf++) = '"';
55 break;
56 case '\'':
57 *(buf++) = '\\';
58 *(buf++) = '\'';
59 break;
60
61 default:
62 /* For special chars we prefer octal over
63 * hexadecimal encoding, simply because glib's
64 * g_strescape() does the same */
65 if ((c < ' ') || (c >= 127)) {
66 *(buf++) = '\\';
67 *(buf++) = octchar((unsigned char) c >> 6);
68 *(buf++) = octchar((unsigned char) c >> 3);
69 *(buf++) = octchar((unsigned char) c);
70 } else
71 *(buf++) = c;
72 break;
73 }
74
75 return buf - buf_old;
76}
77
78char *cescape_length(const char *s, size_t n) {
79 const char *f;
80 char *r, *t;
81
82 assert(s || n == 0)do { if ((__builtin_expect(!!(!(s || n == 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s || n == 0"), "../src/basic/escape.c",
82, __PRETTY_FUNCTION__); } while (0)
;
5
Taking false branch
6
Loop condition is false. Exiting loop
83
84 /* Does C style string escaping. May be reversed with
85 * cunescape(). */
86
87 r = new(char, n*4 + 1)((char*) malloc_multiply(sizeof(char), (n*4 + 1)));
7
Calling 'malloc_multiply'
10
Returned allocated memory
88 if (!r)
11
Assuming 'r' is non-null
12
Taking false branch
89 return NULL((void*)0);
90
91 for (f = s, t = r; f < s + n; f++)
13
Loop condition is true. Entering loop body
92 t += cescape_char(*f, t);
14
Calling 'cescape_char'
93
94 *t = 0;
95
96 return r;
97}
98
99char *cescape(const char *s) {
100 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/escape.c", 100, __PRETTY_FUNCTION__
); } while (0)
;
1
Assuming 's' is non-null
2
Taking false branch
3
Loop condition is false. Exiting loop
101
102 return cescape_length(s, strlen(s));
4
Calling 'cescape_length'
103}
104
105int cunescape_one(const char *p, size_t length, char32_t *ret, bool_Bool *eight_bit) {
106 int r = 1;
107
108 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/basic/escape.c", 108, __PRETTY_FUNCTION__
); } while (0)
;
109 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/basic/escape.c", 109, __PRETTY_FUNCTION__
); } while (0)
;
110
111 /* Unescapes C style. Returns the unescaped character in ret.
112 * Sets *eight_bit to true if the escaped sequence either fits in
113 * one byte in UTF-8 or is a non-unicode literal byte and should
114 * instead be copied directly.
115 */
116
117 if (length != (size_t) -1 && length < 1)
118 return -EINVAL22;
119
120 switch (p[0]) {
121
122 case 'a':
123 *ret = '\a';
124 break;
125 case 'b':
126 *ret = '\b';
127 break;
128 case 'f':
129 *ret = '\f';
130 break;
131 case 'n':
132 *ret = '\n';
133 break;
134 case 'r':
135 *ret = '\r';
136 break;
137 case 't':
138 *ret = '\t';
139 break;
140 case 'v':
141 *ret = '\v';
142 break;
143 case '\\':
144 *ret = '\\';
145 break;
146 case '"':
147 *ret = '"';
148 break;
149 case '\'':
150 *ret = '\'';
151 break;
152
153 case 's':
154 /* This is an extension of the XDG syntax files */
155 *ret = ' ';
156 break;
157
158 case 'x': {
159 /* hexadecimal encoding */
160 int a, b;
161
162 if (length != (size_t) -1 && length < 3)
163 return -EINVAL22;
164
165 a = unhexchar(p[1]);
166 if (a < 0)
167 return -EINVAL22;
168
169 b = unhexchar(p[2]);
170 if (b < 0)
171 return -EINVAL22;
172
173 /* Don't allow NUL bytes */
174 if (a == 0 && b == 0)
175 return -EINVAL22;
176
177 *ret = (a << 4U) | b;
178 *eight_bit = true1;
179 r = 3;
180 break;
181 }
182
183 case 'u': {
184 /* C++11 style 16bit unicode */
185
186 int a[4];
187 size_t i;
188 uint32_t c;
189
190 if (length != (size_t) -1 && length < 5)
191 return -EINVAL22;
192
193 for (i = 0; i < 4; i++) {
194 a[i] = unhexchar(p[1 + i]);
195 if (a[i] < 0)
196 return a[i];
197 }
198
199 c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3];
200
201 /* Don't allow 0 chars */
202 if (c == 0)
203 return -EINVAL22;
204
205 *ret = c;
206 r = 5;
207 break;
208 }
209
210 case 'U': {
211 /* C++11 style 32bit unicode */
212
213 int a[8];
214 size_t i;
215 char32_t c;
216
217 if (length != (size_t) -1 && length < 9)
218 return -EINVAL22;
219
220 for (i = 0; i < 8; i++) {
221 a[i] = unhexchar(p[1 + i]);
222 if (a[i] < 0)
223 return a[i];
224 }
225
226 c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) |
227 ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7];
228
229 /* Don't allow 0 chars */
230 if (c == 0)
231 return -EINVAL22;
232
233 /* Don't allow invalid code points */
234 if (!unichar_is_valid(c))
235 return -EINVAL22;
236
237 *ret = c;
238 r = 9;
239 break;
240 }
241
242 case '0':
243 case '1':
244 case '2':
245 case '3':
246 case '4':
247 case '5':
248 case '6':
249 case '7': {
250 /* octal encoding */
251 int a, b, c;
252 char32_t m;
253
254 if (length != (size_t) -1 && length < 3)
255 return -EINVAL22;
256
257 a = unoctchar(p[0]);
258 if (a < 0)
259 return -EINVAL22;
260
261 b = unoctchar(p[1]);
262 if (b < 0)
263 return -EINVAL22;
264
265 c = unoctchar(p[2]);
266 if (c < 0)
267 return -EINVAL22;
268
269 /* don't allow NUL bytes */
270 if (a == 0 && b == 0 && c == 0)
271 return -EINVAL22;
272
273 /* Don't allow bytes above 255 */
274 m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c;
275 if (m > 255)
276 return -EINVAL22;
277
278 *ret = m;
279 *eight_bit = true1;
280 r = 3;
281 break;
282 }
283
284 default:
285 return -EINVAL22;
286 }
287
288 return r;
289}
290
291int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) {
292 char *r, *t;
293 const char *f;
294 size_t pl;
295
296 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/escape.c", 296, __PRETTY_FUNCTION__
); } while (0)
;
297 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/basic/escape.c", 297, __PRETTY_FUNCTION__
); } while (0)
;
298
299 /* Undoes C style string escaping, and optionally prefixes it. */
300
301 pl = strlen_ptr(prefix);
302
303 r = new(char, pl+length+1)((char*) malloc_multiply(sizeof(char), (pl+length+1)));
304 if (!r)
305 return -ENOMEM12;
306
307 if (prefix)
308 memcpy(r, prefix, pl);
309
310 for (f = s, t = r + pl; f < s + length; f++) {
311 size_t remaining;
312 bool_Bool eight_bit = false0;
313 char32_t u;
314 int k;
315
316 remaining = s + length - f;
317 assert(remaining > 0)do { if ((__builtin_expect(!!(!(remaining > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("remaining > 0"), "../src/basic/escape.c"
, 317, __PRETTY_FUNCTION__); } while (0)
;
318
319 if (*f != '\\') {
320 /* A literal, copy verbatim */
321 *(t++) = *f;
322 continue;
323 }
324
325 if (remaining == 1) {
326 if (flags & UNESCAPE_RELAX) {
327 /* A trailing backslash, copy verbatim */
328 *(t++) = *f;
329 continue;
330 }
331
332 free(r);
333 return -EINVAL22;
334 }
335
336 k = cunescape_one(f + 1, remaining - 1, &u, &eight_bit);
337 if (k < 0) {
338 if (flags & UNESCAPE_RELAX) {
339 /* Invalid escape code, let's take it literal then */
340 *(t++) = '\\';
341 continue;
342 }
343
344 free(r);
345 return k;
346 }
347
348 f += k;
349 if (eight_bit)
350 /* One byte? Set directly as specified */
351 *(t++) = u;
352 else
353 /* Otherwise encode as multi-byte UTF-8 */
354 t += utf8_encode_unichar(t, u);
355 }
356
357 *t = 0;
358
359 *ret = r;
360 return t - r;
361}
362
363int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
364 return cunescape_length_with_prefix(s, length, NULL((void*)0), flags, ret);
365}
366
367int cunescape(const char *s, UnescapeFlags flags, char **ret) {
368 return cunescape_length(s, strlen(s), flags, ret);
369}
370
371char *xescape(const char *s, const char *bad) {
372 char *r, *t;
373 const char *f;
374
375 /* Escapes all chars in bad, in addition to \ and all special
376 * chars, in \xFF style escaping. May be reversed with
377 * cunescape(). */
378
379 r = new(char, strlen(s) * 4 + 1)((char*) malloc_multiply(sizeof(char), (strlen(s) * 4 + 1)));
380 if (!r)
381 return NULL((void*)0);
382
383 for (f = s, t = r; *f; f++) {
384
385 if ((*f < ' ') || (*f >= 127) ||
386 (*f == '\\') || strchr(bad, *f)) {
387 *(t++) = '\\';
388 *(t++) = 'x';
389 *(t++) = hexchar(*f >> 4);
390 *(t++) = hexchar(*f);
391 } else
392 *(t++) = *f;
393 }
394
395 *t = 0;
396
397 return r;
398}
399
400char *octescape(const char *s, size_t len) {
401 char *r, *t;
402 const char *f;
403
404 /* Escapes all chars in bad, in addition to \ and " chars,
405 * in \nnn style escaping. */
406
407 r = new(char, len * 4 + 1)((char*) malloc_multiply(sizeof(char), (len * 4 + 1)));
408 if (!r)
409 return NULL((void*)0);
410
411 for (f = s, t = r; f < s + len; f++) {
412
413 if (*f < ' ' || *f >= 127 || IN_SET(*f, '\\', '"')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){'\\', '"'})/sizeof(int)]; switch(*f) { case
'\\': case '"': _found = 1; break; default: break; } _found;
})
) {
414 *(t++) = '\\';
415 *(t++) = '0' + (*f >> 6);
416 *(t++) = '0' + ((*f >> 3) & 8);
417 *(t++) = '0' + (*f & 8);
418 } else
419 *(t++) = *f;
420 }
421
422 *t = 0;
423
424 return r;
425
426}
427
428static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad, bool_Bool escape_tab_nl) {
429 assert(bad)do { if ((__builtin_expect(!!(!(bad)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("bad"), "../src/basic/escape.c", 429, __PRETTY_FUNCTION__
); } while (0)
;
430
431 for (; *s; s++) {
432 if (escape_tab_nl && IN_SET(*s, '\n', '\t')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){'\n', '\t'})/sizeof(int)]; switch(*s) { case
'\n': case '\t': _found = 1; break; default: break; } _found
; })
) {
433 *(t++) = '\\';
434 *(t++) = *s == '\n' ? 'n' : 't';
435 continue;
436 }
437
438 if (*s == '\\' || strchr(bad, *s))
439 *(t++) = '\\';
440
441 *(t++) = *s;
442 }
443
444 return t;
445}
446
447char *shell_escape(const char *s, const char *bad) {
448 char *r, *t;
449
450 r = new(char, strlen(s)*2+1)((char*) malloc_multiply(sizeof(char), (strlen(s)*2+1)));
451 if (!r)
452 return NULL((void*)0);
453
454 t = strcpy_backslash_escaped(r, s, bad, false0);
455 *t = 0;
456
457 return r;
458}
459
460char* shell_maybe_quote(const char *s, EscapeStyle style) {
461 const char *p;
462 char *r, *t;
463
464 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/escape.c", 464, __PRETTY_FUNCTION__
); } while (0)
;
465
466 /* Encloses a string in quotes if necessary to make it OK as a shell
467 * string. Note that we treat benign UTF-8 characters as needing
468 * escaping too, but that should be OK. */
469
470 for (p = s; *p; p++)
471 if (*p <= ' ' ||
472 *p >= 127 ||
473 strchr(SHELL_NEED_QUOTES"\"\\`$" "*?[" "'()<>|&;!", *p))
474 break;
475
476 if (!*p)
477 return strdup(s);
478
479 r = new(char, (style == ESCAPE_POSIX) + 1 + strlen(s)*2 + 1 + 1)((char*) malloc_multiply(sizeof(char), ((style == ESCAPE_POSIX
) + 1 + strlen(s)*2 + 1 + 1)))
;
480 if (!r)
481 return NULL((void*)0);
482
483 t = r;
484 if (style == ESCAPE_BACKSLASH)
485 *(t++) = '"';
486 else if (style == ESCAPE_POSIX) {
487 *(t++) = '$';
488 *(t++) = '\'';
489 } else
490 assert_not_reached("Bad EscapeStyle")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, (
"Bad EscapeStyle"), "../src/basic/escape.c", 490, __PRETTY_FUNCTION__
); } while (0)
;
491
492 t = mempcpy(t, s, p - s);
493
494 if (style == ESCAPE_BACKSLASH)
495 t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE"\"\\`$", false0);
496 else
497 t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE_POSIX"\\\'", true1);
498
499 if (style == ESCAPE_BACKSLASH)
500 *(t++) = '"';
501 else
502 *(t++) = '\'';
503 *t = 0;
504
505 return r;
506}

../src/basic/alloc-util.h

1/* SPDX-License-Identifier: LGPL-2.1+ */
2#pragma once
3
4#include <alloca.h>
5#include <stddef.h>
6#include <stdlib.h>
7#include <string.h>
8
9#include "macro.h"
10
11#define new(t, n)((t*) malloc_multiply(sizeof(t), (n))) ((t*) malloc_multiply(sizeof(t), (n)))
12
13#define new0(t, n)((t*) calloc((n), sizeof(t))) ((t*) calloc((n), sizeof(t)))
14
15#define newa(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 15, __PRETTY_FUNCTION__); } while
(0); (t*) __builtin_alloca (sizeof(t)*(n)); })
\
16 ({ \
17 assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 17, __PRETTY_FUNCTION__); } while
(0)
; \
18 (t*) alloca(sizeof(t)*(n))__builtin_alloca (sizeof(t)*(n)); \
19 })
20
21#define newa0(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 21, __PRETTY_FUNCTION__); } while
(0); (t*) ({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_
= __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_)
; }); })
\
22 ({ \
23 assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 23, __PRETTY_FUNCTION__); } while
(0)
; \
24 (t*) alloca0(sizeof(t)*(n))({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca
(_len_); (void *) memset(_new_, 0, _len_); })
; \
25 })
26
27#define newdup(t, p, n)((t*) memdup_multiply(p, sizeof(t), (n))) ((t*) memdup_multiply(p, sizeof(t), (n)))
28
29#define newdup_suffix0(t, p, n)((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n)))
30
31#define malloc0(n)(calloc(1, (n))) (calloc(1, (n)))
32
33static inline void *mfree(void *memory) {
34 free(memory);
35 return NULL((void*)0);
36}
37
38#define free_and_replace(a, b)({ free(a); (a) = (b); (b) = ((void*)0); 0; }) \
39 ({ \
40 free(a); \
41 (a) = (b); \
42 (b) = NULL((void*)0); \
43 0; \
44 })
45
46void* memdup(const void *p, size_t l) _alloc_(2);
47void* memdup_suffix0(const void *p, size_t l) _alloc_(2);
48
49static inline void freep(void *p) {
50 free(*(void**) p);
51}
52
53#define _cleanup_free___attribute__((cleanup(freep))) _cleanup_(freep)__attribute__((cleanup(freep)))
54
55static inline bool_Bool size_multiply_overflow(size_t size, size_t need) {
56 return _unlikely_(need != 0 && size > (SIZE_MAX / need))(__builtin_expect(!!(need != 0 && size > ((18446744073709551615UL
) / need)),0))
;
57}
58
59_malloc___attribute__ ((malloc)) _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) {
60 if (size_multiply_overflow(size, need))
8
Taking false branch
61 return NULL((void*)0);
62
63 return malloc(size * need);
9
Memory is allocated
64}
65
66#if !HAVE_REALLOCARRAY1
67_alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) {
68 if (size_multiply_overflow(size, need))
69 return NULL((void*)0);
70
71 return realloc(p, size * need);
72}
73#endif
74
75_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) {
76 if (size_multiply_overflow(size, need))
77 return NULL((void*)0);
78
79 return memdup(p, size * need);
80}
81
82_alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) {
83 if (size_multiply_overflow(size, need))
84 return NULL((void*)0);
85
86 return memdup_suffix0(p, size * need);
87}
88
89void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
90void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
91
92#define GREEDY_REALLOC(array, allocated, need)greedy_realloc((void**) &(array), &(allocated), (need
), sizeof((array)[0]))
\
93 greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0]))
94
95#define GREEDY_REALLOC0(array, allocated, need)greedy_realloc0((void**) &(array), &(allocated), (need
), sizeof((array)[0]))
\
96 greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0]))
97
98#define alloca0(n)({ char *_new_; size_t _len_ = n; _new_ = __builtin_alloca (_len_
); (void *) memset(_new_, 0, _len_); })
\
99 ({ \
100 char *_new_; \
101 size_t _len_ = n; \
102 _new_ = alloca(_len_)__builtin_alloca (_len_); \
103 (void *) memset(_new_, 0, _len_); \
104 })
105
106/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
107#define alloca_align(size, align)({ void *_ptr_; size_t _mask_ = (align) - 1; _ptr_ = __builtin_alloca
((size) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) &
~_mask_); })
\
108 ({ \
109 void *_ptr_; \
110 size_t _mask_ = (align) - 1; \
111 _ptr_ = alloca((size) + _mask_)__builtin_alloca ((size) + _mask_); \
112 (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \
113 })
114
115#define alloca0_align(size, align)({ void *_new_; size_t _size_ = (size); _new_ = ({ void *_ptr_
; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_
) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_
); }); (void*)memset(_new_, 0, _size_); })
\
116 ({ \
117 void *_new_; \
118 size_t _size_ = (size); \
119 _new_ = alloca_align(_size_, (align))({ void *_ptr_; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca
((_size_) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) &
~_mask_); })
; \
120 (void*)memset(_new_, 0, _size_); \
121 })
122
123/* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to
124 * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
125#define TAKE_PTR(ptr)({ typeof(ptr) _ptr_ = (ptr); (ptr) = ((void*)0); _ptr_; }) \
126 ({ \
127 typeof(ptr) _ptr_ = (ptr); \
128 (ptr) = NULL((void*)0); \
129 _ptr_; \
130 })