Bug Summary

File:build-scan/../src/basic/hexdecoct.c
Warning:line 71, 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 hexdecoct.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/hexdecoct.c

../src/basic/hexdecoct.c

1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <ctype.h>
4#include <errno(*__errno_location ()).h>
5#include <stdint.h>
6#include <stdlib.h>
7
8#include "alloc-util.h"
9#include "hexdecoct.h"
10#include "macro.h"
11#include "string-util.h"
12#include "util.h"
13
14char octchar(int x) {
15 return '0' + (x & 7);
16}
17
18int unoctchar(char c) {
19
20 if (c >= '0' && c <= '7')
21 return c - '0';
22
23 return -EINVAL22;
24}
25
26char decchar(int x) {
27 return '0' + (x % 10);
28}
29
30int undecchar(char c) {
31
32 if (c >= '0' && c <= '9')
33 return c - '0';
34
35 return -EINVAL22;
36}
37
38char hexchar(int x) {
39 static const char table[16] = "0123456789abcdef";
40
41 return table[x & 15];
42}
43
44int unhexchar(char c) {
45
46 if (c >= '0' && c <= '9')
47 return c - '0';
48
49 if (c >= 'a' && c <= 'f')
50 return c - 'a' + 10;
51
52 if (c >= 'A' && c <= 'F')
53 return c - 'A' + 10;
54
55 return -EINVAL22;
56}
57
58char *hexmem(const void *p, size_t l) {
59 const uint8_t *x;
60 char *r, *z;
61
62 z = r = new(char, l * 2 + 1)((char*) malloc_multiply(sizeof(char), (l * 2 + 1)));
1
Calling 'malloc_multiply'
4
Returned allocated memory
63 if (!r)
5
Assuming 'r' is non-null
6
Taking false branch
64 return NULL((void*)0);
65
66 for (x = p; x < (const uint8_t*) p + l; x++) {
7
Assuming the condition is false
8
Loop condition is false. Execution continues on line 71
67 *(z++) = hexchar(*x >> 4);
68 *(z++) = hexchar(*x & 15);
69 }
70
71 *z = 0;
9
Use of zero-allocated memory
72 return r;
73}
74
75static int unhex_next(const char **p, size_t *l) {
76 int r;
77
78 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/basic/hexdecoct.c", 78, __PRETTY_FUNCTION__
); } while (0)
;
79 assert(l)do { if ((__builtin_expect(!!(!(l)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("l"), "../src/basic/hexdecoct.c", 79, __PRETTY_FUNCTION__
); } while (0)
;
80
81 /* Find the next non-whitespace character, and decode it. We
82 * greedily skip all preceeding and all following whitespace. */
83
84 for (;;) {
85 if (*l == 0)
86 return -EPIPE32;
87
88 if (!strchr(WHITESPACE" \t\n\r", **p))
89 break;
90
91 /* Skip leading whitespace */
92 (*p)++, (*l)--;
93 }
94
95 r = unhexchar(**p);
96 if (r < 0)
97 return r;
98
99 for (;;) {
100 (*p)++, (*l)--;
101
102 if (*l == 0 || !strchr(WHITESPACE" \t\n\r", **p))
103 break;
104
105 /* Skip following whitespace */
106 }
107
108 return r;
109}
110
111int unhexmem(const char *p, size_t l, void **ret, size_t *ret_len) {
112 _cleanup_free___attribute__((cleanup(freep))) uint8_t *buf = NULL((void*)0);
113 const char *x;
114 uint8_t *z;
115
116 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/basic/hexdecoct.c", 116,
__PRETTY_FUNCTION__); } while (0)
;
117 assert(ret_len)do { if ((__builtin_expect(!!(!(ret_len)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret_len"), "../src/basic/hexdecoct.c", 117
, __PRETTY_FUNCTION__); } while (0)
;
118 assert(p || l == 0)do { if ((__builtin_expect(!!(!(p || l == 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p || l == 0"), "../src/basic/hexdecoct.c"
, 118, __PRETTY_FUNCTION__); } while (0)
;
119
120 if (l == (size_t) -1)
121 l = strlen(p);
122
123 /* Note that the calculation of memory size is an upper boundary, as we ignore whitespace while decoding */
124 buf = malloc((l + 1) / 2 + 1);
125 if (!buf)
126 return -ENOMEM12;
127
128 for (x = p, z = buf;;) {
129 int a, b;
130
131 a = unhex_next(&x, &l);
132 if (a == -EPIPE32) /* End of string */
133 break;
134 if (a < 0)
135 return a;
136
137 b = unhex_next(&x, &l);
138 if (b < 0)
139 return b;
140
141 *(z++) = (uint8_t) a << 4 | (uint8_t) b;
142 }
143
144 *z = 0;
145
146 *ret_len = (size_t) (z - buf);
147 *ret = TAKE_PTR(buf)({ typeof(buf) _ptr_ = (buf); (buf) = ((void*)0); _ptr_; });
148
149 return 0;
150}
151
152/* https://tools.ietf.org/html/rfc4648#section-6
153 * Notice that base32hex differs from base32 in the alphabet it uses.
154 * The distinction is that the base32hex representation preserves the
155 * order of the underlying data when compared as bytestrings, this is
156 * useful when representing NSEC3 hashes, as one can then verify the
157 * order of hashes directly from their representation. */
158char base32hexchar(int x) {
159 static const char table[32] = "0123456789"
160 "ABCDEFGHIJKLMNOPQRSTUV";
161
162 return table[x & 31];
163}
164
165int unbase32hexchar(char c) {
166 unsigned offset;
167
168 if (c >= '0' && c <= '9')
169 return c - '0';
170
171 offset = '9' - '0' + 1;
172
173 if (c >= 'A' && c <= 'V')
174 return c - 'A' + offset;
175
176 return -EINVAL22;
177}
178
179char *base32hexmem(const void *p, size_t l, bool_Bool padding) {
180 char *r, *z;
181 const uint8_t *x;
182 size_t len;
183
184 assert(p || l == 0)do { if ((__builtin_expect(!!(!(p || l == 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p || l == 0"), "../src/basic/hexdecoct.c"
, 184, __PRETTY_FUNCTION__); } while (0)
;
185
186 if (padding)
187 /* five input bytes makes eight output bytes, padding is added so we must round up */
188 len = 8 * (l + 4) / 5;
189 else {
190 /* same, but round down as there is no padding */
191 len = 8 * l / 5;
192
193 switch (l % 5) {
194 case 4:
195 len += 7;
196 break;
197 case 3:
198 len += 5;
199 break;
200 case 2:
201 len += 4;
202 break;
203 case 1:
204 len += 2;
205 break;
206 }
207 }
208
209 z = r = malloc(len + 1);
210 if (!r)
211 return NULL((void*)0);
212
213 for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
214 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
215 * x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
216 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
217 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
218 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
219 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
220 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
221 *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
222 *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */
223 *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */
224 }
225
226 switch (l % 5) {
227 case 4:
228 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
229 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
230 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
231 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
232 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
233 *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
234 *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */
235 if (padding)
236 *(z++) = '=';
237
238 break;
239
240 case 3:
241 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
242 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
243 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
244 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
245 *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */
246 if (padding) {
247 *(z++) = '=';
248 *(z++) = '=';
249 *(z++) = '=';
250 }
251
252 break;
253
254 case 2:
255 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
256 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
257 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
258 *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */
259 if (padding) {
260 *(z++) = '=';
261 *(z++) = '=';
262 *(z++) = '=';
263 *(z++) = '=';
264 }
265
266 break;
267
268 case 1:
269 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
270 *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
271 if (padding) {
272 *(z++) = '=';
273 *(z++) = '=';
274 *(z++) = '=';
275 *(z++) = '=';
276 *(z++) = '=';
277 *(z++) = '=';
278 }
279
280 break;
281 }
282
283 *z = 0;
284 return r;
285}
286
287int unbase32hexmem(const char *p, size_t l, bool_Bool padding, void **mem, size_t *_len) {
288 _cleanup_free___attribute__((cleanup(freep))) uint8_t *r = NULL((void*)0);
289 int a, b, c, d, e, f, g, h;
290 uint8_t *z;
291 const char *x;
292 size_t len;
293 unsigned pad = 0;
294
295 assert(p || l == 0)do { if ((__builtin_expect(!!(!(p || l == 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p || l == 0"), "../src/basic/hexdecoct.c"
, 295, __PRETTY_FUNCTION__); } while (0)
;
296 assert(mem)do { if ((__builtin_expect(!!(!(mem)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("mem"), "../src/basic/hexdecoct.c", 296,
__PRETTY_FUNCTION__); } while (0)
;
297 assert(_len)do { if ((__builtin_expect(!!(!(_len)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("_len"), "../src/basic/hexdecoct.c", 297
, __PRETTY_FUNCTION__); } while (0)
;
298
299 if (l == (size_t) -1)
300 l = strlen(p);
301
302 /* padding ensures any base32hex input has input divisible by 8 */
303 if (padding && l % 8 != 0)
304 return -EINVAL22;
305
306 if (padding) {
307 /* strip the padding */
308 while (l > 0 && p[l - 1] == '=' && pad < 7) {
309 pad++;
310 l--;
311 }
312 }
313
314 /* a group of eight input bytes needs five output bytes, in case of
315 * padding we need to add some extra bytes */
316 len = (l / 8) * 5;
317
318 switch (l % 8) {
319 case 7:
320 len += 4;
321 break;
322 case 5:
323 len += 3;
324 break;
325 case 4:
326 len += 2;
327 break;
328 case 2:
329 len += 1;
330 break;
331 case 0:
332 break;
333 default:
334 return -EINVAL22;
335 }
336
337 z = r = malloc(len + 1);
338 if (!r)
339 return -ENOMEM12;
340
341 for (x = p; x < p + (l / 8) * 8; x += 8) {
342 /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
343 * e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
344 a = unbase32hexchar(x[0]);
345 if (a < 0)
346 return -EINVAL22;
347
348 b = unbase32hexchar(x[1]);
349 if (b < 0)
350 return -EINVAL22;
351
352 c = unbase32hexchar(x[2]);
353 if (c < 0)
354 return -EINVAL22;
355
356 d = unbase32hexchar(x[3]);
357 if (d < 0)
358 return -EINVAL22;
359
360 e = unbase32hexchar(x[4]);
361 if (e < 0)
362 return -EINVAL22;
363
364 f = unbase32hexchar(x[5]);
365 if (f < 0)
366 return -EINVAL22;
367
368 g = unbase32hexchar(x[6]);
369 if (g < 0)
370 return -EINVAL22;
371
372 h = unbase32hexchar(x[7]);
373 if (h < 0)
374 return -EINVAL22;
375
376 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
377 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
378 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
379 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
380 *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */
381 }
382
383 switch (l % 8) {
384 case 7:
385 a = unbase32hexchar(x[0]);
386 if (a < 0)
387 return -EINVAL22;
388
389 b = unbase32hexchar(x[1]);
390 if (b < 0)
391 return -EINVAL22;
392
393 c = unbase32hexchar(x[2]);
394 if (c < 0)
395 return -EINVAL22;
396
397 d = unbase32hexchar(x[3]);
398 if (d < 0)
399 return -EINVAL22;
400
401 e = unbase32hexchar(x[4]);
402 if (e < 0)
403 return -EINVAL22;
404
405 f = unbase32hexchar(x[5]);
406 if (f < 0)
407 return -EINVAL22;
408
409 g = unbase32hexchar(x[6]);
410 if (g < 0)
411 return -EINVAL22;
412
413 /* g == 000VV000 */
414 if (g & 7)
415 return -EINVAL22;
416
417 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
418 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
419 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
420 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
421
422 break;
423 case 5:
424 a = unbase32hexchar(x[0]);
425 if (a < 0)
426 return -EINVAL22;
427
428 b = unbase32hexchar(x[1]);
429 if (b < 0)
430 return -EINVAL22;
431
432 c = unbase32hexchar(x[2]);
433 if (c < 0)
434 return -EINVAL22;
435
436 d = unbase32hexchar(x[3]);
437 if (d < 0)
438 return -EINVAL22;
439
440 e = unbase32hexchar(x[4]);
441 if (e < 0)
442 return -EINVAL22;
443
444 /* e == 000SSSS0 */
445 if (e & 1)
446 return -EINVAL22;
447
448 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
449 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
450 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
451
452 break;
453 case 4:
454 a = unbase32hexchar(x[0]);
455 if (a < 0)
456 return -EINVAL22;
457
458 b = unbase32hexchar(x[1]);
459 if (b < 0)
460 return -EINVAL22;
461
462 c = unbase32hexchar(x[2]);
463 if (c < 0)
464 return -EINVAL22;
465
466 d = unbase32hexchar(x[3]);
467 if (d < 0)
468 return -EINVAL22;
469
470 /* d == 000W0000 */
471 if (d & 15)
472 return -EINVAL22;
473
474 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
475 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
476
477 break;
478 case 2:
479 a = unbase32hexchar(x[0]);
480 if (a < 0)
481 return -EINVAL22;
482
483 b = unbase32hexchar(x[1]);
484 if (b < 0)
485 return -EINVAL22;
486
487 /* b == 000YYY00 */
488 if (b & 3)
489 return -EINVAL22;
490
491 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
492
493 break;
494 case 0:
495 break;
496 default:
497 return -EINVAL22;
498 }
499
500 *z = 0;
501
502 *mem = TAKE_PTR(r)({ typeof(r) _ptr_ = (r); (r) = ((void*)0); _ptr_; });
503 *_len = len;
504
505 return 0;
506}
507
508/* https://tools.ietf.org/html/rfc4648#section-4 */
509char base64char(int x) {
510 static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
511 "abcdefghijklmnopqrstuvwxyz"
512 "0123456789+/";
513 return table[x & 63];
514}
515
516int unbase64char(char c) {
517 unsigned offset;
518
519 if (c >= 'A' && c <= 'Z')
520 return c - 'A';
521
522 offset = 'Z' - 'A' + 1;
523
524 if (c >= 'a' && c <= 'z')
525 return c - 'a' + offset;
526
527 offset += 'z' - 'a' + 1;
528
529 if (c >= '0' && c <= '9')
530 return c - '0' + offset;
531
532 offset += '9' - '0' + 1;
533
534 if (c == '+')
535 return offset;
536
537 offset++;
538
539 if (c == '/')
540 return offset;
541
542 return -EINVAL22;
543}
544
545ssize_t base64mem(const void *p, size_t l, char **out) {
546 char *r, *z;
547 const uint8_t *x;
548
549 assert(p || l == 0)do { if ((__builtin_expect(!!(!(p || l == 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p || l == 0"), "../src/basic/hexdecoct.c"
, 549, __PRETTY_FUNCTION__); } while (0)
;
550 assert(out)do { if ((__builtin_expect(!!(!(out)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("out"), "../src/basic/hexdecoct.c", 550,
__PRETTY_FUNCTION__); } while (0)
;
551
552 /* three input bytes makes four output bytes, padding is added so we must round up */
553 z = r = malloc(4 * (l + 2) / 3 + 1);
554 if (!r)
555 return -ENOMEM12;
556
557 for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
558 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
559 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
560 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
561 *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
562 *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
563 }
564
565 switch (l % 3) {
566 case 2:
567 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
568 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
569 *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
570 *(z++) = '=';
571
572 break;
573 case 1:
574 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
575 *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
576 *(z++) = '=';
577 *(z++) = '=';
578
579 break;
580 }
581
582 *z = 0;
583 *out = r;
584 return z - r;
585}
586
587static int base64_append_width(
588 char **prefix, int plen,
589 const char *sep, int indent,
590 const void *p, size_t l,
591 int width) {
592
593 _cleanup_free___attribute__((cleanup(freep))) char *x = NULL((void*)0);
594 char *t, *s;
595 ssize_t slen, len, avail;
596 int line, lines;
597
598 len = base64mem(p, l, &x);
599 if (len <= 0)
600 return len;
601
602 lines = DIV_ROUND_UP(len, width)({ const typeof((len)) __unique_prefix_X8 = ((len)); const typeof
((width)) __unique_prefix_Y9 = ((width)); (__unique_prefix_X8
/ __unique_prefix_Y9 + !!(__unique_prefix_X8 % __unique_prefix_Y9
)); })
;
603
604 slen = strlen_ptr(sep);
605 t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
606 if (!t)
607 return -ENOMEM12;
608
609 memcpy_safe(t + plen, sep, slen);
610
611 for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) {
612 int act = MIN(width, avail)__extension__ ({ const typeof((width)) __unique_prefix_A10 = (
(width)); const typeof((avail)) __unique_prefix_B11 = ((avail
)); __unique_prefix_A10 < __unique_prefix_B11 ? __unique_prefix_A10
: __unique_prefix_B11; })
;
613
614 if (line > 0 || sep) {
615 memset(s, ' ', indent);
616 s += indent;
617 }
618
619 memcpy(s, x + width * line, act);
620 s += act;
621 *(s++) = line < lines - 1 ? '\n' : '\0';
622 avail -= act;
623 }
624 assert(avail == 0)do { if ((__builtin_expect(!!(!(avail == 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("avail == 0"), "../src/basic/hexdecoct.c"
, 624, __PRETTY_FUNCTION__); } while (0)
;
625
626 *prefix = t;
627 return 0;
628}
629
630int base64_append(
631 char **prefix, int plen,
632 const void *p, size_t l,
633 int indent, int width) {
634
635 if (plen > width / 2 || plen + indent > width)
636 /* leave indent on the left, keep last column free */
637 return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1);
638 else
639 /* leave plen on the left, keep last column free */
640 return base64_append_width(prefix, plen, NULL((void*)0), plen, p, l, width - plen - 1);
641}
642
643static int unbase64_next(const char **p, size_t *l) {
644 int ret;
645
646 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/basic/hexdecoct.c", 646, __PRETTY_FUNCTION__
); } while (0)
;
647 assert(l)do { if ((__builtin_expect(!!(!(l)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("l"), "../src/basic/hexdecoct.c", 647, __PRETTY_FUNCTION__
); } while (0)
;
648
649 /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
650 * greedily skip all preceeding and all following whitespace. */
651
652 for (;;) {
653 if (*l == 0)
654 return -EPIPE32;
655
656 if (!strchr(WHITESPACE" \t\n\r", **p))
657 break;
658
659 /* Skip leading whitespace */
660 (*p)++, (*l)--;
661 }
662
663 if (**p == '=')
664 ret = INT_MAX2147483647; /* return padding as INT_MAX */
665 else {
666 ret = unbase64char(**p);
667 if (ret < 0)
668 return ret;
669 }
670
671 for (;;) {
672 (*p)++, (*l)--;
673
674 if (*l == 0)
675 break;
676 if (!strchr(WHITESPACE" \t\n\r", **p))
677 break;
678
679 /* Skip following whitespace */
680 }
681
682 return ret;
683}
684
685int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) {
686 _cleanup_free___attribute__((cleanup(freep))) uint8_t *buf = NULL((void*)0);
687 const char *x;
688 uint8_t *z;
689 size_t len;
690
691 assert(p || l == 0)do { if ((__builtin_expect(!!(!(p || l == 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p || l == 0"), "../src/basic/hexdecoct.c"
, 691, __PRETTY_FUNCTION__); } while (0)
;
692 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/basic/hexdecoct.c", 692,
__PRETTY_FUNCTION__); } while (0)
;
693 assert(ret_size)do { if ((__builtin_expect(!!(!(ret_size)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret_size"), "../src/basic/hexdecoct.c",
693, __PRETTY_FUNCTION__); } while (0)
;
694
695 if (l == (size_t) -1)
696 l = strlen(p);
697
698 /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
699 * bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
700 len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0);
701
702 buf = malloc(len + 1);
703 if (!buf)
704 return -ENOMEM12;
705
706 for (x = p, z = buf;;) {
707 int a, b, c, d; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
708
709 a = unbase64_next(&x, &l);
710 if (a == -EPIPE32) /* End of string */
711 break;
712 if (a < 0)
713 return a;
714 if (a == INT_MAX2147483647) /* Padding is not allowed at the beginning of a 4ch block */
715 return -EINVAL22;
716
717 b = unbase64_next(&x, &l);
718 if (b < 0)
719 return b;
720 if (b == INT_MAX2147483647) /* Padding is not allowed at the second character of a 4ch block either */
721 return -EINVAL22;
722
723 c = unbase64_next(&x, &l);
724 if (c < 0)
725 return c;
726
727 d = unbase64_next(&x, &l);
728 if (d < 0)
729 return d;
730
731 if (c == INT_MAX2147483647) { /* Padding at the third character */
732
733 if (d != INT_MAX2147483647) /* If the third character is padding, the fourth must be too */
734 return -EINVAL22;
735
736 /* b == 00YY0000 */
737 if (b & 15)
738 return -EINVAL22;
739
740 if (l > 0) /* Trailing rubbish? */
741 return -ENAMETOOLONG36;
742
743 *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
744 break;
745 }
746
747 if (d == INT_MAX2147483647) {
748 /* c == 00ZZZZ00 */
749 if (c & 3)
750 return -EINVAL22;
751
752 if (l > 0) /* Trailing rubbish? */
753 return -ENAMETOOLONG36;
754
755 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
756 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
757 break;
758 }
759
760 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
761 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
762 *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
763 }
764
765 *z = 0;
766
767 *ret_size = (size_t) (z - buf);
768 *ret = TAKE_PTR(buf)({ typeof(buf) _ptr_ = (buf); (buf) = ((void*)0); _ptr_; });
769
770 return 0;
771}
772
773void hexdump(FILE *f, const void *p, size_t s) {
774 const uint8_t *b = p;
775 unsigned n = 0;
776
777 assert(b || s == 0)do { if ((__builtin_expect(!!(!(b || s == 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("b || s == 0"), "../src/basic/hexdecoct.c"
, 777, __PRETTY_FUNCTION__); } while (0)
;
778
779 if (!f)
780 f = stdoutstdout;
781
782 while (s > 0) {
783 size_t i;
784
785 fprintf(f, "%04x ", n);
786
787 for (i = 0; i < 16; i++) {
788
789 if (i >= s)
790 fputs(" ", f);
791 else
792 fprintf(f, "%02x ", b[i]);
793
794 if (i == 7)
795 fputc(' ', f);
796 }
797
798 fputc(' ', f);
799
800 for (i = 0; i < 16; i++) {
801
802 if (i >= s)
803 fputc(' ', f);
804 else
805 fputc(isprint(b[i])((*__ctype_b_loc ())[(int) ((b[i]))] & (unsigned short int
) _ISprint)
? (char) b[i] : '.', f);
806 }
807
808 fputc('\n', f);
809
810 if (s < 16)
811 break;
812
813 n += 16;
814 b += 16;
815 s -= 16;
816 }
817}

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