Home | History | Annotate | Line # | Download | only in gdbsupport
      1 /* Poison symbols at compile time.
      2 
      3    Copyright (C) 2017-2024 Free Software Foundation, Inc.
      4 
      5    This file is part of GDB.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19 
     20 #ifndef GDBSUPPORT_POISON_H
     21 #define GDBSUPPORT_POISON_H
     22 
     23 #include "traits.h"
     24 #include "obstack.h"
     25 
     26 /* Poison memset of non-POD types.  The idea is catching invalid
     27    initialization of non-POD structs that is easy to be introduced as
     28    side effect of refactoring.  For example, say this:
     29 
     30  struct S { VEC(foo_s) *m_data; };
     31 
     32 is converted to this at some point:
     33 
     34  struct S {
     35    S() { m_data.reserve (10); }
     36    std::vector<foo> m_data;
     37  };
     38 
     39 and old code was initializing S objects like this:
     40 
     41  struct S s;
     42  memset (&s, 0, sizeof (S)); // whoops, now wipes vector.
     43 
     44 Declaring memset as deleted for non-POD types makes the memset above
     45 be a compile-time error.  */
     46 
     47 /* Helper for SFINAE.  True if "T *" is memsettable.  I.e., if T is
     48    either void, or POD.  */
     49 template<typename T>
     50 struct IsMemsettable
     51   : gdb::Or<std::is_void<T>,
     52 	    gdb::And<std::is_standard_layout<T>, std::is_trivial<T>>>
     53 {};
     54 
     55 template <typename T,
     56 	  typename = gdb::Requires<gdb::Not<IsMemsettable<T>>>>
     57 void *memset (T *s, int c, size_t n) = delete;
     58 
     59 /* Similarly, poison memcpy and memmove of non trivially-copyable
     60    types, which is undefined.  */
     61 
     62 /* True if "T *" is relocatable.  I.e., copyable with memcpy/memmove.
     63    I.e., T is either trivially copyable, or void.  */
     64 template<typename T>
     65 struct IsRelocatable
     66   : gdb::Or<std::is_void<T>,
     67 	    std::is_trivially_copyable<T>>
     68 {};
     69 
     70 /* True if both source and destination are relocatable.  */
     71 
     72 template <typename D, typename S>
     73 using BothAreRelocatable
     74   = gdb::And<IsRelocatable<D>, IsRelocatable<S>>;
     75 
     76 template <typename D, typename S,
     77 	  typename = gdb::Requires<gdb::Not<BothAreRelocatable<D, S>>>>
     78 void *memcpy (D *dest, const S *src, size_t n) = delete;
     79 
     80 template <typename D, typename S,
     81 	  typename = gdb::Requires<gdb::Not<BothAreRelocatable<D, S>>>>
     82 void *memmove (D *dest, const S *src, size_t n) = delete;
     83 
     84 /* Poison XNEW and friends to catch usages of malloc-style allocations on
     85    objects that require new/delete.  */
     86 
     87 template<typename T>
     88 using IsMallocable = std::is_trivially_constructible<T>;
     89 
     90 template<typename T>
     91 using IsFreeable = gdb::Or<std::is_trivially_destructible<T>, std::is_void<T>>;
     92 
     93 template <typename T, typename = gdb::Requires<gdb::Not<IsFreeable<T>>>>
     94 void free (T *ptr) = delete;
     95 
     96 template<typename T>
     97 static T *
     98 xnew ()
     99 {
    100   static_assert (IsMallocable<T>::value, "Trying to use XNEW with a non-POD \
    101 data type.  Use operator new instead.");
    102   return XNEW (T);
    103 }
    104 
    105 #undef XNEW
    106 #define XNEW(T) xnew<T>()
    107 
    108 template<typename T>
    109 static T *
    110 xcnew ()
    111 {
    112   static_assert (IsMallocable<T>::value, "Trying to use XCNEW with a non-POD \
    113 data type.  Use operator new instead.");
    114   return XCNEW (T);
    115 }
    116 
    117 #undef XCNEW
    118 #define XCNEW(T) xcnew<T>()
    119 
    120 template<typename T>
    121 static void
    122 xdelete (T *p)
    123 {
    124   static_assert (IsFreeable<T>::value, "Trying to use XDELETE with a non-POD \
    125 data type.  Use operator delete instead.");
    126   XDELETE (p);
    127 }
    128 
    129 #undef XDELETE
    130 #define XDELETE(P) xdelete (P)
    131 
    132 template<typename T>
    133 static T *
    134 xnewvec (size_t n)
    135 {
    136   static_assert (IsMallocable<T>::value, "Trying to use XNEWVEC with a \
    137 non-POD data type.  Use operator new[] (or std::vector) instead.");
    138   return XNEWVEC (T, n);
    139 }
    140 
    141 #undef XNEWVEC
    142 #define XNEWVEC(T, N) xnewvec<T> (N)
    143 
    144 template<typename T>
    145 static T *
    146 xcnewvec (size_t n)
    147 {
    148   static_assert (IsMallocable<T>::value, "Trying to use XCNEWVEC with a \
    149 non-POD data type.  Use operator new[] (or std::vector) instead.");
    150   return XCNEWVEC (T, n);
    151 }
    152 
    153 #undef XCNEWVEC
    154 #define XCNEWVEC(T, N) xcnewvec<T> (N)
    155 
    156 template<typename T>
    157 static T *
    158 xresizevec (T *p, size_t n)
    159 {
    160   static_assert (IsMallocable<T>::value, "Trying to use XRESIZEVEC with a \
    161 non-POD data type.");
    162   return XRESIZEVEC (T, p, n);
    163 }
    164 
    165 #undef XRESIZEVEC
    166 #define XRESIZEVEC(T, P, N) xresizevec<T> (P, N)
    167 
    168 template<typename T>
    169 static void
    170 xdeletevec (T *p)
    171 {
    172   static_assert (IsFreeable<T>::value, "Trying to use XDELETEVEC with a \
    173 non-POD data type.  Use operator delete[] (or std::vector) instead.");
    174   XDELETEVEC (p);
    175 }
    176 
    177 #undef XDELETEVEC
    178 #define XDELETEVEC(P) xdeletevec (P)
    179 
    180 template<typename T>
    181 static T *
    182 xnewvar (size_t s)
    183 {
    184   static_assert (IsMallocable<T>::value, "Trying to use XNEWVAR with a \
    185 non-POD data type.");
    186   return XNEWVAR (T, s);;
    187 }
    188 
    189 #undef XNEWVAR
    190 #define XNEWVAR(T, S) xnewvar<T> (S)
    191 
    192 template<typename T>
    193 static T *
    194 xcnewvar (size_t s)
    195 {
    196   static_assert (IsMallocable<T>::value, "Trying to use XCNEWVAR with a \
    197 non-POD data type.");
    198   return XCNEWVAR (T, s);
    199 }
    200 
    201 #undef XCNEWVAR
    202 #define XCNEWVAR(T, S) xcnewvar<T> (S)
    203 
    204 template<typename T>
    205 static T *
    206 xresizevar (T *p, size_t s)
    207 {
    208   static_assert (IsMallocable<T>::value, "Trying to use XRESIZEVAR with a \
    209 non-POD data type.");
    210   return XRESIZEVAR (T, p, s);
    211 }
    212 
    213 #undef XRESIZEVAR
    214 #define XRESIZEVAR(T, P, S) xresizevar<T> (P, S)
    215 
    216 template<typename T>
    217 static T *
    218 xobnew (obstack *ob)
    219 {
    220   static_assert (IsMallocable<T>::value, "Trying to use XOBNEW with a \
    221 non-POD data type.");
    222   return XOBNEW (ob, T);
    223 }
    224 
    225 #undef XOBNEW
    226 #define XOBNEW(O, T) xobnew<T> (O)
    227 
    228 template<typename T>
    229 static T *
    230 xobnewvec (obstack *ob, size_t n)
    231 {
    232   static_assert (IsMallocable<T>::value, "Trying to use XOBNEWVEC with a \
    233 non-POD data type.");
    234   return XOBNEWVEC (ob, T, n);
    235 }
    236 
    237 #undef XOBNEWVEC
    238 #define XOBNEWVEC(O, T, N) xobnewvec<T> (O, N)
    239 
    240 #endif /* GDBSUPPORT_POISON_H */
    241