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>
20 #include <type_traits>
23 * Takes a pointer x and transform it so we can use it to access members
24 * without a function call. Here an example:
26 * #define GET_SIZE(x) LTTNG_REF(x)->size
28 * struct { int size; } s;
30 * printf("size : %d\n", GET_SIZE(&s));
32 * For this example we can't use something like this for compatibility purpose
33 * since this will fail:
35 * #define GET_SIZE(x) x->size;
37 * This is mostly use for the compatibility layer of lttng-tools. See
38 * poll/epoll for a good example. Since x can be on the stack or allocated
39 * memory using malloc(), we must use generic accessors for compat in order to
40 * *not* use a function to access members and not the variable name.
42 #define LTTNG_REF(x) ((typeof(*(x)) *) (x))
46 * Force usage of the assertion condition to prevent unused variable warnings
47 * when `assert()` are disabled by the `NDEBUG` definition.
49 # define LTTNG_ASSERT(_cond) ((void) sizeof((void) (_cond), 0))
52 # define LTTNG_ASSERT(_cond) assert(_cond)
56 * Memory allocation zeroed
60 void *zmalloc_internal(size_t size)
62 return calloc(1, size);
65 template <typename MallocableType>
68 * gcc versions before 5.0 lack some type traits defined in C++11.
69 * Since in this instance we use the trait to prevent misuses
70 * of malloc (and statically assert) and not to generate different
71 * code based on this property, simply set value to true and allow
72 * the code to compile. Anyone using a contemporary compiler will
75 #if __GNUG__ && __GNUC__ < 5
76 static constexpr bool value = true;
78 static constexpr bool value = std::is_trivially_constructible<MallocableType>::value;
83 * Malloc and zero-initialize an object of type T, asserting that MallocableType can be
84 * safely malloc-ed (is trivially constructible).
86 template <typename MallocableType>
87 MallocableType *zmalloc()
89 static_assert(can_malloc<MallocableType>::value, "type can be malloc'ed");
90 return (MallocableType *) zmalloc_internal(sizeof(MallocableType)); /* NOLINT sizeof
96 * Malloc and zero-initialize a buffer of size `size`, asserting that type AllocatedType
97 * can be safely malloc-ed (is trivially constructible).
99 template <typename AllocatedType>
100 AllocatedType *zmalloc(size_t size)
102 static_assert(can_malloc<AllocatedType>::value, "type can be malloc'ed");
103 LTTNG_ASSERT(size >= sizeof(AllocatedType));
104 return (AllocatedType *) zmalloc_internal(size);
108 * Malloc and zero-initialize an array of `nmemb` elements of type AllocatedType,
109 * asserting that AllocatedType can be safely malloc-ed (is trivially constructible).
111 template <typename AllocatedType>
112 AllocatedType *calloc(size_t nmemb)
114 static_assert(can_malloc<AllocatedType>::value, "type can be malloc'ed");
115 return (AllocatedType *) zmalloc_internal(nmemb * sizeof(AllocatedType)); /* NOLINT sizeof
122 * Malloc an object of type AllocatedType, asserting that AllocatedType can be safely malloc-ed (is
123 * trivially constructible).
125 template <typename AllocatedType>
126 AllocatedType *malloc()
128 static_assert(can_malloc<AllocatedType>::value, "type can be malloc'ed");
129 return (AllocatedType *) malloc(sizeof(AllocatedType));
133 * Malloc a buffer of size `size`, asserting that AllocatedType can be safely
134 * malloc-ed (is trivially constructible).
136 template<typename AllocatedType>
137 AllocatedType *malloc(size_t size)
139 static_assert (can_malloc<AllocatedType>::value, "type can be malloc'ed");
140 return (AllocatedType *) malloc(size);
144 * Prevent using `free` on types that are non-POD.
146 * Declare a delete prototype of free if the parameter type is not safe to free
149 * If the parameter is a pointer to void, we can't check if what is pointed
150 * to is safe to free or not, as we don't know what is pointed to. Ideally,
151 * all calls to free would be with a typed pointer, but there are too many
152 * instances of passing a pointer to void to enforce that right now. So allow
153 * pointers to void, these will not be checked.
156 template<typename FreedType>
160 * gcc versions before 5.0 lack some type traits defined in C++11.
161 * Since in this instance we use the trait to prevent misuses
162 * of free (and statically assert) and not to generate different
163 * code based on this property, simply set value to true and allow
164 * the code to compile. Anyone using a contemporary compiler will
167 #if __GNUG__ && __GNUC__ < 5
168 static constexpr bool value = true;
170 static constexpr bool value = std::is_trivially_destructible<FreedType>::value ||
171 std::is_void<FreedType>::value;
175 template <typename FreedType, typename = typename std::enable_if<!can_free<FreedType>::value>::type>
176 void free(FreedType *p) = delete;
178 template <typename InitializedType>
180 static constexpr bool value = std::is_pod<InitializedType>::value ||
181 std::is_void<InitializedType>::value;
184 template <typename InitializedType,
185 typename = typename std::enable_if<!can_memset<InitializedType>::value>::type>
186 void *memset(InitializedType *s, int c, size_t n) = delete;
192 * gcc versions before 5.0 lack some type traits defined in C++11.
193 * Since in this instance we use the trait to prevent misuses
194 * of memcpy (and statically assert) and not to generate different
195 * code based on this property, simply set value to true and allow
196 * the code to compile. Anyone using a contemporary compiler will
199 #if __GNUG__ && __GNUC__ < 5
200 static constexpr bool value = true;
202 static constexpr bool value = std::is_trivially_copyable<T>::value;
206 template <typename DestinationType,
208 typename = typename std::enable_if<!can_memcpy<DestinationType>::value>::type,
209 typename = typename std::enable_if<!can_memcpy<SourceType>::value>::type>
210 void *memcpy(DestinationType *d, const SourceType *s, size_t n) = delete;
212 template <typename MovedType>
215 * gcc versions before 5.0 lack some type traits defined in C++11.
216 * Since in this instance we use the trait to prevent misuses
217 * of memmove (and statically assert) and not to generate different
218 * code based on this property, simply set value to true and allow
219 * the code to compile. Anyone using a contemporary compiler will
222 #if __GNUG__ && __GNUC__ < 5
223 static constexpr bool value = true;
225 static constexpr bool value = std::is_trivially_copyable<MovedType>::value;
229 template <typename DestinationType,
231 typename = typename std::enable_if<!can_memmove<DestinationType>::value>::type,
232 typename = typename std::enable_if<!can_memmove<SourceType>::value>::type>
233 void *memmove(DestinationType *d, const SourceType *s, size_t n) = delete;
236 #define ARRAY_SIZE(array) (sizeof(array) / (sizeof((array)[0])))
240 #define LTTNG_PACKED __attribute__((__packed__))
243 #ifndef LTTNG_NO_SANITIZE_ADDRESS
244 #if defined(__clang__) || defined (__GNUC__)
245 #define LTTNG_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
247 #define LTTNG_NO_SANITIZE_ADDRESS
251 #define member_sizeof(type, field) sizeof(((type *) 0)->field)
253 #define ASSERT_LOCKED(lock) LTTNG_ASSERT(pthread_mutex_trylock(&(lock)))
254 #define ASSERT_RCU_READ_LOCKED(lock) LTTNG_ASSERT(rcu_read_ongoing())
256 /* Attribute suitable to tag functions as having printf()-like arguments. */
257 #define ATTR_FORMAT_PRINTF(_string_index, _first_to_check) \
258 __attribute__((format(printf, _string_index, _first_to_check)))
260 /* Attribute suitable to tag functions as having strftime()-like arguments. */
261 #define ATTR_FORMAT_STRFTIME(_string_index) \
262 __attribute__((format(strftime, _string_index, 0)))
264 /* Macros used to ignore specific compiler diagnostics. */
266 #define DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
267 #define DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
269 #if defined(__clang__)
271 # define DIAGNOSTIC_IGNORE_SUGGEST_ATTRIBUTE_FORMAT
272 # define DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL \
273 _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"")
274 # define DIAGNOSTIC_IGNORE_LOGICAL_OP
275 # define DIAGNOSTIC_IGNORE_DUPLICATED_BRANCHES
276 # define DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
277 _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"")
280 # define DIAGNOSTIC_IGNORE_SUGGEST_ATTRIBUTE_FORMAT \
281 _Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=format\"")
282 # define DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL \
283 _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"")
284 # define DIAGNOSTIC_IGNORE_LOGICAL_OP \
285 _Pragma("GCC diagnostic ignored \"-Wlogical-op\"")
286 #if __GNUG__ && __GNUC__ >= 7
287 # define DIAGNOSTIC_IGNORE_DUPLICATED_BRANCHES \
288 _Pragma("GCC diagnostic ignored \"-Wduplicated-branches\"")
290 # define DIAGNOSTIC_IGNORE_DUPLICATED_BRANCHES
291 #endif /* __GNUG__ && __GNUC__ >= 7 */
292 # define DIAGNOSTIC_IGNORE_INVALID_OFFSETOF \
293 _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"")
296 /* Used to make specific C++ functions to C code. */
298 #define C_LINKAGE extern "C"
304 * lttng_strncpy returns 0 on success, or nonzero on failure.
305 * It checks that the @src string fits into @dst_len before performing
306 * the copy. On failure, no copy has been performed.
308 * Assumes that 'src' is null-terminated.
310 * dst_len includes the string's trailing NULL.
313 int lttng_strncpy(char *dst, const char *src, size_t dst_len)
315 if (strlen(src) >= dst_len) {
316 /* Fail since copying would result in truncation. */
325 template <class ParentType, class MemberType>
326 ParentType *container_of(const MemberType *member, const MemberType ParentType::*ptr_to_member)
328 const ParentType *dummy_parent = nullptr;
329 auto *offset_of_member = reinterpret_cast<const char *>(&(dummy_parent->*ptr_to_member));
330 auto address_of_parent = reinterpret_cast<const char *>(member) - offset_of_member;
332 return reinterpret_cast<ParentType *>(address_of_parent);
334 } /* namespace utils */
335 } /* namespace lttng */
337 #endif /* _MACROS_H */