Fix: syscall event rule: emission sites not compared in is_equal
[lttng-tools.git] / src / common / macros.hpp
CommitLineData
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
28f23191
JG
14#include <memory>
15#include <pthread.h>
93375aa6 16#include <stddef.h>
64803277 17#include <stdlib.h>
f6835b82 18#include <string.h>
64803277 19#include <type_traits>
990570ed
DG
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 */
5c7248cd 41#define LTTNG_REF(x) ((typeof(*(x)) *) (x))
990570ed 42
64803277
SM
43#ifdef NDEBUG
44/*
28f23191
JG
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))
64803277 49#else
28f23191
JG
50#include <assert.h>
51#define LTTNG_ASSERT(_cond) assert(_cond)
64803277
SM
52#endif
53
990570ed
DG
54/*
55 * Memory allocation zeroed
56 */
64803277 57
28f23191 58static inline void *zmalloc_internal(size_t size)
64803277
SM
59{
60 return calloc(1, size);
61}
62
31375c42
JG
63template <typename MallocableType>
64struct can_malloc {
f12e33ba
JG
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
31375c42 76 static constexpr bool value = std::is_trivially_constructible<MallocableType>::value;
f12e33ba 77#endif
64803277
SM
78};
79
80/*
31375c42 81 * Malloc and zero-initialize an object of type T, asserting that MallocableType can be
64803277
SM
82 * safely malloc-ed (is trivially constructible).
83 */
31375c42
JG
84template <typename MallocableType>
85MallocableType *zmalloc()
64803277 86{
31375c42
JG
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. */
64803277
SM
91}
92
93/*
31375c42 94 * Malloc and zero-initialize a buffer of size `size`, asserting that type AllocatedType
64803277
SM
95 * can be safely malloc-ed (is trivially constructible).
96 */
31375c42
JG
97template <typename AllocatedType>
98AllocatedType *zmalloc(size_t size)
64803277 99{
31375c42
JG
100 static_assert(can_malloc<AllocatedType>::value, "type can be malloc'ed");
101 LTTNG_ASSERT(size >= sizeof(AllocatedType));
102 return (AllocatedType *) zmalloc_internal(size);
64803277
SM
103}
104
105/*
31375c42
JG
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).
64803277 108 */
31375c42
JG
109template <typename AllocatedType>
110AllocatedType *calloc(size_t nmemb)
64803277 111{
31375c42
JG
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. */
64803277
SM
117}
118
119/*
31375c42 120 * Malloc an object of type AllocatedType, asserting that AllocatedType can be safely malloc-ed (is
64803277
SM
121 * trivially constructible).
122 */
31375c42
JG
123template <typename AllocatedType>
124AllocatedType *malloc()
4616a46c 125{
31375c42
JG
126 static_assert(can_malloc<AllocatedType>::value, "type can be malloc'ed");
127 return (AllocatedType *) malloc(sizeof(AllocatedType));
4616a46c 128}
990570ed 129
64803277 130/*
31375c42 131 * Malloc a buffer of size `size`, asserting that AllocatedType can be safely
64803277
SM
132 * malloc-ed (is trivially constructible).
133 */
28f23191 134template <typename AllocatedType>
31375c42 135AllocatedType *malloc(size_t size)
64803277 136{
28f23191 137 static_assert(can_malloc<AllocatedType>::value, "type can be malloc'ed");
31375c42 138 return (AllocatedType *) malloc(size);
64803277
SM
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
28f23191
JG
154template <typename FreedType>
155struct can_free {
f12e33ba
JG
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
31375c42
JG
167 static constexpr bool value = std::is_trivially_destructible<FreedType>::value ||
168 std::is_void<FreedType>::value;
f12e33ba 169#endif
64803277
SM
170};
171
31375c42
JG
172template <typename FreedType, typename = typename std::enable_if<!can_free<FreedType>::value>::type>
173void free(FreedType *p) = delete;
64803277 174
31375c42
JG
175template <typename InitializedType>
176struct can_memset {
177 static constexpr bool value = std::is_pod<InitializedType>::value ||
178 std::is_void<InitializedType>::value;
a8e336c2
SM
179};
180
31375c42
JG
181template <typename InitializedType,
182 typename = typename std::enable_if<!can_memset<InitializedType>::value>::type>
183void *memset(InitializedType *s, int c, size_t n) = delete;
a8e336c2 184
28f23191
JG
185template <typename T>
186struct can_memcpy {
f12e33ba
JG
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
a8e336c2 198 static constexpr bool value = std::is_trivially_copyable<T>::value;
f12e33ba 199#endif
a8e336c2
SM
200};
201
31375c42
JG
202template <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>
206void *memcpy(DestinationType *d, const SourceType *s, size_t n) = delete;
a8e336c2 207
31375c42
JG
208template <typename MovedType>
209struct can_memmove {
f12e33ba
JG
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
31375c42 221 static constexpr bool value = std::is_trivially_copyable<MovedType>::value;
f12e33ba 222#endif
a8e336c2
SM
223};
224
31375c42
JG
225template <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>
229void *memmove(DestinationType *d, const SourceType *s, size_t n) = delete;
a8e336c2 230
990570ed 231#ifndef ARRAY_SIZE
28f23191 232#define ARRAY_SIZE(array) (sizeof(array) / (sizeof((array)[0])))
990570ed
DG
233#endif
234
54c90d10
DG
235#ifndef LTTNG_PACKED
236#define LTTNG_PACKED __attribute__((__packed__))
237#endif
238
1405051a 239#ifndef LTTNG_NO_SANITIZE_ADDRESS
28f23191 240#if defined(__clang__) || defined(__GNUC__)
1405051a
FD
241#define LTTNG_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
242#else
243#define LTTNG_NO_SANITIZE_ADDRESS
244#endif
245#endif
246
28f23191 247#define member_sizeof(type, field) sizeof(((type *) 0)->field)
f8f3885c 248
28f23191
JG
249#define ASSERT_LOCKED(lock) LTTNG_ASSERT(pthread_mutex_trylock(&(lock)))
250#define ASSERT_RCU_READ_LOCKED() LTTNG_ASSERT(rcu_read_ongoing())
56047f5a 251#define ASSERT_RCU_READ_UNLOCKED() LTTNG_ASSERT(!rcu_read_ongoing())
5e5c14ce 252
d22ad5f8
SM
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
411b3154 257/* Attribute suitable to tag functions as having strftime()-like arguments. */
28f23191 258#define ATTR_FORMAT_STRFTIME(_string_index) __attribute__((format(strftime, _string_index, 0)))
411b3154 259
d22ad5f8
SM
260/* Macros used to ignore specific compiler diagnostics. */
261
262#define DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
28f23191 263#define DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
d22ad5f8
SM
264
265#if defined(__clang__)
28f23191
JG
266/* Clang */
267#define DIAGNOSTIC_IGNORE_SUGGEST_ATTRIBUTE_FORMAT
268#define DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL \
411b3154 269 _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"")
28f23191
JG
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\"")
d22ad5f8 274#else
28f23191
JG
275/* GCC */
276#define DIAGNOSTIC_IGNORE_SUGGEST_ATTRIBUTE_FORMAT \
d22ad5f8 277 _Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=format\"")
28f23191 278#define DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL \
411b3154 279 _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"")
28f23191 280#define DIAGNOSTIC_IGNORE_LOGICAL_OP _Pragma("GCC diagnostic ignored \"-Wlogical-op\"")
efc2642c 281#if __GNUG__ && __GNUC__ >= 7
28f23191 282#define DIAGNOSTIC_IGNORE_DUPLICATED_BRANCHES \
05aa7e19 283 _Pragma("GCC diagnostic ignored \"-Wduplicated-branches\"")
efc2642c 284#else
28f23191 285#define DIAGNOSTIC_IGNORE_DUPLICATED_BRANCHES
efc2642c 286#endif /* __GNUG__ && __GNUC__ >= 7 */
28f23191 287#define DIAGNOSTIC_IGNORE_INVALID_OFFSETOF _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"")
d22ad5f8
SM
288#endif
289
d50d200a
SM
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
28f23191
JG
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)
f6835b82 307{
b25a5991 308 if (strlen(src) >= dst_len) {
f6835b82
MD
309 /* Fail since copying would result in truncation. */
310 return -1;
311 }
c3ef76cd 312 strcpy(dst, src);
f6835b82
MD
313 return 0;
314}
315
0114db0e
JG
316namespace lttng {
317namespace utils {
31375c42
JG
318template <class ParentType, class MemberType>
319ParentType *container_of(const MemberType *member, const MemberType ParentType::*ptr_to_member)
0114db0e 320{
31375c42 321 const ParentType *dummy_parent = nullptr;
0114db0e
JG
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
31375c42 325 return reinterpret_cast<ParentType *>(address_of_parent);
0114db0e
JG
326}
327} /* namespace utils */
328} /* namespace lttng */
329
990570ed 330#endif /* _MACROS_H */
This page took 0.099784 seconds and 4 git commands to generate.