2 * Copyright (C) 2011 EfficiOS Inc.
3 * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 * SPDX-License-Identifier: GPL-2.0-only
12 #include <common/compat/string.hpp>
19 #include <type_traits>
22 * Takes a pointer x and transform it so we can use it to access members
23 * without a function call. Here an example:
25 * #define GET_SIZE(x) LTTNG_REF(x)->size
27 * struct { int size; } s;
29 * printf("size : %d\n", GET_SIZE(&s));
31 * For this example we can't use something like this for compatibility purpose
32 * since this will fail:
34 * #define GET_SIZE(x) x->size;
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.
41 #define LTTNG_REF(x) ((typeof(*(x)) *) (x))
45 * Force usage of the assertion condition to prevent unused variable warnings
46 * when `assert()` are disabled by the `NDEBUG` definition.
48 #define LTTNG_ASSERT(_cond) ((void) sizeof((void) (_cond), 0))
51 #define LTTNG_ASSERT(_cond) assert(_cond)
55 * Memory allocation zeroed
58 static inline void *zmalloc_internal(size_t size)
60 return calloc(1, size);
63 template <typename MallocableType>
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
73 #if __GNUG__ && __GNUC__ < 5
74 static constexpr bool value = true;
76 static constexpr bool value = std::is_trivially_constructible<MallocableType>::value;
81 * Malloc and zero-initialize an object of type T, asserting that MallocableType can be
82 * safely malloc-ed (is trivially constructible).
84 template <typename MallocableType>
85 MallocableType *zmalloc()
87 static_assert(can_malloc<MallocableType>::value, "type can be malloc'ed");
88 return (MallocableType *) zmalloc_internal(sizeof(MallocableType)); /* NOLINT sizeof
94 * Malloc and zero-initialize a buffer of size `size`, asserting that type AllocatedType
95 * can be safely malloc-ed (is trivially constructible).
97 template <typename AllocatedType>
98 AllocatedType *zmalloc(size_t size)
100 static_assert(can_malloc<AllocatedType>::value, "type can be malloc'ed");
101 LTTNG_ASSERT(size >= sizeof(AllocatedType));
102 return (AllocatedType *) zmalloc_internal(size);
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).
109 template <typename AllocatedType>
110 AllocatedType *calloc(size_t nmemb)
112 static_assert(can_malloc<AllocatedType>::value, "type can be malloc'ed");
113 return (AllocatedType *) zmalloc_internal(nmemb * sizeof(AllocatedType)); /* NOLINT sizeof
120 * Malloc an object of type AllocatedType, asserting that AllocatedType can be safely malloc-ed (is
121 * trivially constructible).
123 template <typename AllocatedType>
124 AllocatedType *malloc()
126 static_assert(can_malloc<AllocatedType>::value, "type can be malloc'ed");
127 return (AllocatedType *) malloc(sizeof(AllocatedType));
131 * Malloc a buffer of size `size`, asserting that AllocatedType can be safely
132 * malloc-ed (is trivially constructible).
134 template <typename AllocatedType>
135 AllocatedType *malloc(size_t size)
137 static_assert(can_malloc<AllocatedType>::value, "type can be malloc'ed");
138 return (AllocatedType *) malloc(size);
142 * Prevent using `free` on types that are non-POD.
144 * Declare a delete prototype of free if the parameter type is not safe to free
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.
154 template <typename FreedType>
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
164 #if __GNUG__ && __GNUC__ < 5
165 static constexpr bool value = true;
167 static constexpr bool value = std::is_trivially_destructible<FreedType>::value ||
168 std::is_void<FreedType>::value;
172 template <typename FreedType, typename = typename std::enable_if<!can_free<FreedType>::value>::type>
173 void free(FreedType *p) = delete;
175 template <typename InitializedType>
177 static constexpr bool value = std::is_pod<InitializedType>::value ||
178 std::is_void<InitializedType>::value;
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;
185 template <typename T>
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
195 #if __GNUG__ && __GNUC__ < 5
196 static constexpr bool value = true;
198 static constexpr bool value = std::is_trivially_copyable<T>::value;
202 template <typename DestinationType,
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;
208 template <typename MovedType>
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
218 #if __GNUG__ && __GNUC__ < 5
219 static constexpr bool value = true;
221 static constexpr bool value = std::is_trivially_copyable<MovedType>::value;
225 template <typename DestinationType,
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;
232 #define ARRAY_SIZE(array) (sizeof(array) / (sizeof((array)[0])))
236 #define LTTNG_PACKED __attribute__((__packed__))
239 #ifndef LTTNG_NO_SANITIZE_ADDRESS
240 #if defined(__clang__) || defined(__GNUC__)
241 #define LTTNG_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
243 #define LTTNG_NO_SANITIZE_ADDRESS
247 #define member_sizeof(type, field) sizeof(((type *) 0)->field)
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())
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)))
257 /* Attribute suitable to tag functions as having strftime()-like arguments. */
258 #define ATTR_FORMAT_STRFTIME(_string_index) __attribute__((format(strftime, _string_index, 0)))
260 /* Macros used to ignore specific compiler diagnostics. */
262 #define DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
263 #define DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
265 #if defined(__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\"")
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\"")
285 #define DIAGNOSTIC_IGNORE_DUPLICATED_BRANCHES
286 #endif /* __GNUG__ && __GNUC__ >= 7 */
287 #define DIAGNOSTIC_IGNORE_INVALID_OFFSETOF _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"")
290 /* Used to make specific C++ functions to C code. */
292 #define C_LINKAGE extern "C"
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.
302 * Assumes that 'src' is null-terminated.
304 * dst_len includes the string's trailing NULL.
306 static inline int lttng_strncpy(char *dst, const char *src, size_t dst_len)
308 if (strlen(src) >= dst_len) {
309 /* Fail since copying would result in truncation. */
318 template <class ParentType, class MemberType>
319 ParentType *container_of(const MemberType *member, const MemberType ParentType::*ptr_to_member)
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;
325 return reinterpret_cast<ParentType *>(address_of_parent);
327 } /* namespace utils */
328 } /* namespace lttng */
330 #endif /* _MACROS_H */