/src/systemd/src/basic/alloc-util.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
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 | | #if HAS_FEATURE_MEMORY_SANITIZER |
12 | | # include <sanitizer/msan_interface.h> |
13 | | #endif |
14 | | |
15 | | typedef void (*free_func_t)(void *p); |
16 | | typedef void* (*mfree_func_t)(void *p); |
17 | | |
18 | | /* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than |
19 | | * proceeding and smashing the stack limits. Note that by default RLIMIT_STACK is 8M on Linux. */ |
20 | | #define ALLOCA_MAX (4U*1024U*1024U) |
21 | | |
22 | 152k | #define new(t, n) ((t*) malloc_multiply(sizeof(t), (n))) |
23 | | |
24 | 166k | #define new0(t, n) ((t*) calloc((n) ?: 1, sizeof(t))) |
25 | | |
26 | | #define alloca_safe(n) \ |
27 | 61.4k | ({ \ |
28 | 61.4k | size_t _nn_ = n; \ |
29 | 61.4k | assert(_nn_ <= ALLOCA_MAX); \ |
30 | 61.4k | alloca(_nn_ == 0 ? 1 : _nn_); \ |
31 | 61.4k | }) \ |
32 | | |
33 | | #define newa(t, n) \ |
34 | 61.4k | ({ \ |
35 | 61.4k | size_t _n_ = n; \ |
36 | 61.4k | assert(!size_multiply_overflow(sizeof(t), _n_)); \ |
37 | 61.4k | (t*) alloca_safe(sizeof(t)*_n_); \ |
38 | 61.4k | }) |
39 | | |
40 | | #define newa0(t, n) \ |
41 | | ({ \ |
42 | | size_t _n_ = n; \ |
43 | | assert(!size_multiply_overflow(sizeof(t), _n_)); \ |
44 | | (t*) alloca0((sizeof(t)*_n_)); \ |
45 | | }) |
46 | | |
47 | | #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) |
48 | | |
49 | | #define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) |
50 | | |
51 | | #define malloc0(n) (calloc(1, (n) ?: 1)) |
52 | | |
53 | | #define free_and_replace_full(a, b, free_func) \ |
54 | 159k | ({ \ |
55 | 159k | typeof(a)* _a = &(a); \ |
56 | 159k | typeof(b)* _b = &(b); \ |
57 | 159k | free_func(*_a); \ |
58 | 159k | *_a = *_b; \ |
59 | 159k | *_b = NULL; \ |
60 | 159k | 0; \ |
61 | 159k | }) |
62 | | |
63 | | #define free_and_replace(a, b) \ |
64 | 159k | free_and_replace_full(a, b, free) |
65 | | |
66 | | /* This is similar to free_and_replace_full(), but NULL is not assigned to 'b', and its reference counter is |
67 | | * increased. */ |
68 | | #define unref_and_replace_full(a, b, ref_func, unref_func) \ |
69 | | ({ \ |
70 | | typeof(a)* _a = &(a); \ |
71 | | typeof(b) _b = ref_func(b); \ |
72 | | unref_func(*_a); \ |
73 | | *_a = _b; \ |
74 | | 0; \ |
75 | | }) |
76 | | |
77 | | void* memdup(const void *p, size_t l) _alloc_(2); |
78 | | void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, since we return a buffer one byte larger than the specified size */ |
79 | | |
80 | | #define memdupa(p, l) \ |
81 | | ({ \ |
82 | | void *_q_; \ |
83 | | size_t _l_ = l; \ |
84 | | _q_ = alloca_safe(_l_); \ |
85 | | memcpy_safe(_q_, p, _l_); \ |
86 | | }) |
87 | | |
88 | | #define memdupa_suffix0(p, l) \ |
89 | | ({ \ |
90 | | void *_q_; \ |
91 | | size_t _l_ = l; \ |
92 | | _q_ = alloca_safe(_l_ + 1); \ |
93 | | ((uint8_t*) _q_)[_l_] = 0; \ |
94 | | memcpy_safe(_q_, p, _l_); \ |
95 | | }) |
96 | | |
97 | 0 | static inline void unsetp(void *p) { |
98 | 0 | /* A trivial "destructor" that can be used in cases where we want to |
99 | 0 | * unset a pointer from a _cleanup_ function. */ |
100 | 0 |
|
101 | 0 | *(void**)p = NULL; |
102 | 0 | } Unexecuted instantiation: fuzz-link-parser.c:unsetp Unexecuted instantiation: link-config.c:unsetp Unexecuted instantiation: link-config-gperf.c:unsetp |
103 | | |
104 | 922k | static inline void freep(void *p) { |
105 | 922k | *(void**)p = mfree(*(void**) p); |
106 | 922k | } Unexecuted instantiation: fuzz-link-parser.c:freep Line | Count | Source | 104 | 922k | static inline void freep(void *p) { | 105 | 922k | *(void**)p = mfree(*(void**) p); | 106 | 922k | } |
Unexecuted instantiation: link-config-gperf.c:freep |
107 | | |
108 | 919k | #define _cleanup_free_ _cleanup_(freep) |
109 | | |
110 | 213k | static inline bool size_multiply_overflow(size_t size, size_t need) { |
111 | 213k | return _unlikely_(need != 0 && size > (SIZE_MAX / need)); |
112 | 213k | } Unexecuted instantiation: fuzz-link-parser.c:size_multiply_overflow link-config.c:size_multiply_overflow Line | Count | Source | 110 | 213k | static inline bool size_multiply_overflow(size_t size, size_t need) { | 111 | 213k | return _unlikely_(need != 0 && size > (SIZE_MAX / need)); | 112 | 213k | } |
Unexecuted instantiation: link-config-gperf.c:size_multiply_overflow |
113 | | |
114 | 152k | _malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) { |
115 | 152k | if (size_multiply_overflow(size, need)) |
116 | 0 | return NULL; |
117 | | |
118 | 152k | return malloc(size * need ?: 1); |
119 | 152k | } Unexecuted instantiation: fuzz-link-parser.c:malloc_multiply link-config.c:malloc_multiply Line | Count | Source | 114 | 152k | _malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) { | 115 | 152k | if (size_multiply_overflow(size, need)) | 116 | 0 | return NULL; | 117 | | | 118 | 152k | return malloc(size * need ?: 1); | 119 | 152k | } |
Unexecuted instantiation: link-config-gperf.c:malloc_multiply |
120 | | |
121 | | #if !HAVE_REALLOCARRAY |
122 | | _alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) { |
123 | | if (size_multiply_overflow(size, need)) |
124 | | return NULL; |
125 | | |
126 | | return realloc(p, size * need ?: 1); |
127 | | } |
128 | | #endif |
129 | | |
130 | 0 | _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) { |
131 | 0 | if (size_multiply_overflow(size, need)) |
132 | 0 | return NULL; |
133 | 0 |
|
134 | 0 | return memdup(p, size * need); |
135 | 0 | } Unexecuted instantiation: fuzz-link-parser.c:memdup_multiply Unexecuted instantiation: link-config.c:memdup_multiply Unexecuted instantiation: link-config-gperf.c:memdup_multiply |
136 | | |
137 | | /* Note that we can't decorate this function with _alloc_() since the returned memory area is one byte larger |
138 | | * than the product of its parameters. */ |
139 | 0 | static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) { |
140 | 0 | if (size_multiply_overflow(size, need)) |
141 | 0 | return NULL; |
142 | 0 |
|
143 | 0 | return memdup_suffix0(p, size * need); |
144 | 0 | } Unexecuted instantiation: fuzz-link-parser.c:memdup_suffix0_multiply Unexecuted instantiation: link-config.c:memdup_suffix0_multiply Unexecuted instantiation: link-config-gperf.c:memdup_suffix0_multiply |
145 | | |
146 | | void* greedy_realloc(void **p, size_t need, size_t size); |
147 | | void* greedy_realloc0(void **p, size_t need, size_t size); |
148 | | |
149 | | #define GREEDY_REALLOC(array, need) \ |
150 | | greedy_realloc((void**) &(array), (need), sizeof((array)[0])) |
151 | | |
152 | | #define GREEDY_REALLOC0(array, need) \ |
153 | | greedy_realloc0((void**) &(array), (need), sizeof((array)[0])) |
154 | | |
155 | | #define alloca0(n) \ |
156 | | ({ \ |
157 | | char *_new_; \ |
158 | | size_t _len_ = n; \ |
159 | | _new_ = alloca_safe(_len_); \ |
160 | | memset(_new_, 0, _len_); \ |
161 | | }) |
162 | | |
163 | | /* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ |
164 | | #define alloca_align(size, align) \ |
165 | | ({ \ |
166 | | void *_ptr_; \ |
167 | | size_t _mask_ = (align) - 1; \ |
168 | | size_t _size_ = size; \ |
169 | | _ptr_ = alloca_safe(_size_ + _mask_); \ |
170 | | (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ |
171 | | }) |
172 | | |
173 | | #define alloca0_align(size, align) \ |
174 | | ({ \ |
175 | | void *_new_; \ |
176 | | size_t _xsize_ = (size); \ |
177 | | _new_ = alloca_align(_xsize_, (align)); \ |
178 | | memset(_new_, 0, _xsize_); \ |
179 | | }) |
180 | | |
181 | | #if HAS_FEATURE_MEMORY_SANITIZER |
182 | | # define msan_unpoison(r, s) __msan_unpoison(r, s) |
183 | | #else |
184 | | # define msan_unpoison(r, s) |
185 | | #endif |
186 | | |
187 | | /* This returns the number of usable bytes in a malloc()ed region as per malloc_usable_size(), in a way that |
188 | | * is compatible with _FORTIFY_SOURCES. If _FORTIFY_SOURCES is used many memory operations will take the |
189 | | * object size as returned by __builtin_object_size() into account. Hence, let's return the smaller size of |
190 | | * malloc_usable_size() and __builtin_object_size() here, so that we definitely operate in safe territory by |
191 | | * both the compiler's and libc's standards. Note that __builtin_object_size() evaluates to SIZE_MAX if the |
192 | | * size cannot be determined, hence the MIN() expression should be safe with dynamically sized memory, |
193 | | * too. Moreover, when NULL is passed malloc_usable_size() is documented to return zero, and |
194 | | * __builtin_object_size() returns SIZE_MAX too, hence we also return a sensible value of 0 in this corner |
195 | | * case. */ |
196 | | #define MALLOC_SIZEOF_SAFE(x) \ |
197 | 29.4k | MIN(malloc_usable_size(x), __builtin_object_size(x, 0)) |
198 | | |
199 | | /* Inspired by ELEMENTSOF() but operates on malloc()'ed memory areas: typesafely returns the number of items |
200 | | * that fit into the specified memory block */ |
201 | | #define MALLOC_ELEMENTSOF(x) \ |
202 | | (__builtin_choose_expr( \ |
203 | | __builtin_types_compatible_p(typeof(x), typeof(&*(x))), \ |
204 | | MALLOC_SIZEOF_SAFE(x)/sizeof((x)[0]), \ |
205 | | VOID_0)) |
206 | | |
207 | | |
208 | | /* These are like strdupa()/strndupa(), but honour ALLOCA_MAX */ |
209 | | #define strdupa_safe(s) \ |
210 | | ({ \ |
211 | | const char *_t = (s); \ |
212 | | (char*) memdupa_suffix0(_t, strlen(_t)); \ |
213 | | }) |
214 | | |
215 | | #define strndupa_safe(s, n) \ |
216 | | ({ \ |
217 | | const char *_t = (s); \ |
218 | | (char*) memdupa_suffix0(_t, strnlen(_t, (n))); \ |
219 | | }) |
220 | | |
221 | | #include "memory-util.h" |