Bug Summary

File:build-scan/../src/basic/strv.c
Warning:line 367, column 12
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)
1
Assuming 'separator' is non-null
2
Taking false branch
344 separator = " ";
345
346 k = strlen(separator);
347
348 n = 0;
349 STRV_FOREACH(s, l)for ((s) = (l); (s) && *(s); (s)++) {
3
Assuming 's' is non-null
4
Loop condition is true. Entering loop body
6
Loop condition is true. Entering loop body
8
Loop condition is false. Execution continues on line 355
350 if (s
4.1
's' is equal to 'l'
6.1
's' is not equal to 'l'
4.1
's' is equal to 'l'
6.1
's' is not equal to 'l'
!= l)
5
Taking false branch
7
Taking true branch
351 n += k;
352 n += strlen(*s);
353 }
354
355 r = new(char, n+1)((char*) malloc_multiply(sizeof(char), (n+1)));
9
Calling 'malloc_multiply'
12
Returned allocated memory
356 if (!r)
13
Assuming 'r' is non-null
14
Taking false branch
357 return NULL((void*)0);
358
359 e = r;
360 STRV_FOREACH(s, l)for ((s) = (l); (s) && *(s); (s)++) {
15
Loop condition is true. Entering loop body
17
Loop condition is true. Entering loop body
19
Loop condition is false. Execution continues on line 367
361 if (s
15.1
's' is equal to 'l'
17.1
's' is not equal to 'l'
15.1
's' is equal to 'l'
17.1
's' is not equal to 'l'
!= l)
16
Taking false branch
18
Taking true branch
362 e = stpcpy(e, separator);
363
364 e = stpcpy(e, *s);
365 }
366
367 *e = 0;
20
Use of zero-allocated memory
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)
430 return 0;
431
432 n = strv_length(*l);
433 position = MIN(position, n)__extension__ ({ const typeof((position)) __unique_prefix_A8 =
((position)); const typeof((n)) __unique_prefix_B9 = ((n)); __unique_prefix_A8
< __unique_prefix_B9 ? __unique_prefix_A8 : __unique_prefix_B9
; })
;
434
435 /* increase and check for overflow */
436 m = n + 2;
437 if (m < n)
438 return -ENOMEM12;
439
440 c = new(char*, m)((char**) malloc_multiply(sizeof(char*), (m)));
441 if (!c)
442 return -ENOMEM12;
443
444 for (i = 0; i < position; i++)
445 c[i] = (*l)[i];
446 c[position] = value;
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);
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/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 })