File: | build-scan/../src/libsystemd/sd-id128/sd-id128.c |
Warning: | line 153, column 33 Potential leak of memory pointed to by 'description' |
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_A4 = ((khash_get_size(h))); const typeof((sizeof(result))) __unique_prefix_B5 = ((sizeof(result))); __unique_prefix_A4 < __unique_prefix_B5 ? __unique_prefix_A4 : __unique_prefix_B5; })); | |||
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 | }) |