1 /* Poison symbols at compile time. 2 3 Copyright (C) 2017-2023 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 COMMON_POISON_H 21 #define COMMON_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 std::is_pod<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 #if HAVE_IS_TRIVIALLY_COPYABLE 60 61 /* Similarly, poison memcpy and memmove of non trivially-copyable 62 types, which is undefined. */ 63 64 /* True if "T *" is relocatable. I.e., copyable with memcpy/memmove. 65 I.e., T is either trivially copyable, or void. */ 66 template<typename T> 67 struct IsRelocatable 68 : gdb::Or<std::is_void<T>, 69 std::is_trivially_copyable<T>> 70 {}; 71 72 /* True if both source and destination are relocatable. */ 73 74 template <typename D, typename S> 75 using BothAreRelocatable 76 = gdb::And<IsRelocatable<D>, IsRelocatable<S>>; 77 78 template <typename D, typename S, 79 typename = gdb::Requires<gdb::Not<BothAreRelocatable<D, S>>>> 80 void *memcpy (D *dest, const S *src, size_t n) = delete; 81 82 template <typename D, typename S, 83 typename = gdb::Requires<gdb::Not<BothAreRelocatable<D, S>>>> 84 void *memmove (D *dest, const S *src, size_t n) = delete; 85 86 #endif /* HAVE_IS_TRIVIALLY_COPYABLE */ 87 88 /* Poison XNEW and friends to catch usages of malloc-style allocations on 89 objects that require new/delete. */ 90 91 template<typename T> 92 #if HAVE_IS_TRIVIALLY_CONSTRUCTIBLE 93 using IsMallocable = std::is_trivially_constructible<T>; 94 #else 95 using IsMallocable = std::true_type; 96 #endif 97 98 template<typename T> 99 using IsFreeable = gdb::Or<std::is_trivially_destructible<T>, std::is_void<T>>; 100 101 template <typename T, typename = gdb::Requires<gdb::Not<IsFreeable<T>>>> 102 void free (T *ptr) = delete; 103 104 template<typename T> 105 static T * 106 xnew () 107 { 108 static_assert (IsMallocable<T>::value, "Trying to use XNEW with a non-POD \ 109 data type. Use operator new instead."); 110 return XNEW (T); 111 } 112 113 #undef XNEW 114 #define XNEW(T) xnew<T>() 115 116 template<typename T> 117 static T * 118 xcnew () 119 { 120 static_assert (IsMallocable<T>::value, "Trying to use XCNEW with a non-POD \ 121 data type. Use operator new instead."); 122 return XCNEW (T); 123 } 124 125 #undef XCNEW 126 #define XCNEW(T) xcnew<T>() 127 128 template<typename T> 129 static void 130 xdelete (T *p) 131 { 132 static_assert (IsFreeable<T>::value, "Trying to use XDELETE with a non-POD \ 133 data type. Use operator delete instead."); 134 XDELETE (p); 135 } 136 137 #undef XDELETE 138 #define XDELETE(P) xdelete (P) 139 140 template<typename T> 141 static T * 142 xnewvec (size_t n) 143 { 144 static_assert (IsMallocable<T>::value, "Trying to use XNEWVEC with a \ 145 non-POD data type. Use operator new[] (or std::vector) instead."); 146 return XNEWVEC (T, n); 147 } 148 149 #undef XNEWVEC 150 #define XNEWVEC(T, N) xnewvec<T> (N) 151 152 template<typename T> 153 static T * 154 xcnewvec (size_t n) 155 { 156 static_assert (IsMallocable<T>::value, "Trying to use XCNEWVEC with a \ 157 non-POD data type. Use operator new[] (or std::vector) instead."); 158 return XCNEWVEC (T, n); 159 } 160 161 #undef XCNEWVEC 162 #define XCNEWVEC(T, N) xcnewvec<T> (N) 163 164 template<typename T> 165 static T * 166 xresizevec (T *p, size_t n) 167 { 168 static_assert (IsMallocable<T>::value, "Trying to use XRESIZEVEC with a \ 169 non-POD data type."); 170 return XRESIZEVEC (T, p, n); 171 } 172 173 #undef XRESIZEVEC 174 #define XRESIZEVEC(T, P, N) xresizevec<T> (P, N) 175 176 template<typename T> 177 static void 178 xdeletevec (T *p) 179 { 180 static_assert (IsFreeable<T>::value, "Trying to use XDELETEVEC with a \ 181 non-POD data type. Use operator delete[] (or std::vector) instead."); 182 XDELETEVEC (p); 183 } 184 185 #undef XDELETEVEC 186 #define XDELETEVEC(P) xdeletevec (P) 187 188 template<typename T> 189 static T * 190 xnewvar (size_t s) 191 { 192 static_assert (IsMallocable<T>::value, "Trying to use XNEWVAR with a \ 193 non-POD data type."); 194 return XNEWVAR (T, s);; 195 } 196 197 #undef XNEWVAR 198 #define XNEWVAR(T, S) xnewvar<T> (S) 199 200 template<typename T> 201 static T * 202 xcnewvar (size_t s) 203 { 204 static_assert (IsMallocable<T>::value, "Trying to use XCNEWVAR with a \ 205 non-POD data type."); 206 return XCNEWVAR (T, s); 207 } 208 209 #undef XCNEWVAR 210 #define XCNEWVAR(T, S) xcnewvar<T> (S) 211 212 template<typename T> 213 static T * 214 xresizevar (T *p, size_t s) 215 { 216 static_assert (IsMallocable<T>::value, "Trying to use XRESIZEVAR with a \ 217 non-POD data type."); 218 return XRESIZEVAR (T, p, s); 219 } 220 221 #undef XRESIZEVAR 222 #define XRESIZEVAR(T, P, S) xresizevar<T> (P, S) 223 224 template<typename T> 225 static T * 226 xobnew (obstack *ob) 227 { 228 static_assert (IsMallocable<T>::value, "Trying to use XOBNEW with a \ 229 non-POD data type."); 230 return XOBNEW (ob, T); 231 } 232 233 #undef XOBNEW 234 #define XOBNEW(O, T) xobnew<T> (O) 235 236 template<typename T> 237 static T * 238 xobnewvec (obstack *ob, size_t n) 239 { 240 static_assert (IsMallocable<T>::value, "Trying to use XOBNEWVEC with a \ 241 non-POD data type."); 242 return XOBNEWVEC (ob, T, n); 243 } 244 245 #undef XOBNEWVEC 246 #define XOBNEWVEC(O, T, N) xobnewvec<T> (O, N) 247 248 #endif /* COMMON_POISON_H */ 249