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 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 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 /* COMMON_POISON_H */ 241