File: | build-scan/../src/basic/escape.c |
Warning: | line 33, column 34 Use of zero-allocated memory |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
13 | int 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) { | |||
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++) = '\\'; | |||
| ||||
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 | ||||
78 | char *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); | |||
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))); | |||
88 | if (!r) | |||
89 | return NULL((void*)0); | |||
90 | ||||
91 | for (f = s, t = r; f < s + n; f++) | |||
92 | t += cescape_char(*f, t); | |||
93 | ||||
94 | *t = 0; | |||
95 | ||||
96 | return r; | |||
97 | } | |||
98 | ||||
99 | char *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); | |||
| ||||
101 | ||||
102 | return cescape_length(s, strlen(s)); | |||
103 | } | |||
104 | ||||
105 | int 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 | ||||
291 | int 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 | ||||
363 | int 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 | ||||
367 | int cunescape(const char *s, UnescapeFlags flags, char **ret) { | |||
368 | return cunescape_length(s, strlen(s), flags, ret); | |||
369 | } | |||
370 | ||||
371 | char *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 | ||||
400 | char *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 | ||||
428 | static 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 | ||||
447 | char *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 | ||||
460 | char* 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 | } |
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 | |
33 | static 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 | |
46 | void* memdup(const void *p, size_t l) _alloc_(2); |
47 | void* memdup_suffix0(const void *p, size_t l) _alloc_(2); |
48 | |
49 | static inline void freep(void *p) { |
50 | free(*(void**) p); |
51 | } |
52 | |
53 | #define _cleanup_free___attribute__((cleanup(freep))) _cleanup_(freep)__attribute__((cleanup(freep))) |
54 | |
55 | static 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)) |
61 | return NULL((void*)0); |
62 | |
63 | return malloc(size * need); |
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 | |
89 | void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); |
90 | void* 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 | }) |