| File: | build-scan/../src/basic/hexdecoct.c |
| Warning: | line 67, column 24 Use of zero-allocated memory |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 | ||||
| 14 | char octchar(int x) { | |||
| 15 | return '0' + (x & 7); | |||
| 16 | } | |||
| 17 | ||||
| 18 | int unoctchar(char c) { | |||
| 19 | ||||
| 20 | if (c >= '0' && c <= '7') | |||
| 21 | return c - '0'; | |||
| 22 | ||||
| 23 | return -EINVAL22; | |||
| 24 | } | |||
| 25 | ||||
| 26 | char decchar(int x) { | |||
| 27 | return '0' + (x % 10); | |||
| 28 | } | |||
| 29 | ||||
| 30 | int undecchar(char c) { | |||
| 31 | ||||
| 32 | if (c >= '0' && c <= '9') | |||
| 33 | return c - '0'; | |||
| 34 | ||||
| 35 | return -EINVAL22; | |||
| 36 | } | |||
| 37 | ||||
| 38 | char hexchar(int x) { | |||
| 39 | static const char table[16] = "0123456789abcdef"; | |||
| 40 | ||||
| 41 | return table[x & 15]; | |||
| 42 | } | |||
| 43 | ||||
| 44 | int 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 | ||||
| 58 | char *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))); | |||
| ||||
| 63 | if (!r) | |||
| 64 | return NULL((void*)0); | |||
| 65 | ||||
| 66 | for (x = p; x < (const uint8_t*) p + l; x++) { | |||
| 67 | *(z++) = hexchar(*x >> 4); | |||
| ||||
| 68 | *(z++) = hexchar(*x & 15); | |||
| 69 | } | |||
| 70 | ||||
| 71 | *z = 0; | |||
| 72 | return r; | |||
| 73 | } | |||
| 74 | ||||
| 75 | static 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 | ||||
| 111 | int 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. */ | |||
| 158 | char base32hexchar(int x) { | |||
| 159 | static const char table[32] = "0123456789" | |||
| 160 | "ABCDEFGHIJKLMNOPQRSTUV"; | |||
| 161 | ||||
| 162 | return table[x & 31]; | |||
| 163 | } | |||
| 164 | ||||
| 165 | int 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 | ||||
| 179 | char *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 | ||||
| 287 | int 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 */ | |||
| 509 | char base64char(int x) { | |||
| 510 | static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |||
| 511 | "abcdefghijklmnopqrstuvwxyz" | |||
| 512 | "0123456789+/"; | |||
| 513 | return table[x & 63]; | |||
| 514 | } | |||
| 515 | ||||
| 516 | int 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 | ||||
| 545 | ssize_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 | ||||
| 587 | static 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_X4 = ((len)); const typeof ((width)) __unique_prefix_Y5 = ((width)); (__unique_prefix_X4 / __unique_prefix_Y5 + !!(__unique_prefix_X4 % __unique_prefix_Y5 )); }); | |||
| 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_A6 = ( (width)); const typeof((avail)) __unique_prefix_B7 = ((avail) ); __unique_prefix_A6 < __unique_prefix_B7 ? __unique_prefix_A6 : __unique_prefix_B7; }); | |||
| 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 | ||||
| 630 | int 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 | ||||
| 643 | static 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 | ||||
| 685 | int 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 | ||||
| 773 | void 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 | } |
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
| 2 | #pragma once |
| 3 | |
| 4 | #include <alloca.h> |
| 5 | #include <stddef.h> |
| 6 | #include <stdlib.h> |
| 7 | #include <string.h> |
| 8 | |
| 9 | #include "macro.h" |
| 10 | |
| 11 | #define new(t, n)((t*) malloc_multiply(sizeof(t), (n))) ((t*) malloc_multiply(sizeof(t), (n))) |
| 12 | |
| 13 | #define new0(t, n)((t*) calloc((n), sizeof(t))) ((t*) calloc((n), sizeof(t))) |
| 14 | |
| 15 | #define newa(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 15, __PRETTY_FUNCTION__); } while (0); (t*) __builtin_alloca (sizeof(t)*(n)); }) \ |
| 16 | ({ \ |
| 17 | assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 17, __PRETTY_FUNCTION__); } while (0); \ |
| 18 | (t*) alloca(sizeof(t)*(n))__builtin_alloca (sizeof(t)*(n)); \ |
| 19 | }) |
| 20 | |
| 21 | #define newa0(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 21, __PRETTY_FUNCTION__); } while (0); (t*) ({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_) ; }); }) \ |
| 22 | ({ \ |
| 23 | assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 23, __PRETTY_FUNCTION__); } while (0); \ |
| 24 | (t*) alloca0(sizeof(t)*(n))({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_); }); \ |
| 25 | }) |
| 26 | |
| 27 | #define newdup(t, p, n)((t*) memdup_multiply(p, sizeof(t), (n))) ((t*) memdup_multiply(p, sizeof(t), (n))) |
| 28 | |
| 29 | #define newdup_suffix0(t, p, n)((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) |
| 30 | |
| 31 | #define malloc0(n)(calloc(1, (n))) (calloc(1, (n))) |
| 32 | |
| 33 | static inline void *mfree(void *memory) { |
| 34 | free(memory); |
| 35 | return NULL((void*)0); |
| 36 | } |
| 37 | |
| 38 | #define free_and_replace(a, b)({ free(a); (a) = (b); (b) = ((void*)0); 0; }) \ |
| 39 | ({ \ |
| 40 | free(a); \ |
| 41 | (a) = (b); \ |
| 42 | (b) = NULL((void*)0); \ |
| 43 | 0; \ |
| 44 | }) |
| 45 | |
| 46 | void* memdup(const void *p, size_t l) _alloc_(2); |
| 47 | void* memdup_suffix0(const void *p, size_t l) _alloc_(2); |
| 48 | |
| 49 | static inline void freep(void *p) { |
| 50 | free(*(void**) p); |
| 51 | } |
| 52 | |
| 53 | #define _cleanup_free___attribute__((cleanup(freep))) _cleanup_(freep)__attribute__((cleanup(freep))) |
| 54 | |
| 55 | static inline bool_Bool size_multiply_overflow(size_t size, size_t need) { |
| 56 | return _unlikely_(need != 0 && size > (SIZE_MAX / need))(__builtin_expect(!!(need != 0 && size > ((18446744073709551615UL ) / need)),0)); |
| 57 | } |
| 58 | |
| 59 | _malloc___attribute__ ((malloc)) _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) { |
| 60 | if (size_multiply_overflow(size, need)) |
| 61 | return NULL((void*)0); |
| 62 | |
| 63 | return malloc(size * need); |
| 64 | } |
| 65 | |
| 66 | #if !HAVE_REALLOCARRAY1 |
| 67 | _alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) { |
| 68 | if (size_multiply_overflow(size, need)) |
| 69 | return NULL((void*)0); |
| 70 | |
| 71 | return realloc(p, size * need); |
| 72 | } |
| 73 | #endif |
| 74 | |
| 75 | _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) { |
| 76 | if (size_multiply_overflow(size, need)) |
| 77 | return NULL((void*)0); |
| 78 | |
| 79 | return memdup(p, size * need); |
| 80 | } |
| 81 | |
| 82 | _alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) { |
| 83 | if (size_multiply_overflow(size, need)) |
| 84 | return NULL((void*)0); |
| 85 | |
| 86 | return memdup_suffix0(p, size * need); |
| 87 | } |
| 88 | |
| 89 | void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); |
| 90 | void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); |
| 91 | |
| 92 | #define GREEDY_REALLOC(array, allocated, need)greedy_realloc((void**) &(array), &(allocated), (need ), sizeof((array)[0])) \ |
| 93 | greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) |
| 94 | |
| 95 | #define GREEDY_REALLOC0(array, allocated, need)greedy_realloc0((void**) &(array), &(allocated), (need ), sizeof((array)[0])) \ |
| 96 | greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0])) |
| 97 | |
| 98 | #define alloca0(n)({ char *_new_; size_t _len_ = n; _new_ = __builtin_alloca (_len_ ); (void *) memset(_new_, 0, _len_); }) \ |
| 99 | ({ \ |
| 100 | char *_new_; \ |
| 101 | size_t _len_ = n; \ |
| 102 | _new_ = alloca(_len_)__builtin_alloca (_len_); \ |
| 103 | (void *) memset(_new_, 0, _len_); \ |
| 104 | }) |
| 105 | |
| 106 | /* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ |
| 107 | #define alloca_align(size, align)({ void *_ptr_; size_t _mask_ = (align) - 1; _ptr_ = __builtin_alloca ((size) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); }) \ |
| 108 | ({ \ |
| 109 | void *_ptr_; \ |
| 110 | size_t _mask_ = (align) - 1; \ |
| 111 | _ptr_ = alloca((size) + _mask_)__builtin_alloca ((size) + _mask_); \ |
| 112 | (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ |
| 113 | }) |
| 114 | |
| 115 | #define alloca0_align(size, align)({ void *_new_; size_t _size_ = (size); _new_ = ({ void *_ptr_ ; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_ ) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_ ); }); (void*)memset(_new_, 0, _size_); }) \ |
| 116 | ({ \ |
| 117 | void *_new_; \ |
| 118 | size_t _size_ = (size); \ |
| 119 | _new_ = alloca_align(_size_, (align))({ void *_ptr_; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); }); \ |
| 120 | (void*)memset(_new_, 0, _size_); \ |
| 121 | }) |
| 122 | |
| 123 | /* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to |
| 124 | * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ |
| 125 | #define TAKE_PTR(ptr)({ typeof(ptr) _ptr_ = (ptr); (ptr) = ((void*)0); _ptr_; }) \ |
| 126 | ({ \ |
| 127 | typeof(ptr) _ptr_ = (ptr); \ |
| 128 | (ptr) = NULL((void*)0); \ |
| 129 | _ptr_; \ |
| 130 | }) |