Coverage Report

Created: 2023-12-14 14:24

/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
link-config.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"