Bug Summary

File:build-scan/../src/basic/strv.c
Warning:line 446, column 21
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 strv.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/strv.c

../src/basic/strv.c

1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <errno(*__errno_location ()).h>
4#include <fnmatch.h>
5#include <stdarg.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9
10#include "alloc-util.h"
11#include "escape.h"
12#include "extract-word.h"
13#include "fileio.h"
14#include "string-util.h"
15#include "strv.h"
16#include "util.h"
17
18char *strv_find(char **l, const char *name) {
19 char **i;
20
21 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/basic/strv.c", 21, __PRETTY_FUNCTION__
); } while (0)
;
22
23 STRV_FOREACH(i, l)for ((i) = (l); (i) && *(i); (i)++)
24 if (streq(*i, name)(strcmp((*i),(name)) == 0))
25 return *i;
26
27 return NULL((void*)0);
28}
29
30char *strv_find_prefix(char **l, const char *name) {
31 char **i;
32
33 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/basic/strv.c", 33, __PRETTY_FUNCTION__
); } while (0)
;
34
35 STRV_FOREACH(i, l)for ((i) = (l); (i) && *(i); (i)++)
36 if (startswith(*i, name))
37 return *i;
38
39 return NULL((void*)0);
40}
41
42char *strv_find_startswith(char **l, const char *name) {
43 char **i, *e;
44
45 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/basic/strv.c", 45, __PRETTY_FUNCTION__
); } while (0)
;
46
47 /* Like strv_find_prefix, but actually returns only the
48 * suffix, not the whole item */
49
50 STRV_FOREACH(i, l)for ((i) = (l); (i) && *(i); (i)++) {
51 e = startswith(*i, name);
52 if (e)
53 return e;
54 }
55
56 return NULL((void*)0);
57}
58
59void strv_clear(char **l) {
60 char **k;
61
62 if (!l)
63 return;
64
65 for (k = l; *k; k++)
66 free(*k);
67
68 *l = NULL((void*)0);
69}
70
71char **strv_free(char **l) {
72 strv_clear(l);
73 return mfree(l);
74}
75
76char **strv_free_erase(char **l) {
77 char **i;
78
79 STRV_FOREACH(i, l)for ((i) = (l); (i) && *(i); (i)++)
80 string_erase(*i);
81
82 return strv_free(l);
83}
84
85char **strv_copy(char * const *l) {
86 char **r, **k;
87
88 k = r = new(char*, strv_length(l) + 1)((char**) malloc_multiply(sizeof(char*), (strv_length(l) + 1)
))
;
89 if (!r)
90 return NULL((void*)0);
91
92 if (l)
93 for (; *l; k++, l++) {
94 *k = strdup(*l);
95 if (!*k) {
96 strv_free(r);
97 return NULL((void*)0);
98 }
99 }
100
101 *k = NULL((void*)0);
102 return r;
103}
104
105size_t strv_length(char * const *l) {
106 size_t n = 0;
107
108 if (!l)
109 return 0;
110
111 for (; *l; l++)
112 n++;
113
114 return n;
115}
116
117char **strv_new_ap(const char *x, va_list ap) {
118 const char *s;
119 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **a = NULL((void*)0);
120 size_t n = 0, i = 0;
121 va_list aq;
122
123 /* As a special trick we ignore all listed strings that equal
124 * STRV_IGNORE. This is supposed to be used with the
125 * STRV_IFNOTNULL() macro to include possibly NULL strings in
126 * the string list. */
127
128 if (x) {
129 n = x == STRV_IGNORE((const char *) -1) ? 0 : 1;
130
131 va_copy(aq, ap)__builtin_va_copy(aq, ap);
132 while ((s = va_arg(aq, const char*)__builtin_va_arg(aq, const char*))) {
133 if (s == STRV_IGNORE((const char *) -1))
134 continue;
135
136 n++;
137 }
138
139 va_end(aq)__builtin_va_end(aq);
140 }
141
142 a = new(char*, n+1)((char**) malloc_multiply(sizeof(char*), (n+1)));
143 if (!a)
144 return NULL((void*)0);
145
146 if (x) {
147 if (x != STRV_IGNORE((const char *) -1)) {
148 a[i] = strdup(x);
149 if (!a[i])
150 return NULL((void*)0);
151 i++;
152 }
153
154 while ((s = va_arg(ap, const char*)__builtin_va_arg(ap, const char*))) {
155
156 if (s == STRV_IGNORE((const char *) -1))
157 continue;
158
159 a[i] = strdup(s);
160 if (!a[i])
161 return NULL((void*)0);
162
163 i++;
164 }
165 }
166
167 a[i] = NULL((void*)0);
168
169 return TAKE_PTR(a)({ typeof(a) _ptr_ = (a); (a) = ((void*)0); _ptr_; });
170}
171
172char **strv_new(const char *x, ...) {
173 char **r;
174 va_list ap;
175
176 va_start(ap, x)__builtin_va_start(ap, x);
177 r = strv_new_ap(x, ap);
178 va_end(ap)__builtin_va_end(ap);
179
180 return r;
181}
182
183int strv_extend_strv(char ***a, char **b, bool_Bool filter_duplicates) {
184 char **s, **t;
185 size_t p, q, i = 0, j;
186
187 assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("a"), "../src/basic/strv.c", 187, __PRETTY_FUNCTION__
); } while (0)
;
188
189 if (strv_isempty(b))
190 return 0;
191
192 p = strv_length(*a);
193 q = strv_length(b);
194
195 t = reallocarray(*a, p + q + 1, sizeof(char *));
196 if (!t)
197 return -ENOMEM12;
198
199 t[p] = NULL((void*)0);
200 *a = t;
201
202 STRV_FOREACH(s, b)for ((s) = (b); (s) && *(s); (s)++) {
203
204 if (filter_duplicates && strv_contains(t, *s)(!!strv_find((t), (*s))))
205 continue;
206
207 t[p+i] = strdup(*s);
208 if (!t[p+i])
209 goto rollback;
210
211 i++;
212 t[p+i] = NULL((void*)0);
213 }
214
215 assert(i <= q)do { if ((__builtin_expect(!!(!(i <= q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i <= q"), "../src/basic/strv.c", 215
, __PRETTY_FUNCTION__); } while (0)
;
216
217 return (int) i;
218
219rollback:
220 for (j = 0; j < i; j++)
221 free(t[p + j]);
222
223 t[p] = NULL((void*)0);
224 return -ENOMEM12;
225}
226
227int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
228 int r;
229 char **s;
230
231 STRV_FOREACH(s, b)for ((s) = (b); (s) && *(s); (s)++) {
232 char *v;
233
234 v = strappend(*s, suffix);
235 if (!v)
236 return -ENOMEM12;
237
238 r = strv_push(a, v);
239 if (r < 0) {
240 free(v);
241 return r;
242 }
243 }
244
245 return 0;
246}
247
248char **strv_split(const char *s, const char *separator) {
249 const char *word, *state;
250 size_t l;
251 size_t n, i;
252 char **r;
253
254 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/strv.c", 254, __PRETTY_FUNCTION__
); } while (0)
;
255
256 n = 0;
257 FOREACH_WORD_SEPARATOR(word, l, s, separator, state)for ((state) = (s), (word) = split(&(state), &(l), (separator
), (0)); (word); (word) = split(&(state), &(l), (separator
), (0)))
258 n++;
259
260 r = new(char*, n+1)((char**) malloc_multiply(sizeof(char*), (n+1)));
261 if (!r)
262 return NULL((void*)0);
263
264 i = 0;
265 FOREACH_WORD_SEPARATOR(word, l, s, separator, state)for ((state) = (s), (word) = split(&(state), &(l), (separator
), (0)); (word); (word) = split(&(state), &(l), (separator
), (0)))
{
266 r[i] = strndup(word, l);
267 if (!r[i]) {
268 strv_free(r);
269 return NULL((void*)0);
270 }
271
272 i++;
273 }
274
275 r[i] = NULL((void*)0);
276 return r;
277}
278
279char **strv_split_newlines(const char *s) {
280 char **l;
281 size_t n;
282
283 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/strv.c", 283, __PRETTY_FUNCTION__
); } while (0)
;
284
285 /* Special version of strv_split() that splits on newlines and
286 * suppresses an empty string at the end */
287
288 l = strv_split(s, NEWLINE"\n\r");
289 if (!l)
290 return NULL((void*)0);
291
292 n = strv_length(l);
293 if (n <= 0)
294 return l;
295
296 if (isempty(l[n - 1]))
297 l[n - 1] = mfree(l[n - 1]);
298
299 return l;
300}
301
302int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) {
303 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **l = NULL((void*)0);
304 size_t n = 0, allocated = 0;
305 int r;
306
307 assert(t)do { if ((__builtin_expect(!!(!(t)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("t"), "../src/basic/strv.c", 307, __PRETTY_FUNCTION__
); } while (0)
;
308 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/strv.c", 308, __PRETTY_FUNCTION__
); } while (0)
;
309
310 for (;;) {
311 _cleanup_free___attribute__((cleanup(freep))) char *word = NULL((void*)0);
312
313 r = extract_first_word(&s, &word, separators, flags);
314 if (r < 0)
315 return r;
316 if (r == 0)
317 break;
318
319 if (!GREEDY_REALLOC(l, allocated, n + 2)greedy_realloc((void**) &(l), &(allocated), (n + 2), sizeof
((l)[0]))
)
320 return -ENOMEM12;
321
322 l[n++] = TAKE_PTR(word)({ typeof(word) _ptr_ = (word); (word) = ((void*)0); _ptr_; }
)
;
323
324 l[n] = NULL((void*)0);
325 }
326
327 if (!l) {
328 l = new0(char*, 1)((char**) calloc((1), sizeof(char*)));
329 if (!l)
330 return -ENOMEM12;
331 }
332
333 *t = TAKE_PTR(l)({ typeof(l) _ptr_ = (l); (l) = ((void*)0); _ptr_; });
334
335 return (int) n;
336}
337
338char *strv_join(char **l, const char *separator) {
339 char *r, *e;
340 char **s;
341 size_t n, k;
342
343 if (!separator)
344 separator = " ";
345
346 k = strlen(separator);
347
348 n = 0;
349 STRV_FOREACH(s, l)for ((s) = (l); (s) && *(s); (s)++) {
350 if (s != l)
351 n += k;
352 n += strlen(*s);
353 }
354
355 r = new(char, n+1)((char*) malloc_multiply(sizeof(char), (n+1)));
356 if (!r)
357 return NULL((void*)0);
358
359 e = r;
360 STRV_FOREACH(s, l)for ((s) = (l); (s) && *(s); (s)++) {
361 if (s != l)
362 e = stpcpy(e, separator);
363
364 e = stpcpy(e, *s);
365 }
366
367 *e = 0;
368
369 return r;
370}
371
372int strv_push(char ***l, char *value) {
373 char **c;
374 size_t n, m;
375
376 if (!value)
377 return 0;
378
379 n = strv_length(*l);
380
381 /* Increase and check for overflow */
382 m = n + 2;
383 if (m < n)
384 return -ENOMEM12;
385
386 c = reallocarray(*l, m, sizeof(char*));
387 if (!c)
388 return -ENOMEM12;
389
390 c[n] = value;
391 c[n+1] = NULL((void*)0);
392
393 *l = c;
394 return 0;
395}
396
397int strv_push_pair(char ***l, char *a, char *b) {
398 char **c;
399 size_t n, m;
400
401 if (!a && !b)
402 return 0;
403
404 n = strv_length(*l);
405
406 /* increase and check for overflow */
407 m = n + !!a + !!b + 1;
408 if (m < n)
409 return -ENOMEM12;
410
411 c = reallocarray(*l, m, sizeof(char*));
412 if (!c)
413 return -ENOMEM12;
414
415 if (a)
416 c[n++] = a;
417 if (b)
418 c[n++] = b;
419 c[n] = NULL((void*)0);
420
421 *l = c;
422 return 0;
423}
424
425int strv_insert(char ***l, size_t position, char *value) {
426 char **c;
427 size_t n, m, i;
428
429 if (!value)
3
Assuming 'value' is non-null
4
Taking false branch
430 return 0;
431
432 n = strv_length(*l);
433 position = MIN(position, n)__extension__ ({ const typeof((position)) __unique_prefix_A10
= ((position)); const typeof((n)) __unique_prefix_B11 = ((n)
); __unique_prefix_A10 < __unique_prefix_B11 ? __unique_prefix_A10
: __unique_prefix_B11; })
;
5
Assuming '__unique_prefix_A0' is < '__unique_prefix_B1'
6
'?' condition is true
434
435 /* increase and check for overflow */
436 m = n + 2;
437 if (m < n)
7
Assuming 'm' is >= 'n'
8
Taking false branch
438 return -ENOMEM12;
439
440 c = new(char*, m)((char**) malloc_multiply(sizeof(char*), (m)));
9
Calling 'malloc_multiply'
12
Returned allocated memory
441 if (!c)
13
Assuming 'c' is non-null
14
Taking false branch
442 return -ENOMEM12;
443
444 for (i = 0; i < position; i++)
15
Loop condition is false. Execution continues on line 446
445 c[i] = (*l)[i];
446 c[position] = value;
16
Use of zero-allocated memory
447 for (i = position; i < n; i++)
448 c[i+1] = (*l)[i];
449
450 c[n+1] = NULL((void*)0);
451
452 free(*l);
453 *l = c;
454
455 return 0;
456}
457
458int strv_consume(char ***l, char *value) {
459 int r;
460
461 r = strv_push(l, value);
462 if (r < 0)
463 free(value);
464
465 return r;
466}
467
468int strv_consume_pair(char ***l, char *a, char *b) {
469 int r;
470
471 r = strv_push_pair(l, a, b);
472 if (r < 0) {
473 free(a);
474 free(b);
475 }
476
477 return r;
478}
479
480int strv_consume_prepend(char ***l, char *value) {
481 int r;
482
483 r = strv_push_prepend(l, value);
1
Calling 'strv_push_prepend'
484 if (r < 0)
485 free(value);
486
487 return r;
488}
489
490int strv_extend(char ***l, const char *value) {
491 char *v;
492
493 if (!value)
494 return 0;
495
496 v = strdup(value);
497 if (!v)
498 return -ENOMEM12;
499
500 return strv_consume(l, v);
501}
502
503int strv_extend_front(char ***l, const char *value) {
504 size_t n, m;
505 char *v, **c;
506
507 assert(l)do { if ((__builtin_expect(!!(!(l)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("l"), "../src/basic/strv.c", 507, __PRETTY_FUNCTION__
); } while (0)
;
508
509 /* Like strv_extend(), but prepends rather than appends the new entry */
510
511 if (!value)
512 return 0;
513
514 n = strv_length(*l);
515
516 /* Increase and overflow check. */
517 m = n + 2;
518 if (m < n)
519 return -ENOMEM12;
520
521 v = strdup(value);
522 if (!v)
523 return -ENOMEM12;
524
525 c = reallocarray(*l, m, sizeof(char*));
526 if (!c) {
527 free(v);
528 return -ENOMEM12;
529 }
530
531 memmove(c+1, c, n * sizeof(char*));
532 c[0] = v;
533 c[n+1] = NULL((void*)0);
534
535 *l = c;
536 return 0;
537}
538
539char **strv_uniq(char **l) {
540 char **i;
541
542 /* Drops duplicate entries. The first identical string will be
543 * kept, the others dropped */
544
545 STRV_FOREACH(i, l)for ((i) = (l); (i) && *(i); (i)++)
546 strv_remove(i+1, *i);
547
548 return l;
549}
550
551bool_Bool strv_is_uniq(char **l) {
552 char **i;
553
554 STRV_FOREACH(i, l)for ((i) = (l); (i) && *(i); (i)++)
555 if (strv_find(i+1, *i))
556 return false0;
557
558 return true1;
559}
560
561char **strv_remove(char **l, const char *s) {
562 char **f, **t;
563
564 if (!l)
565 return NULL((void*)0);
566
567 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/strv.c", 567, __PRETTY_FUNCTION__
); } while (0)
;
568
569 /* Drops every occurrence of s in the string list, edits
570 * in-place. */
571
572 for (f = t = l; *f; f++)
573 if (streq(*f, s)(strcmp((*f),(s)) == 0))
574 free(*f);
575 else
576 *(t++) = *f;
577
578 *t = NULL((void*)0);
579 return l;
580}
581
582char **strv_parse_nulstr(const char *s, size_t l) {
583 /* l is the length of the input data, which will be split at NULs into
584 * elements of the resulting strv. Hence, the number of items in the resulting strv
585 * will be equal to one plus the number of NUL bytes in the l bytes starting at s,
586 * unless s[l-1] is NUL, in which case the final empty string is not stored in
587 * the resulting strv, and length is equal to the number of NUL bytes.
588 *
589 * Note that contrary to a normal nulstr which cannot contain empty strings, because
590 * the input data is terminated by any two consequent NUL bytes, this parser accepts
591 * empty strings in s.
592 */
593
594 const char *p;
595 size_t c = 0, i = 0;
596 char **v;
597
598 assert(s || l <= 0)do { if ((__builtin_expect(!!(!(s || l <= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s || l <= 0"), "../src/basic/strv.c"
, 598, __PRETTY_FUNCTION__); } while (0)
;
599
600 if (l <= 0)
601 return new0(char*, 1)((char**) calloc((1), sizeof(char*)));
602
603 for (p = s; p < s + l; p++)
604 if (*p == 0)
605 c++;
606
607 if (s[l-1] != 0)
608 c++;
609
610 v = new0(char*, c+1)((char**) calloc((c+1), sizeof(char*)));
611 if (!v)
612 return NULL((void*)0);
613
614 p = s;
615 while (p < s + l) {
616 const char *e;
617
618 e = memchr(p, 0, s + l - p);
619
620 v[i] = strndup(p, e ? e - p : s + l - p);
621 if (!v[i]) {
622 strv_free(v);
623 return NULL((void*)0);
624 }
625
626 i++;
627
628 if (!e)
629 break;
630
631 p = e + 1;
632 }
633
634 assert(i == c)do { if ((__builtin_expect(!!(!(i == c)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i == c"), "../src/basic/strv.c", 634, __PRETTY_FUNCTION__
); } while (0)
;
635
636 return v;
637}
638
639char **strv_split_nulstr(const char *s) {
640 const char *i;
641 char **r = NULL((void*)0);
642
643 NULSTR_FOREACH(i, s)for ((i) = (s); (i) && *(i); (i) = strchr((i), 0)+1)
644 if (strv_extend(&r, i) < 0) {
645 strv_free(r);
646 return NULL((void*)0);
647 }
648
649 if (!r)
650 return strv_new(NULL((void*)0), NULL((void*)0));
651
652 return r;
653}
654
655int strv_make_nulstr(char **l, char **p, size_t *q) {
656 /* A valid nulstr with two NULs at the end will be created, but
657 * q will be the length without the two trailing NULs. Thus the output
658 * string is a valid nulstr and can be iterated over using NULSTR_FOREACH,
659 * and can also be parsed by strv_parse_nulstr as long as the length
660 * is provided separately.
661 */
662
663 size_t n_allocated = 0, n = 0;
664 _cleanup_free___attribute__((cleanup(freep))) char *m = NULL((void*)0);
665 char **i;
666
667 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/basic/strv.c", 667, __PRETTY_FUNCTION__
); } while (0)
;
668 assert(q)do { if ((__builtin_expect(!!(!(q)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("q"), "../src/basic/strv.c", 668, __PRETTY_FUNCTION__
); } while (0)
;
669
670 STRV_FOREACH(i, l)for ((i) = (l); (i) && *(i); (i)++) {
671 size_t z;
672
673 z = strlen(*i);
674
675 if (!GREEDY_REALLOC(m, n_allocated, n + z + 2)greedy_realloc((void**) &(m), &(n_allocated), (n + z +
2), sizeof((m)[0]))
)
676 return -ENOMEM12;
677
678 memcpy(m + n, *i, z + 1);
679 n += z + 1;
680 }
681
682 if (!m) {
683 m = new0(char, 1)((char*) calloc((1), sizeof(char)));
684 if (!m)
685 return -ENOMEM12;
686 n = 1;
687 } else
688 /* make sure there is a second extra NUL at the end of resulting nulstr */
689 m[n] = '\0';
690
691 assert(n > 0)do { if ((__builtin_expect(!!(!(n > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("n > 0"), "../src/basic/strv.c", 691,
__PRETTY_FUNCTION__); } while (0)
;
692 *p = m;
693 *q = n - 1;
694
695 m = NULL((void*)0);
696
697 return 0;
698}
699
700bool_Bool strv_overlap(char **a, char **b) {
701 char **i;
702
703 STRV_FOREACH(i, a)for ((i) = (a); (i) && *(i); (i)++)
704 if (strv_contains(b, *i)(!!strv_find((b), (*i))))
705 return true1;
706
707 return false0;
708}
709
710static int str_compare(const void *_a, const void *_b) {
711 const char **a = (const char**) _a, **b = (const char**) _b;
712
713 return strcmp(*a, *b);
714}
715
716char **strv_sort(char **l) {
717 qsort_safe(l, strv_length(l), sizeof(char*), str_compare);
718 return l;
719}
720
721bool_Bool strv_equal(char **a, char **b) {
722
723 if (strv_isempty(a))
724 return strv_isempty(b);
725
726 if (strv_isempty(b))
727 return false0;
728
729 for ( ; *a || *b; ++a, ++b)
730 if (!streq_ptr(*a, *b))
731 return false0;
732
733 return true1;
734}
735
736void strv_print(char **l) {
737 char **s;
738
739 STRV_FOREACH(s, l)for ((s) = (l); (s) && *(s); (s)++)
740 puts(*s);
741}
742
743int strv_extendf(char ***l, const char *format, ...) {
744 va_list ap;
745 char *x;
746 int r;
747
748 va_start(ap, format)__builtin_va_start(ap, format);
749 r = vasprintf(&x, format, ap);
750 va_end(ap)__builtin_va_end(ap);
751
752 if (r < 0)
753 return -ENOMEM12;
754
755 return strv_consume(l, x);
756}
757
758char **strv_reverse(char **l) {
759 size_t n, i;
760
761 n = strv_length(l);
762 if (n <= 1)
763 return l;
764
765 for (i = 0; i < n / 2; i++)
766 SWAP_TWO(l[i], l[n-1-i])do { typeof(l[i]) _t = (l[i]); (l[i]) = (l[n-1-i]); (l[n-1-i]
) = (_t); } while (0)
;
767
768 return l;
769}
770
771char **strv_shell_escape(char **l, const char *bad) {
772 char **s;
773
774 /* Escapes every character in every string in l that is in bad,
775 * edits in-place, does not roll-back on error. */
776
777 STRV_FOREACH(s, l)for ((s) = (l); (s) && *(s); (s)++) {
778 char *v;
779
780 v = shell_escape(*s, bad);
781 if (!v)
782 return NULL((void*)0);
783
784 free(*s);
785 *s = v;
786 }
787
788 return l;
789}
790
791bool_Bool strv_fnmatch(char* const* patterns, const char *s, int flags) {
792 char* const* p;
793
794 STRV_FOREACH(p, patterns)for ((p) = (patterns); (p) && *(p); (p)++)
795 if (fnmatch(*p, s, flags) == 0)
796 return true1;
797
798 return false0;
799}
800
801char ***strv_free_free(char ***l) {
802 char ***i;
803
804 if (!l)
805 return NULL((void*)0);
806
807 for (i = l; *i; i++)
808 strv_free(*i);
809
810 return mfree(l);
811}
812
813char **strv_skip(char **l, size_t n) {
814
815 while (n > 0) {
816 if (strv_isempty(l))
817 return l;
818
819 l++, n--;
820 }
821
822 return l;
823}
824
825int strv_extend_n(char ***l, const char *value, size_t n) {
826 size_t i, j, k;
827 char **nl;
828
829 assert(l)do { if ((__builtin_expect(!!(!(l)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("l"), "../src/basic/strv.c", 829, __PRETTY_FUNCTION__
); } while (0)
;
830
831 if (!value)
832 return 0;
833 if (n == 0)
834 return 0;
835
836 /* Adds the value n times to l */
837
838 k = strv_length(*l);
839
840 nl = reallocarray(*l, k + n + 1, sizeof(char *));
841 if (!nl)
842 return -ENOMEM12;
843
844 *l = nl;
845
846 for (i = k; i < k + n; i++) {
847 nl[i] = strdup(value);
848 if (!nl[i])
849 goto rollback;
850 }
851
852 nl[i] = NULL((void*)0);
853 return 0;
854
855rollback:
856 for (j = k; j < i; j++)
857 free(nl[j]);
858
859 nl[k] = NULL((void*)0);
860 return -ENOMEM12;
861}
862
863int fputstrv(FILE *f, char **l, const char *separator, bool_Bool *space) {
864 bool_Bool b = false0;
865 char **s;
866 int r;
867
868 /* Like fputs(), but for strv, and with a less stupid argument order */
869
870 if (!space)
871 space = &b;
872
873 STRV_FOREACH(s, l)for ((s) = (l); (s) && *(s); (s)++) {
874 r = fputs_with_space(f, *s, separator, space);
875 if (r < 0)
876 return r;
877 }
878
879 return 0;
880}

../src/basic/strv.h

1/* SPDX-License-Identifier: LGPL-2.1+ */
2#pragma once
3
4#include <fnmatch.h>
5#include <stdarg.h>
6#include <stdbool.h>
7#include <stddef.h>
8
9#include "alloc-util.h"
10#include "extract-word.h"
11#include "macro.h"
12#include "util.h"
13
14char *strv_find(char **l, const char *name) _pure___attribute__ ((pure));
15char *strv_find_prefix(char **l, const char *name) _pure___attribute__ ((pure));
16char *strv_find_startswith(char **l, const char *name) _pure___attribute__ ((pure));
17
18char **strv_free(char **l);
19DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free)static inline void strv_freep(char** *p) { if (*p) strv_free(
*p); }
;
20#define _cleanup_strv_free___attribute__((cleanup(strv_freep))) _cleanup_(strv_freep)__attribute__((cleanup(strv_freep)))
21
22char **strv_free_erase(char **l);
23DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase)static inline void strv_free_erasep(char** *p) { if (*p) strv_free_erase
(*p); }
;
24#define _cleanup_strv_free_erase___attribute__((cleanup(strv_free_erasep))) _cleanup_(strv_free_erasep)__attribute__((cleanup(strv_free_erasep)))
25
26void strv_clear(char **l);
27
28char **strv_copy(char * const *l);
29size_t strv_length(char * const *l) _pure___attribute__ ((pure));
30
31int strv_extend_strv(char ***a, char **b, bool_Bool filter_duplicates);
32int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
33int strv_extend(char ***l, const char *value);
34int strv_extendf(char ***l, const char *format, ...) _printf_(2,0)__attribute__ ((format (printf, 2, 0)));
35int strv_extend_front(char ***l, const char *value);
36int strv_push(char ***l, char *value);
37int strv_push_pair(char ***l, char *a, char *b);
38int strv_insert(char ***l, size_t position, char *value);
39
40static inline int strv_push_prepend(char ***l, char *value) {
41 return strv_insert(l, 0, value);
2
Calling 'strv_insert'
42}
43
44int strv_consume(char ***l, char *value);
45int strv_consume_pair(char ***l, char *a, char *b);
46int strv_consume_prepend(char ***l, char *value);
47
48char **strv_remove(char **l, const char *s);
49char **strv_uniq(char **l);
50bool_Bool strv_is_uniq(char **l);
51
52bool_Bool strv_equal(char **a, char **b);
53
54#define strv_contains(l, s)(!!strv_find((l), (s))) (!!strv_find((l), (s)))
55
56char **strv_new(const char *x, ...) _sentinel___attribute__ ((sentinel));
57char **strv_new_ap(const char *x, va_list ap);
58
59#define STRV_IGNORE((const char *) -1) ((const char *) -1)
60
61static inline const char* STRV_IFNOTNULL(const char *x) {
62 return x ? x : STRV_IGNORE((const char *) -1);
63}
64
65static inline bool_Bool strv_isempty(char * const *l) {
66 return !l || !*l;
67}
68
69char **strv_split(const char *s, const char *separator);
70char **strv_split_newlines(const char *s);
71
72int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags);
73
74char *strv_join(char **l, const char *separator);
75
76char **strv_parse_nulstr(const char *s, size_t l);
77char **strv_split_nulstr(const char *s);
78int strv_make_nulstr(char **l, char **p, size_t *n);
79
80bool_Bool strv_overlap(char **a, char **b) _pure___attribute__ ((pure));
81
82#define STRV_FOREACH(s, l)for ((s) = (l); (s) && *(s); (s)++) \
83 for ((s) = (l); (s) && *(s); (s)++)
84
85#define STRV_FOREACH_BACKWARDS(s, l)for (s = ({ char **_l = l; _l ? _l + strv_length(_l) - 1U : (
(void*)0); }); (l) && ((s) >= (l)); (s)--)
\
86 for (s = ({ \
87 char **_l = l; \
88 _l ? _l + strv_length(_l) - 1U : NULL((void*)0); \
89 }); \
90 (l) && ((s) >= (l)); \
91 (s)--)
92
93#define STRV_FOREACH_PAIR(x, y, l)for ((x) = (l), (y) = (x+1); (x) && *(x) && *
(y); (x) += 2, (y) = (x + 1))
\
94 for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
95
96char **strv_sort(char **l);
97void strv_print(char **l);
98
99#define STRV_MAKE(...)((char**) ((const char*[]) { ..., ((void*)0) })) ((char**) ((const char*[]) { __VA_ARGS__, NULL((void*)0) }))
100
101#define STRV_MAKE_EMPTY((char*[1]) { ((void*)0) }) ((char*[1]) { NULL((void*)0) })
102
103#define strv_from_stdarg_alloca(first)({ char **_l; if (!first) _l = (char**) &first; else { size_t
_n; va_list _ap; _n = 1; __builtin_va_start(_ap, first); while
(__builtin_va_arg(_ap, char*)) _n++; __builtin_va_end(_ap); _l
= ({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow
(sizeof(char*), _n+1))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("!size_multiply_overflow(sizeof(char*), _n+1)"), "../src/basic/strv.h"
, 103, __PRETTY_FUNCTION__); } while (0); (char**) __builtin_alloca
(sizeof(char*)*(_n+1)); }); _l[_n = 0] = (char*) first; __builtin_va_start
(_ap, first); for (;;) { _l[++_n] = __builtin_va_arg(_ap, char
*); if (!_l[_n]) break; } __builtin_va_end(_ap); } _l; })
\
104 ({ \
105 char **_l; \
106 \
107 if (!first) \
108 _l = (char**) &first; \
109 else { \
110 size_t _n; \
111 va_list _ap; \
112 \
113 _n = 1; \
114 va_start(_ap, first)__builtin_va_start(_ap, first); \
115 while (va_arg(_ap, char*)__builtin_va_arg(_ap, char*)) \
116 _n++; \
117 va_end(_ap)__builtin_va_end(_ap); \
118 \
119 _l = newa(char*, _n+1)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(char*), _n+1))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("!size_multiply_overflow(sizeof(char*), _n+1)"), "../src/basic/strv.h"
, 119, __PRETTY_FUNCTION__); } while (0); (char**) __builtin_alloca
(sizeof(char*)*(_n+1)); })
; \
120 _l[_n = 0] = (char*) first; \
121 va_start(_ap, first)__builtin_va_start(_ap, first); \
122 for (;;) { \
123 _l[++_n] = va_arg(_ap, char*)__builtin_va_arg(_ap, char*); \
124 if (!_l[_n]) \
125 break; \
126 } \
127 va_end(_ap)__builtin_va_end(_ap); \
128 } \
129 _l; \
130 })
131
132#define STR_IN_SET(x, ...)(!!strv_find((((char**) ((const char*[]) { ..., ((void*)0) })
)), (x)))
strv_contains(STRV_MAKE(__VA_ARGS__), x)(!!strv_find((((char**) ((const char*[]) { __VA_ARGS__, ((void
*)0) }))), (x)))
133#define STRPTR_IN_SET(x, ...)({ const char* _x = (x); _x && (!!strv_find((((char**
) ((const char*[]) { ..., ((void*)0) }))), (_x))); })
\
134 ({ \
135 const char* _x = (x); \
136 _x && strv_contains(STRV_MAKE(__VA_ARGS__), _x)(!!strv_find((((char**) ((const char*[]) { __VA_ARGS__, ((void
*)0) }))), (_x)))
; \
137 })
138
139#define STARTSWITH_SET(p, ...)({ const char *_p = (p); char *_found = ((void*)0), **_i; for
((_i) = (((char**) ((const char*[]) { ..., ((void*)0) }))); (
_i) && *(_i); (_i)++) { _found = startswith(_p, *_i);
if (_found) break; } _found; })
\
140 ({ \
141 const char *_p = (p); \
142 char *_found = NULL((void*)0), **_i; \
143 STRV_FOREACH(_i, STRV_MAKE(__VA_ARGS__))for ((_i) = (((char**) ((const char*[]) { __VA_ARGS__, ((void
*)0) }))); (_i) && *(_i); (_i)++)
{ \
144 _found = startswith(_p, *_i); \
145 if (_found) \
146 break; \
147 } \
148 _found; \
149 })
150
151#define FOREACH_STRING(x, ...)for (char **_l = ({ char **_ll = ((char**) ((const char*[]) {
..., ((void*)0) })); x = _ll ? _ll[0] : ((void*)0); _ll; });
_l && *_l; x = ({ _l ++; _l[0]; }))
\
152 for (char **_l = ({ \
153 char **_ll = STRV_MAKE(__VA_ARGS__)((char**) ((const char*[]) { __VA_ARGS__, ((void*)0) })); \
154 x = _ll ? _ll[0] : NULL((void*)0); \
155 _ll; \
156 }); \
157 _l && *_l; \
158 x = ({ \
159 _l ++; \
160 _l[0]; \
161 }))
162
163char **strv_reverse(char **l);
164char **strv_shell_escape(char **l, const char *bad);
165
166bool_Bool strv_fnmatch(char* const* patterns, const char *s, int flags);
167
168static inline bool_Bool strv_fnmatch_or_empty(char* const* patterns, const char *s, int flags) {
169 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/strv.h", 169, __PRETTY_FUNCTION__
); } while (0)
;
170 return strv_isempty(patterns) ||
171 strv_fnmatch(patterns, s, flags);
172}
173
174char ***strv_free_free(char ***l);
175DEFINE_TRIVIAL_CLEANUP_FUNC(char***, strv_free_free)static inline void strv_free_freep(char*** *p) { if (*p) strv_free_free
(*p); }
;
176
177char **strv_skip(char **l, size_t n);
178
179int strv_extend_n(char ***l, const char *value, size_t n);
180
181int fputstrv(FILE *f, char **l, const char *separator, bool_Bool *space);
182
183#define strv_free_and_replace(a, b)({ strv_free(a); (a) = (b); (b) = ((void*)0); 0; }) \
184 ({ \
185 strv_free(a); \
186 (a) = (b); \
187 (b) = NULL((void*)0); \
188 0; \
189 })

../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))
10
Taking false branch
61 return NULL((void*)0);
62
63 return malloc(size * need);
11
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 })