Commit | Line | Data |
---|---|---|
990570ed | 1 | /* |
21cf9b6b | 2 | * Copyright (C) 2011 EfficiOS Inc. |
ab5be9fa | 3 | * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
990570ed | 4 | * |
ab5be9fa | 5 | * SPDX-License-Identifier: GPL-2.0-only |
990570ed | 6 | * |
990570ed DG |
7 | */ |
8 | ||
9 | #ifndef _MACROS_H | |
10 | #define _MACROS_H | |
11 | ||
64803277 SM |
12 | #include <common/compat/string.hpp> |
13 | ||
93375aa6 | 14 | #include <stddef.h> |
64803277 | 15 | #include <stdlib.h> |
f6835b82 | 16 | #include <string.h> |
64803277 SM |
17 | |
18 | #include <type_traits> | |
990570ed DG |
19 | |
20 | /* | |
21 | * Takes a pointer x and transform it so we can use it to access members | |
22 | * without a function call. Here an example: | |
23 | * | |
24 | * #define GET_SIZE(x) LTTNG_REF(x)->size | |
25 | * | |
26 | * struct { int size; } s; | |
27 | * | |
28 | * printf("size : %d\n", GET_SIZE(&s)); | |
29 | * | |
30 | * For this example we can't use something like this for compatibility purpose | |
31 | * since this will fail: | |
32 | * | |
33 | * #define GET_SIZE(x) x->size; | |
34 | * | |
35 | * This is mostly use for the compatibility layer of lttng-tools. See | |
36 | * poll/epoll for a good example. Since x can be on the stack or allocated | |
37 | * memory using malloc(), we must use generic accessors for compat in order to | |
38 | * *not* use a function to access members and not the variable name. | |
39 | */ | |
40 | #define LTTNG_REF(x) ((typeof(*x) *)(x)) | |
41 | ||
64803277 SM |
42 | #ifdef NDEBUG |
43 | /* | |
44 | * Force usage of the assertion condition to prevent unused variable warnings | |
45 | * when `assert()` are disabled by the `NDEBUG` definition. | |
46 | */ | |
47 | # define LTTNG_ASSERT(_cond) ((void) sizeof((void) (_cond), 0)) | |
48 | #else | |
49 | # include <assert.h> | |
50 | # define LTTNG_ASSERT(_cond) assert(_cond) | |
51 | #endif | |
52 | ||
990570ed DG |
53 | /* |
54 | * Memory allocation zeroed | |
55 | */ | |
64803277 | 56 | |
4616a46c | 57 | static inline |
64803277 SM |
58 | void *zmalloc_internal(size_t size) |
59 | { | |
60 | return calloc(1, size); | |
61 | } | |
62 | ||
63 | template <typename T> | |
64 | struct can_malloc | |
65 | { | |
f12e33ba JG |
66 | /* |
67 | * gcc versions before 5.0 lack some type traits defined in C++11. | |
68 | * Since in this instance we use the trait to prevent misuses | |
69 | * of malloc (and statically assert) and not to generate different | |
70 | * code based on this property, simply set value to true and allow | |
71 | * the code to compile. Anyone using a contemporary compiler will | |
72 | * catch the error. | |
73 | */ | |
74 | #if __GNUG__ && __GNUC__ < 5 | |
75 | static constexpr bool value = true; | |
76 | #else | |
64803277 | 77 | static constexpr bool value = std::is_trivially_constructible<T>::value; |
f12e33ba | 78 | #endif |
64803277 SM |
79 | }; |
80 | ||
81 | /* | |
82 | * Malloc and zero-initialize an object of type T, asserting that T can be | |
83 | * safely malloc-ed (is trivially constructible). | |
84 | */ | |
85 | template<typename T> | |
86 | T *zmalloc() | |
87 | { | |
88 | static_assert (can_malloc<T>::value, "type can be malloc'ed"); | |
89 | return (T *) zmalloc_internal(sizeof(T)); | |
90 | } | |
91 | ||
92 | /* | |
93 | * Malloc and zero-initialize a buffer of size `size`, asserting that type T | |
94 | * can be safely malloc-ed (is trivially constructible). | |
95 | */ | |
96 | template<typename T> | |
97 | T *zmalloc(size_t size) | |
98 | { | |
99 | static_assert (can_malloc<T>::value, "type can be malloc'ed"); | |
100 | LTTNG_ASSERT(size >= sizeof(T)); | |
101 | return (T *) zmalloc_internal(size); | |
102 | } | |
103 | ||
104 | /* | |
105 | * Malloc and zero-initialize an array of `nmemb` elements of type T, | |
106 | * asserting that T can be safely malloc-ed (is trivially constructible). | |
107 | */ | |
108 | template<typename T> | |
109 | T *calloc(size_t nmemb) | |
110 | { | |
111 | static_assert (can_malloc<T>::value, "type can be malloc'ed"); | |
112 | return (T *) zmalloc_internal(nmemb * sizeof(T)); | |
113 | } | |
114 | ||
115 | /* | |
116 | * Malloc an object of type T, asserting that T can be safely malloc-ed (is | |
117 | * trivially constructible). | |
118 | */ | |
119 | template<typename T> | |
120 | T *malloc() | |
4616a46c | 121 | { |
64803277 SM |
122 | static_assert (can_malloc<T>::value, "type can be malloc'ed"); |
123 | return (T *) malloc(sizeof(T)); | |
4616a46c | 124 | } |
990570ed | 125 | |
64803277 SM |
126 | /* |
127 | * Malloc a buffer of size `size`, asserting that type T can be safely | |
128 | * malloc-ed (is trivially constructible). | |
129 | */ | |
130 | template<typename T> | |
131 | T *malloc(size_t size) | |
132 | { | |
133 | static_assert (can_malloc<T>::value, "type can be malloc'ed"); | |
134 | return (T *) malloc(size); | |
135 | } | |
136 | ||
137 | /* | |
138 | * Prevent using `free` on types that are non-POD. | |
139 | * | |
140 | * Declare a delete prototype of free if the parameter type is not safe to free | |
141 | * (non-POD). | |
142 | * | |
143 | * If the parameter is a pointer to void, we can't check if what is pointed | |
144 | * to is safe to free or not, as we don't know what is pointed to. Ideally, | |
145 | * all calls to free would be with a typed pointer, but there are too many | |
146 | * instances of passing a pointer to void to enforce that right now. So allow | |
147 | * pointers to void, these will not be checked. | |
148 | */ | |
149 | ||
150 | template<typename T> | |
a8e336c2 | 151 | struct can_free |
64803277 | 152 | { |
f12e33ba JG |
153 | /* |
154 | * gcc versions before 5.0 lack some type traits defined in C++11. | |
155 | * Since in this instance we use the trait to prevent misuses | |
156 | * of free (and statically assert) and not to generate different | |
157 | * code based on this property, simply set value to true and allow | |
158 | * the code to compile. Anyone using a contemporary compiler will | |
159 | * catch the error. | |
160 | */ | |
161 | #if __GNUG__ && __GNUC__ < 5 | |
162 | static constexpr bool value = true; | |
163 | #else | |
a8e336c2 | 164 | static constexpr bool value = std::is_trivially_destructible<T>::value || std::is_void<T>::value; |
f12e33ba | 165 | #endif |
64803277 SM |
166 | }; |
167 | ||
a8e336c2 | 168 | template<typename T, typename = typename std::enable_if<!can_free<T>::value>::type> |
64803277 SM |
169 | void free(T *p) = delete; |
170 | ||
a8e336c2 SM |
171 | template<typename T> |
172 | struct can_memset | |
173 | { | |
174 | static constexpr bool value = std::is_pod<T>::value || std::is_void<T>::value; | |
175 | }; | |
176 | ||
177 | template <typename T, typename = typename std::enable_if<!can_memset<T>::value>::type> | |
178 | void *memset(T *s, int c, size_t n) = delete; | |
179 | ||
180 | template<typename T> | |
181 | struct can_memcpy | |
182 | { | |
f12e33ba JG |
183 | /* |
184 | * gcc versions before 5.0 lack some type traits defined in C++11. | |
185 | * Since in this instance we use the trait to prevent misuses | |
186 | * of memcpy (and statically assert) and not to generate different | |
187 | * code based on this property, simply set value to true and allow | |
188 | * the code to compile. Anyone using a contemporary compiler will | |
189 | * catch the error. | |
190 | */ | |
191 | #if __GNUG__ && __GNUC__ < 5 | |
192 | static constexpr bool value = true; | |
193 | #else | |
a8e336c2 | 194 | static constexpr bool value = std::is_trivially_copyable<T>::value; |
f12e33ba | 195 | #endif |
a8e336c2 SM |
196 | }; |
197 | ||
198 | template <typename T, typename U, | |
199 | typename = typename std::enable_if<!can_memcpy<T>::value>::type, | |
200 | typename = typename std::enable_if<!can_memcpy<U>::value>::type> | |
201 | void *memcpy(T *d, const U *s, size_t n) = delete; | |
202 | ||
203 | template<typename T> | |
204 | struct can_memmove | |
205 | { | |
f12e33ba JG |
206 | /* |
207 | * gcc versions before 5.0 lack some type traits defined in C++11. | |
208 | * Since in this instance we use the trait to prevent misuses | |
209 | * of memmove (and statically assert) and not to generate different | |
210 | * code based on this property, simply set value to true and allow | |
211 | * the code to compile. Anyone using a contemporary compiler will | |
212 | * catch the error. | |
213 | */ | |
214 | #if __GNUG__ && __GNUC__ < 5 | |
215 | static constexpr bool value = true; | |
216 | #else | |
a8e336c2 | 217 | static constexpr bool value = std::is_trivially_copyable<T>::value; |
f12e33ba | 218 | #endif |
a8e336c2 SM |
219 | }; |
220 | ||
221 | template <typename T, typename U, | |
222 | typename = typename std::enable_if<!can_memmove<T>::value>::type, | |
223 | typename = typename std::enable_if<!can_memmove<U>::value>::type> | |
224 | void *memmove(T *d, const U *s, size_t n) = delete; | |
225 | ||
990570ed DG |
226 | #ifndef ARRAY_SIZE |
227 | #define ARRAY_SIZE(array) (sizeof(array) / (sizeof((array)[0]))) | |
228 | #endif | |
229 | ||
93375aa6 JG |
230 | #ifndef container_of |
231 | #define container_of(ptr, type, member) \ | |
232 | ({ \ | |
233 | const typeof(((type *)NULL)->member) * __ptr = (ptr); \ | |
234 | (type *)((char *)__ptr - offsetof(type, member)); \ | |
235 | }) | |
236 | #endif | |
237 | ||
54c90d10 DG |
238 | #ifndef LTTNG_PACKED |
239 | #define LTTNG_PACKED __attribute__((__packed__)) | |
240 | #endif | |
241 | ||
1405051a FD |
242 | #ifndef LTTNG_NO_SANITIZE_ADDRESS |
243 | #if defined(__clang__) || defined (__GNUC__) | |
244 | #define LTTNG_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) | |
245 | #else | |
246 | #define LTTNG_NO_SANITIZE_ADDRESS | |
247 | #endif | |
248 | #endif | |
249 | ||
f8f3885c MD |
250 | #define member_sizeof(type, field) sizeof(((type *) 0)->field) |
251 | ||
a0377dfe | 252 | #define ASSERT_LOCKED(lock) LTTNG_ASSERT(pthread_mutex_trylock(&lock)) |
48b7cdc2 | 253 | #define ASSERT_RCU_READ_LOCKED(lock) LTTNG_ASSERT(rcu_read_ongoing()) |
5e5c14ce | 254 | |
d22ad5f8 SM |
255 | /* Attribute suitable to tag functions as having printf()-like arguments. */ |
256 | #define ATTR_FORMAT_PRINTF(_string_index, _first_to_check) \ | |
257 | __attribute__((format(printf, _string_index, _first_to_check))) | |
258 | ||
411b3154 SM |
259 | /* Attribute suitable to tag functions as having strftime()-like arguments. */ |
260 | #define ATTR_FORMAT_STRFTIME(_string_index) \ | |
261 | __attribute__((format(strftime, _string_index, 0))) | |
262 | ||
d22ad5f8 SM |
263 | /* Macros used to ignore specific compiler diagnostics. */ |
264 | ||
265 | #define DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") | |
266 | #define DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") | |
267 | ||
268 | #if defined(__clang__) | |
269 | /* Clang */ | |
270 | # define DIAGNOSTIC_IGNORE_SUGGEST_ATTRIBUTE_FORMAT | |
411b3154 SM |
271 | # define DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL \ |
272 | _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") | |
942003e5 | 273 | # define DIAGNOSTIC_IGNORE_LOGICAL_OP |
05aa7e19 | 274 | # define DIAGNOSTIC_IGNORE_DUPLICATED_BRANCHES |
bd2c951e JG |
275 | # define DIAGNOSTIC_IGNORE_INVALID_OFFSETOF |
276 | _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"") | |
d22ad5f8 SM |
277 | #else |
278 | /* GCC */ | |
279 | # define DIAGNOSTIC_IGNORE_SUGGEST_ATTRIBUTE_FORMAT \ | |
280 | _Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=format\"") | |
411b3154 SM |
281 | # define DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL \ |
282 | _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") | |
942003e5 MJ |
283 | # define DIAGNOSTIC_IGNORE_LOGICAL_OP \ |
284 | _Pragma("GCC diagnostic ignored \"-Wlogical-op\"") | |
05aa7e19 JG |
285 | # define DIAGNOSTIC_IGNORE_DUPLICATED_BRANCHES \ |
286 | _Pragma("GCC diagnostic ignored \"-Wduplicated-branches\"") | |
bd2c951e JG |
287 | # define DIAGNOSTIC_IGNORE_INVALID_OFFSETOF \ |
288 | _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"") | |
d22ad5f8 SM |
289 | #endif |
290 | ||
d50d200a SM |
291 | /* Used to make specific C++ functions to C code. */ |
292 | #ifdef __cplusplus | |
293 | #define C_LINKAGE extern "C" | |
294 | #else | |
295 | #define C_LINKAGE | |
296 | #endif | |
297 | ||
f6835b82 MD |
298 | /* |
299 | * lttng_strncpy returns 0 on success, or nonzero on failure. | |
300 | * It checks that the @src string fits into @dst_len before performing | |
301 | * the copy. On failure, no copy has been performed. | |
302 | * | |
b25a5991 JG |
303 | * Assumes that 'src' is null-terminated. |
304 | * | |
f6835b82 MD |
305 | * dst_len includes the string's trailing NULL. |
306 | */ | |
307 | static inline | |
308 | int lttng_strncpy(char *dst, const char *src, size_t dst_len) | |
309 | { | |
b25a5991 | 310 | if (strlen(src) >= dst_len) { |
f6835b82 MD |
311 | /* Fail since copying would result in truncation. */ |
312 | return -1; | |
313 | } | |
c3ef76cd | 314 | strcpy(dst, src); |
f6835b82 MD |
315 | return 0; |
316 | } | |
317 | ||
990570ed | 318 | #endif /* _MACROS_H */ |