common: prevent using memset on non-POD types
authorSimon Marchi <simon.marchi@efficios.com>
Wed, 8 Sep 2021 22:00:42 +0000 (18:00 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Wed, 6 Apr 2022 15:32:22 +0000 (11:32 -0400)
While converting some code to use C++ constructs, it can be easy to
forget to change some spot that uses memset to initialize or move the
object. Add a templated deleted declaration to prevent using memset on
types that aren't POD.

For example, if I make lttng_ust_event non-POD, in
src/bin/lttng-sessiond/trace-ust.h, I get this error:

      CXX      save.lo
    /home/simark/src/lttng-tools/src/bin/lttng-sessiond/save.cpp: In function ‘int save_agent_events(config_writer*, agent*)’:
    /home/simark/src/lttng-tools/src/bin/lttng-sessiond/save.cpp:1246:23: error: use of deleted function ‘void* memset(T*, int, size_t) [with T = ltt_ust_event; <template-parameter-1-2> = void; size_t = long unsigned int]’
     1246 |                 memset(&fake_event, 0, sizeof(fake_event));
          |                 ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    In file included from /home/simark/src/lttng-tools/src/common/defaults.h:14,
                     from /home/simark/src/lttng-tools/src/bin/lttng-sessiond/save.cpp:15:
    /home/simark/src/lttng-tools/src/common/macros.h:128:7: note: declared here
      128 | void *memset(T *s, int c, size_t n) = delete;
          |       ^~~~~~

Note: I tried applying this to memcpy as well, but Clang gave me some
troubles with its -Waddress-of-packed-member diagnostic, so I gave up.

Change-Id: Id55735db15901c6fc5d58e9b6b6b689733302398
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
src/common/macros.hpp

index 49f163b42fb5a6c81cc3906f9016a06fac6383a2..b734652eea9ea89218d7e798edabed46fe272e73 100644 (file)
@@ -136,14 +136,45 @@ T *malloc(size_t size)
  */
 
 template<typename T>
-struct is_pod_or_void
+struct can_free
 {
-       static constexpr bool value = std::is_pod<T>::value || std::is_void<T>::value;
+       static constexpr bool value = std::is_trivially_destructible<T>::value || std::is_void<T>::value;
 };
 
-template<typename T, typename = typename std::enable_if<!is_pod_or_void<T>::value>::type>
+template<typename T, typename = typename std::enable_if<!can_free<T>::value>::type>
 void free(T *p) = delete;
 
+template<typename T>
+struct can_memset
+{
+       static constexpr bool value = std::is_pod<T>::value || std::is_void<T>::value;
+};
+
+template <typename T, typename = typename std::enable_if<!can_memset<T>::value>::type>
+void *memset(T *s, int c, size_t n) = delete;
+
+template<typename T>
+struct can_memcpy
+{
+       static constexpr bool value = std::is_trivially_copyable<T>::value;
+};
+
+template <typename T, typename U,
+               typename = typename std::enable_if<!can_memcpy<T>::value>::type,
+               typename = typename std::enable_if<!can_memcpy<U>::value>::type>
+void *memcpy(T *d, const U *s, size_t n) = delete;
+
+template<typename T>
+struct can_memmove
+{
+       static constexpr bool value = std::is_trivially_copyable<T>::value;
+};
+
+template <typename T, typename U,
+               typename = typename std::enable_if<!can_memmove<T>::value>::type,
+               typename = typename std::enable_if<!can_memmove<U>::value>::type>
+void *memmove(T *d, const U *s, size_t n) = delete;
+
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(array)   (sizeof(array) / (sizeof((array)[0])))
 #endif
This page took 0.026593 seconds and 4 git commands to generate.