Bug Summary

File:build-scan/../src/import/qcow2-util.c
Warning:line 253, column 25
Potential leak of memory pointed to by 'l1_table'

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 qcow2-util.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 static -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 systemd-import.p -I . -I .. -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 -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 hidden -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/import/qcow2-util.c

../src/import/qcow2-util.c

1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <zlib.h>
4
5#include "alloc-util.h"
6#include "btrfs-util.h"
7#include "qcow2-util.h"
8#include "sparse-endian.h"
9#include "util.h"
10
11#define QCOW2_MAGIC0x514649fb 0x514649fb
12
13#define QCOW2_COPIED(1ULL << 63) (1ULL << 63)
14#define QCOW2_COMPRESSED(1ULL << 62) (1ULL << 62)
15#define QCOW2_ZERO(1ULL << 0) (1ULL << 0)
16
17typedef struct _packed___attribute__ ((packed)) Header {
18 be32_t magic;
19 be32_t version;
20
21 be64_t backing_file_offset;
22 be32_t backing_file_size;
23
24 be32_t cluster_bits;
25 be64_t size;
26 be32_t crypt_method;
27
28 be32_t l1_size;
29 be64_t l1_table_offset;
30
31 be64_t refcount_table_offset;
32 be32_t refcount_table_clusters;
33
34 be32_t nb_snapshots;
35 be64_t snapshots_offset;
36
37 /* The remainder is only present on QCOW3 */
38 be64_t incompatible_features;
39 be64_t compatible_features;
40 be64_t autoclear_features;
41
42 be32_t refcount_order;
43 be32_t header_length;
44} Header;
45
46#define HEADER_MAGIC(header)be32toh((header)->magic) be32toh((header)->magic)
47#define HEADER_VERSION(header)be32toh((header)->version) be32toh((header)->version)
48#define HEADER_CLUSTER_BITS(header)be32toh((header)->cluster_bits) be32toh((header)->cluster_bits)
49#define HEADER_CLUSTER_SIZE(header)(1ULL << be32toh((header)->cluster_bits)) (1ULL << HEADER_CLUSTER_BITS(header)be32toh((header)->cluster_bits))
50#define HEADER_L2_BITS(header)(be32toh((header)->cluster_bits) - 3) (HEADER_CLUSTER_BITS(header)be32toh((header)->cluster_bits) - 3)
51#define HEADER_SIZE(header)be64toh((header)->size) be64toh((header)->size)
52#define HEADER_CRYPT_METHOD(header)be32toh((header)->crypt_method) be32toh((header)->crypt_method)
53#define HEADER_L1_SIZE(header)be32toh((header)->l1_size) be32toh((header)->l1_size)
54#define HEADER_L2_SIZE(header)((1ULL << be32toh((header)->cluster_bits))/sizeof(uint64_t
))
(HEADER_CLUSTER_SIZE(header)(1ULL << be32toh((header)->cluster_bits))/sizeof(uint64_t))
55#define HEADER_L1_TABLE_OFFSET(header)be64toh((header)->l1_table_offset) be64toh((header)->l1_table_offset)
56
57static uint32_t HEADER_HEADER_LENGTH(const Header *h) {
58 if (HEADER_VERSION(h)be32toh((h)->version) < 3)
59 return offsetof(Header, incompatible_features)__builtin_offsetof(Header, incompatible_features);
60
61 return be32toh(h->header_length);
62}
63
64static int copy_cluster(
65 int sfd, uint64_t soffset,
66 int dfd, uint64_t doffset,
67 uint64_t cluster_size,
68 void *buffer) {
69
70 ssize_t l;
71 int r;
72
73 r = btrfs_clone_range(sfd, soffset, dfd, doffset, cluster_size);
74 if (r >= 0)
75 return r;
76
77 l = pread(sfd, buffer, cluster_size, soffset);
78 if (l < 0)
79 return -errno(*__errno_location ());
80 if ((uint64_t) l != cluster_size)
81 return -EIO5;
82
83 l = pwrite(dfd, buffer, cluster_size, doffset);
84 if (l < 0)
85 return -errno(*__errno_location ());
86 if ((uint64_t) l != cluster_size)
87 return -EIO5;
88
89 return 0;
90}
91
92static int decompress_cluster(
93 int sfd, uint64_t soffset,
94 int dfd, uint64_t doffset,
95 uint64_t compressed_size,
96 uint64_t cluster_size,
97 void *buffer1,
98 void *buffer2) {
99
100 _cleanup_free___attribute__((cleanup(freep))) void *large_buffer = NULL((void*)0);
101 z_stream s = {};
102 uint64_t sz;
103 ssize_t l;
104 int r;
105
106 if (compressed_size > cluster_size) {
107 /* The usual cluster buffer doesn't suffice, let's
108 * allocate a larger one, temporarily */
109
110 large_buffer = malloc(compressed_size);
111 if (!large_buffer)
112 return -ENOMEM12;
113
114 buffer1 = large_buffer;
115 }
116
117 l = pread(sfd, buffer1, compressed_size, soffset);
118 if (l < 0)
119 return -errno(*__errno_location ());
120 if ((uint64_t) l != compressed_size)
121 return -EIO5;
122
123 s.next_in = buffer1;
124 s.avail_in = compressed_size;
125 s.next_out = buffer2;
126 s.avail_out = cluster_size;
127
128 r = inflateInit2(&s, -12)inflateInit2_((&s), (-12), "1.2.11", (int)sizeof(z_stream
))
;
129 if (r != Z_OK0)
130 return -EIO5;
131
132 r = inflate(&s, Z_FINISH4);
133 sz = (uint8_t*) s.next_out - (uint8_t*) buffer2;
134 inflateEnd(&s);
135 if (r != Z_STREAM_END1 || sz != cluster_size)
136 return -EIO5;
137
138 l = pwrite(dfd, buffer2, cluster_size, doffset);
139 if (l < 0)
140 return -errno(*__errno_location ());
141 if ((uint64_t) l != cluster_size)
142 return -EIO5;
143
144 return 0;
145}
146
147static int normalize_offset(
148 const Header *header,
149 uint64_t p,
150 uint64_t *ret,
151 bool_Bool *compressed,
152 uint64_t *compressed_size) {
153
154 uint64_t q;
155
156 q = be64toh(p);
157
158 if (q & QCOW2_COMPRESSED(1ULL << 62)) {
159 uint64_t sz, csize_shift, csize_mask;
160
161 if (!compressed)
162 return -EOPNOTSUPP95;
163
164 csize_shift = 64 - 2 - (HEADER_CLUSTER_BITS(header)be32toh((header)->cluster_bits) - 8);
165 csize_mask = (1ULL << (HEADER_CLUSTER_BITS(header)be32toh((header)->cluster_bits) - 8)) - 1;
166 sz = (((q >> csize_shift) & csize_mask) + 1) * 512 - (q & 511);
167 q &= ((1ULL << csize_shift) - 1);
168
169 if (compressed_size)
170 *compressed_size = sz;
171
172 *compressed = true1;
173
174 } else {
175 if (compressed) {
176 *compressed = false0;
177 *compressed_size = 0;
178 }
179
180 if (q & QCOW2_ZERO(1ULL << 0)) {
181 /* We make no distinction between zero blocks and holes */
182 *ret = 0;
183 return 0;
184 }
185
186 q &= ~QCOW2_COPIED(1ULL << 63);
187 }
188
189 *ret = q;
190 return q > 0; /* returns positive if not a hole */
191}
192
193static int verify_header(const Header *header) {
194 assert(header)do { if ((__builtin_expect(!!(!(header)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("header"), "../src/import/qcow2-util.c",
194, __PRETTY_FUNCTION__); } while (0)
;
195
196 if (HEADER_MAGIC(header)be32toh((header)->magic) != QCOW2_MAGIC0x514649fb)
197 return -EBADMSG74;
198
199 if (!IN_SET(HEADER_VERSION(header), 2, 3)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){2, 3})/sizeof(int)]; switch(be32toh((header
)->version)) { case 2: case 3: _found = 1; break; default:
break; } _found; })
)
200 return -EOPNOTSUPP95;
201
202 if (HEADER_CRYPT_METHOD(header)be32toh((header)->crypt_method) != 0)
203 return -EOPNOTSUPP95;
204
205 if (HEADER_CLUSTER_BITS(header)be32toh((header)->cluster_bits) < 9) /* 512K */
206 return -EBADMSG74;
207
208 if (HEADER_CLUSTER_BITS(header)be32toh((header)->cluster_bits) > 21) /* 2MB */
209 return -EBADMSG74;
210
211 if (HEADER_SIZE(header)be64toh((header)->size) % HEADER_CLUSTER_SIZE(header)(1ULL << be32toh((header)->cluster_bits)) != 0)
212 return -EBADMSG74;
213
214 if (HEADER_L1_SIZE(header)be32toh((header)->l1_size) > 32*1024*1024) /* 32MB */
215 return -EBADMSG74;
216
217 if (HEADER_VERSION(header)be32toh((header)->version) == 3) {
218
219 if (header->incompatible_features != 0)
220 return -EOPNOTSUPP95;
221
222 if (HEADER_HEADER_LENGTH(header) < sizeof(Header))
223 return -EBADMSG74;
224 }
225
226 return 0;
227}
228
229int qcow2_convert(int qcow2_fd, int raw_fd) {
230 _cleanup_free___attribute__((cleanup(freep))) void *buffer1 = NULL((void*)0), *buffer2 = NULL((void*)0);
231 _cleanup_free___attribute__((cleanup(freep))) be64_t *l1_table = NULL((void*)0), *l2_table = NULL((void*)0);
232 uint64_t sz, i;
233 Header header;
234 ssize_t l;
235 int r;
236
237 l = pread(qcow2_fd, &header, sizeof(header), 0);
238 if (l < 0)
1
Assuming 'l' is >= 0
2
Taking false branch
239 return -errno(*__errno_location ());
240 if (l != sizeof(header))
3
Assuming the condition is false
4
Taking false branch
241 return -EIO5;
242
243 r = verify_header(&header);
244 if (r
4.1
'r' is >= 0
4.1
'r' is >= 0
< 0)
5
Taking false branch
245 return r;
246
247 l1_table = new(be64_t, HEADER_L1_SIZE(&header))((be64_t*) malloc_multiply(sizeof(be64_t), (be32toh((&header
)->l1_size))))
;
6
Calling 'malloc_multiply'
9
Returned allocated memory
248 if (!l1_table)
10
Assuming 'l1_table' is non-null
11
Taking false branch
249 return -ENOMEM12;
250
251 l2_table = malloc(HEADER_CLUSTER_SIZE(&header)(1ULL << be32toh((&header)->cluster_bits)));
252 if (!l2_table)
12
Assuming 'l2_table' is null
13
Taking true branch
253 return -ENOMEM12;
14
Potential leak of memory pointed to by 'l1_table'
254
255 buffer1 = malloc(HEADER_CLUSTER_SIZE(&header)(1ULL << be32toh((&header)->cluster_bits)));
256 if (!buffer1)
257 return -ENOMEM12;
258
259 buffer2 = malloc(HEADER_CLUSTER_SIZE(&header)(1ULL << be32toh((&header)->cluster_bits)));
260 if (!buffer2)
261 return -ENOMEM12;
262
263 /* Empty the file if it exists, we rely on zero bits */
264 if (ftruncate(raw_fd, 0) < 0)
265 return -errno(*__errno_location ());
266
267 if (ftruncate(raw_fd, HEADER_SIZE(&header)be64toh((&header)->size)) < 0)
268 return -errno(*__errno_location ());
269
270 sz = sizeof(uint64_t) * HEADER_L1_SIZE(&header)be32toh((&header)->l1_size);
271 l = pread(qcow2_fd, l1_table, sz, HEADER_L1_TABLE_OFFSET(&header)be64toh((&header)->l1_table_offset));
272 if (l < 0)
273 return -errno(*__errno_location ());
274 if ((uint64_t) l != sz)
275 return -EIO5;
276
277 for (i = 0; i < HEADER_L1_SIZE(&header)be32toh((&header)->l1_size); i ++) {
278 uint64_t l2_begin, j;
279
280 r = normalize_offset(&header, l1_table[i], &l2_begin, NULL((void*)0), NULL((void*)0));
281 if (r < 0)
282 return r;
283 if (r == 0)
284 continue;
285
286 l = pread(qcow2_fd, l2_table, HEADER_CLUSTER_SIZE(&header)(1ULL << be32toh((&header)->cluster_bits)), l2_begin);
287 if (l < 0)
288 return -errno(*__errno_location ());
289 if ((uint64_t) l != HEADER_CLUSTER_SIZE(&header)(1ULL << be32toh((&header)->cluster_bits)))
290 return -EIO5;
291
292 for (j = 0; j < HEADER_L2_SIZE(&header)((1ULL << be32toh((&header)->cluster_bits))/sizeof
(uint64_t))
; j++) {
293 uint64_t data_begin, p, compressed_size;
294 bool_Bool compressed;
295
296 p = ((i << HEADER_L2_BITS(&header)(be32toh((&header)->cluster_bits) - 3)) + j) << HEADER_CLUSTER_BITS(&header)be32toh((&header)->cluster_bits);
297
298 r = normalize_offset(&header, l2_table[j], &data_begin, &compressed, &compressed_size);
299 if (r < 0)
300 return r;
301 if (r == 0)
302 continue;
303
304 if (compressed)
305 r = decompress_cluster(
306 qcow2_fd, data_begin,
307 raw_fd, p,
308 compressed_size, HEADER_CLUSTER_SIZE(&header)(1ULL << be32toh((&header)->cluster_bits)),
309 buffer1, buffer2);
310 else
311 r = copy_cluster(
312 qcow2_fd, data_begin,
313 raw_fd, p,
314 HEADER_CLUSTER_SIZE(&header)(1ULL << be32toh((&header)->cluster_bits)), buffer1);
315 if (r < 0)
316 return r;
317 }
318 }
319
320 return 0;
321}
322
323int qcow2_detect(int fd) {
324 be32_t id;
325 ssize_t l;
326
327 l = pread(fd, &id, sizeof(id), 0);
328 if (l < 0)
329 return -errno(*__errno_location ());
330 if (l != sizeof(id))
331 return -EIO5;
332
333 return htobe32(QCOW2_MAGIC0x514649fb) == id;
334}

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