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