| File: | build-scan/../src/libsystemd/sd-id128/sd-id128.c |
| Warning: | line 163, column 9 Use of zero-allocated memory |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
| 2 | /*** | |||
| 3 | ***/ | |||
| 4 | ||||
| 5 | #include <errno(*__errno_location ()).h> | |||
| 6 | #include <fcntl.h> | |||
| 7 | #include <unistd.h> | |||
| 8 | ||||
| 9 | #include "sd-id128.h" | |||
| 10 | ||||
| 11 | #include "alloc-util.h" | |||
| 12 | #include "fd-util.h" | |||
| 13 | #include "hexdecoct.h" | |||
| 14 | #include "id128-util.h" | |||
| 15 | #include "io-util.h" | |||
| 16 | #include "khash.h" | |||
| 17 | #include "macro.h" | |||
| 18 | #include "missing.h" | |||
| 19 | #include "random-util.h" | |||
| 20 | #include "user-util.h" | |||
| 21 | #include "util.h" | |||
| 22 | ||||
| 23 | _public___attribute__ ((visibility("default"))) char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX33]) { | |||
| 24 | unsigned n; | |||
| 25 | ||||
| 26 | assert_return(s, NULL)do { if (!(((__builtin_expect(!!(s),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("s"), "../src/libsystemd/sd-id128/sd-id128.c" , 26, __PRETTY_FUNCTION__), 0))) return (((void*)0)); } while (0); | |||
| 27 | ||||
| 28 | for (n = 0; n < 16; n++) { | |||
| 29 | s[n*2] = hexchar(id.bytes[n] >> 4); | |||
| 30 | s[n*2+1] = hexchar(id.bytes[n] & 0xF); | |||
| 31 | } | |||
| 32 | ||||
| 33 | s[32] = 0; | |||
| 34 | ||||
| 35 | return s; | |||
| 36 | } | |||
| 37 | ||||
| 38 | _public___attribute__ ((visibility("default"))) int sd_id128_from_string(const char s[], sd_id128_t *ret) { | |||
| 39 | unsigned n, i; | |||
| 40 | sd_id128_t t; | |||
| 41 | bool_Bool is_guid = false0; | |||
| 42 | ||||
| 43 | assert_return(s, -EINVAL)do { if (!(((__builtin_expect(!!(s),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("s"), "../src/libsystemd/sd-id128/sd-id128.c" , 43, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 44 | ||||
| 45 | for (n = 0, i = 0; n < 16;) { | |||
| 46 | int a, b; | |||
| 47 | ||||
| 48 | if (s[i] == '-') { | |||
| 49 | /* Is this a GUID? Then be nice, and skip over | |||
| 50 | * the dashes */ | |||
| 51 | ||||
| 52 | if (i == 8) | |||
| 53 | is_guid = true1; | |||
| 54 | else if (IN_SET(i, 13, 18, 23)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){13, 18, 23})/sizeof(int)]; switch(i) { case 13: case 18: case 23: _found = 1; break; default: break; } _found ; })) { | |||
| 55 | if (!is_guid) | |||
| 56 | return -EINVAL22; | |||
| 57 | } else | |||
| 58 | return -EINVAL22; | |||
| 59 | ||||
| 60 | i++; | |||
| 61 | continue; | |||
| 62 | } | |||
| 63 | ||||
| 64 | a = unhexchar(s[i++]); | |||
| 65 | if (a < 0) | |||
| 66 | return -EINVAL22; | |||
| 67 | ||||
| 68 | b = unhexchar(s[i++]); | |||
| 69 | if (b < 0) | |||
| 70 | return -EINVAL22; | |||
| 71 | ||||
| 72 | t.bytes[n++] = (a << 4) | b; | |||
| 73 | } | |||
| 74 | ||||
| 75 | if (i != (is_guid ? 36 : 32)) | |||
| 76 | return -EINVAL22; | |||
| 77 | ||||
| 78 | if (s[i] != 0) | |||
| 79 | return -EINVAL22; | |||
| 80 | ||||
| 81 | if (ret) | |||
| 82 | *ret = t; | |||
| 83 | return 0; | |||
| 84 | } | |||
| 85 | ||||
| 86 | _public___attribute__ ((visibility("default"))) int sd_id128_get_machine(sd_id128_t *ret) { | |||
| 87 | static thread_local__thread sd_id128_t saved_machine_id = {}; | |||
| 88 | int r; | |||
| 89 | ||||
| 90 | assert_return(ret, -EINVAL)do { if (!(((__builtin_expect(!!(ret),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd/sd-id128/sd-id128.c" , 90, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 91 | ||||
| 92 | if (sd_id128_is_null(saved_machine_id)) { | |||
| 93 | r = id128_read("/etc/machine-id", ID128_PLAIN, &saved_machine_id); | |||
| 94 | if (r < 0) | |||
| 95 | return r; | |||
| 96 | ||||
| 97 | if (sd_id128_is_null(saved_machine_id)) | |||
| 98 | return -ENOMEDIUM123; | |||
| 99 | } | |||
| 100 | ||||
| 101 | *ret = saved_machine_id; | |||
| 102 | return 0; | |||
| 103 | } | |||
| 104 | ||||
| 105 | _public___attribute__ ((visibility("default"))) int sd_id128_get_boot(sd_id128_t *ret) { | |||
| 106 | static thread_local__thread sd_id128_t saved_boot_id = {}; | |||
| 107 | int r; | |||
| 108 | ||||
| 109 | assert_return(ret, -EINVAL)do { if (!(((__builtin_expect(!!(ret),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd/sd-id128/sd-id128.c" , 109, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 110 | ||||
| 111 | if (sd_id128_is_null(saved_boot_id)) { | |||
| 112 | r = id128_read("/proc/sys/kernel/random/boot_id", ID128_UUID, &saved_boot_id); | |||
| 113 | if (r < 0) | |||
| 114 | return r; | |||
| 115 | } | |||
| 116 | ||||
| 117 | *ret = saved_boot_id; | |||
| 118 | return 0; | |||
| 119 | } | |||
| 120 | ||||
| 121 | static int get_invocation_from_keyring(sd_id128_t *ret) { | |||
| 122 | ||||
| 123 | _cleanup_free___attribute__((cleanup(freep))) char *description = NULL((void*)0); | |||
| 124 | char *d, *p, *g, *u, *e; | |||
| 125 | unsigned long perms; | |||
| 126 | key_serial_t key; | |||
| 127 | size_t sz = 256; | |||
| 128 | uid_t uid; | |||
| 129 | gid_t gid; | |||
| 130 | int r, c; | |||
| 131 | ||||
| 132 | #define MAX_PERMS((unsigned long) (0x01000000|0x02000000|0x08000000| 0x00010000 |0x00020000|0x00080000)) ((unsigned long) (KEY_POS_VIEW0x01000000|KEY_POS_READ0x02000000|KEY_POS_SEARCH0x08000000| \ | |||
| 133 | KEY_USR_VIEW0x00010000|KEY_USR_READ0x00020000|KEY_USR_SEARCH0x00080000)) | |||
| 134 | ||||
| 135 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd/sd-id128/sd-id128.c" , 135, __PRETTY_FUNCTION__); } while (0); | |||
| ||||
| 136 | ||||
| 137 | key = request_keymissing_request_key("user", "invocation_id", NULL((void*)0), 0); | |||
| 138 | if (key == -1) { | |||
| 139 | /* Keyring support not available? No invocation key stored? */ | |||
| 140 | if (IN_SET(errno, ENOSYS, ENOKEY)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){38, 126})/sizeof(int)]; switch((*__errno_location ())) { case 38: case 126: _found = 1; break; default: break; } _found; })) | |||
| 141 | return 0; | |||
| 142 | ||||
| 143 | return -errno(*__errno_location ()); | |||
| 144 | } | |||
| 145 | ||||
| 146 | for (;;) { | |||
| 147 | description = new(char, sz)((char*) malloc_multiply(sizeof(char), (sz))); | |||
| 148 | if (!description) | |||
| 149 | return -ENOMEM12; | |||
| 150 | ||||
| 151 | c = keyctlmissing_keyctl(KEYCTL_DESCRIBE6, key, (unsigned long) description, sz, 0); | |||
| 152 | if (c < 0) | |||
| 153 | return -errno(*__errno_location ()); | |||
| 154 | ||||
| 155 | if ((size_t) c <= sz) | |||
| 156 | break; | |||
| 157 | ||||
| 158 | sz = c; | |||
| 159 | free(description); | |||
| 160 | } | |||
| 161 | ||||
| 162 | /* The kernel returns a final NUL in the string, verify that. */ | |||
| 163 | assert(description[c-1] == 0)do { if ((__builtin_expect(!!(!(description[c-1] == 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("description[c-1] == 0"), "../src/libsystemd/sd-id128/sd-id128.c" , 163, __PRETTY_FUNCTION__); } while (0); | |||
| ||||
| 164 | ||||
| 165 | /* Chop off the final description string */ | |||
| 166 | d = strrchr(description, ';'); | |||
| 167 | if (!d) | |||
| 168 | return -EIO5; | |||
| 169 | *d = 0; | |||
| 170 | ||||
| 171 | /* Look for the permissions */ | |||
| 172 | p = strrchr(description, ';'); | |||
| 173 | if (!p) | |||
| 174 | return -EIO5; | |||
| 175 | ||||
| 176 | errno(*__errno_location ()) = 0; | |||
| 177 | perms = strtoul(p + 1, &e, 16); | |||
| 178 | if (errno(*__errno_location ()) > 0) | |||
| 179 | return -errno(*__errno_location ()); | |||
| 180 | if (e == p + 1) /* Read at least one character */ | |||
| 181 | return -EIO5; | |||
| 182 | if (e != d) /* Must reached the end */ | |||
| 183 | return -EIO5; | |||
| 184 | ||||
| 185 | if ((perms & ~MAX_PERMS((unsigned long) (0x01000000|0x02000000|0x08000000| 0x00010000 |0x00020000|0x00080000))) != 0) | |||
| 186 | return -EPERM1; | |||
| 187 | ||||
| 188 | *p = 0; | |||
| 189 | ||||
| 190 | /* Look for the group ID */ | |||
| 191 | g = strrchr(description, ';'); | |||
| 192 | if (!g) | |||
| 193 | return -EIO5; | |||
| 194 | r = parse_gid(g + 1, &gid); | |||
| 195 | if (r < 0) | |||
| 196 | return r; | |||
| 197 | if (gid != 0) | |||
| 198 | return -EPERM1; | |||
| 199 | *g = 0; | |||
| 200 | ||||
| 201 | /* Look for the user ID */ | |||
| 202 | u = strrchr(description, ';'); | |||
| 203 | if (!u) | |||
| 204 | return -EIO5; | |||
| 205 | r = parse_uid(u + 1, &uid); | |||
| 206 | if (r < 0) | |||
| 207 | return r; | |||
| 208 | if (uid != 0) | |||
| 209 | return -EPERM1; | |||
| 210 | ||||
| 211 | c = keyctlmissing_keyctl(KEYCTL_READ11, key, (unsigned long) ret, sizeof(sd_id128_t), 0); | |||
| 212 | if (c < 0) | |||
| 213 | return -errno(*__errno_location ()); | |||
| 214 | if (c != sizeof(sd_id128_t)) | |||
| 215 | return -EIO5; | |||
| 216 | ||||
| 217 | return 1; | |||
| 218 | } | |||
| 219 | ||||
| 220 | _public___attribute__ ((visibility("default"))) int sd_id128_get_invocation(sd_id128_t *ret) { | |||
| 221 | static thread_local__thread sd_id128_t saved_invocation_id = {}; | |||
| 222 | int r; | |||
| 223 | ||||
| 224 | assert_return(ret, -EINVAL)do { if (!(((__builtin_expect(!!(ret),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd/sd-id128/sd-id128.c" , 224, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 225 | ||||
| 226 | if (sd_id128_is_null(saved_invocation_id)) { | |||
| 227 | ||||
| 228 | /* We first try to read the invocation ID from the kernel keyring. This has the benefit that it is not | |||
| 229 | * fakeable by unprivileged code. If the information is not available in the keyring, we use | |||
| 230 | * $INVOCATION_ID but ignore the data if our process was called by less privileged code | |||
| 231 | * (i.e. secure_getenv() instead of getenv()). | |||
| 232 | * | |||
| 233 | * The kernel keyring is only relevant for system services (as for user services we don't store the | |||
| 234 | * invocation ID in the keyring, as there'd be no trust benefit in that). The environment variable is | |||
| 235 | * primarily relevant for user services, and sufficiently safe as no privilege boundary is involved. */ | |||
| 236 | ||||
| 237 | r = get_invocation_from_keyring(&saved_invocation_id); | |||
| 238 | if (r < 0) | |||
| 239 | return r; | |||
| 240 | ||||
| 241 | if (r == 0) { | |||
| 242 | const char *e; | |||
| 243 | ||||
| 244 | e = secure_getenv("INVOCATION_ID"); | |||
| 245 | if (!e) | |||
| 246 | return -ENXIO6; | |||
| 247 | ||||
| 248 | r = sd_id128_from_string(e, &saved_invocation_id); | |||
| 249 | if (r < 0) | |||
| 250 | return r; | |||
| 251 | } | |||
| 252 | } | |||
| 253 | ||||
| 254 | *ret = saved_invocation_id; | |||
| 255 | return 0; | |||
| 256 | } | |||
| 257 | ||||
| 258 | static sd_id128_t make_v4_uuid(sd_id128_t id) { | |||
| 259 | /* Stolen from generate_random_uuid() of drivers/char/random.c | |||
| 260 | * in the kernel sources */ | |||
| 261 | ||||
| 262 | /* Set UUID version to 4 --- truly random generation */ | |||
| 263 | id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40; | |||
| 264 | ||||
| 265 | /* Set the UUID variant to DCE */ | |||
| 266 | id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80; | |||
| 267 | ||||
| 268 | return id; | |||
| 269 | } | |||
| 270 | ||||
| 271 | _public___attribute__ ((visibility("default"))) int sd_id128_randomize(sd_id128_t *ret) { | |||
| 272 | sd_id128_t t; | |||
| 273 | int r; | |||
| 274 | ||||
| 275 | assert_return(ret, -EINVAL)do { if (!(((__builtin_expect(!!(ret),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd/sd-id128/sd-id128.c" , 275, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 276 | ||||
| 277 | r = acquire_random_bytes(&t, sizeof t, true1); | |||
| 278 | if (r < 0) | |||
| 279 | return r; | |||
| 280 | ||||
| 281 | /* Turn this into a valid v4 UUID, to be nice. Note that we | |||
| 282 | * only guarantee this for newly generated UUIDs, not for | |||
| 283 | * pre-existing ones. */ | |||
| 284 | ||||
| 285 | *ret = make_v4_uuid(t); | |||
| 286 | return 0; | |||
| 287 | } | |||
| 288 | ||||
| 289 | _public___attribute__ ((visibility("default"))) int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret) { | |||
| 290 | _cleanup_(khash_unrefp)__attribute__((cleanup(khash_unrefp))) khash *h = NULL((void*)0); | |||
| 291 | sd_id128_t m, result; | |||
| 292 | const void *p; | |||
| 293 | int r; | |||
| 294 | ||||
| 295 | assert_return(ret, -EINVAL)do { if (!(((__builtin_expect(!!(ret),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/libsystemd/sd-id128/sd-id128.c" , 295, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 296 | ||||
| 297 | r = sd_id128_get_machine(&m); | |||
| 298 | if (r < 0) | |||
| 299 | return r; | |||
| 300 | ||||
| 301 | r = khash_new_with_key(&h, "hmac(sha256)", &m, sizeof(m)); | |||
| 302 | if (r < 0) | |||
| 303 | return r; | |||
| 304 | ||||
| 305 | r = khash_put(h, &app_id, sizeof(app_id)); | |||
| 306 | if (r < 0) | |||
| 307 | return r; | |||
| 308 | ||||
| 309 | r = khash_digest_data(h, &p); | |||
| 310 | if (r < 0) | |||
| 311 | return r; | |||
| 312 | ||||
| 313 | /* We chop off the trailing 16 bytes */ | |||
| 314 | memcpy(&result, p, MIN(khash_get_size(h), sizeof(result))__extension__ ({ const typeof((khash_get_size(h))) __unique_prefix_A6 = ((khash_get_size(h))); const typeof((sizeof(result))) __unique_prefix_B7 = ((sizeof(result))); __unique_prefix_A6 < __unique_prefix_B7 ? __unique_prefix_A6 : __unique_prefix_B7; })); | |||
| 315 | ||||
| 316 | *ret = make_v4_uuid(result); | |||
| 317 | return 0; | |||
| 318 | } |
| 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 | }) |