Commit | Line | Data |
---|---|---|
b0b92aeb PA |
1 | /* Poison symbols at compile time. |
2 | ||
e2882c85 | 3 | Copyright (C) 2017-2018 Free Software Foundation, Inc. |
b0b92aeb PA |
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 | ||
25 | /* Poison memset of non-POD types. The idea is catching invalid | |
26 | initialization of non-POD structs that is easy to be introduced as | |
27 | side effect of refactoring. For example, say this: | |
28 | ||
29 | struct S { VEC(foo_s) *m_data; }; | |
30 | ||
31 | is converted to this at some point: | |
32 | ||
33 | struct S { | |
34 | S() { m_data.reserve (10); } | |
35 | std::vector<foo> m_data; | |
36 | }; | |
37 | ||
38 | and old code was initializing S objects like this: | |
39 | ||
40 | struct S s; | |
41 | memset (&s, 0, sizeof (S)); // whoops, now wipes vector. | |
42 | ||
43 | Declaring memset as deleted for non-POD types makes the memset above | |
44 | be a compile-time error. */ | |
45 | ||
46 | /* Helper for SFINAE. True if "T *" is memsettable. I.e., if T is | |
47 | either void, or POD. */ | |
48 | template<typename T> | |
49 | struct IsMemsettable | |
50 | : gdb::Or<std::is_void<T>, | |
51 | std::is_pod<T>> | |
52 | {}; | |
53 | ||
54 | template <typename T, | |
55 | typename = gdb::Requires<gdb::Not<IsMemsettable<T>>>> | |
56 | void *memset (T *s, int c, size_t n) = delete; | |
57 | ||
debed3db PA |
58 | #if HAVE_IS_TRIVIALLY_COPYABLE |
59 | ||
b0b92aeb PA |
60 | /* Similarly, poison memcpy and memmove of non trivially-copyable |
61 | types, which is undefined. */ | |
62 | ||
63 | /* True if "T *" is relocatable. I.e., copyable with memcpy/memmove. | |
64 | I.e., T is either trivially copyable, or void. */ | |
65 | template<typename T> | |
66 | struct IsRelocatable | |
67 | : gdb::Or<std::is_void<T>, | |
68 | std::is_trivially_copyable<T>> | |
69 | {}; | |
70 | ||
71 | /* True if both source and destination are relocatable. */ | |
72 | ||
73 | template <typename D, typename S> | |
74 | using BothAreRelocatable | |
75 | = gdb::And<IsRelocatable<D>, IsRelocatable<S>>; | |
76 | ||
77 | template <typename D, typename S, | |
78 | typename = gdb::Requires<gdb::Not<BothAreRelocatable<D, S>>>> | |
79 | void *memcpy (D *dest, const S *src, size_t n) = delete; | |
80 | ||
81 | template <typename D, typename S, | |
82 | typename = gdb::Requires<gdb::Not<BothAreRelocatable<D, S>>>> | |
83 | void *memmove (D *dest, const S *src, size_t n) = delete; | |
84 | ||
debed3db PA |
85 | #endif /* HAVE_IS_TRIVIALLY_COPYABLE */ |
86 | ||
8172f16b SM |
87 | /* Poison XNEW and friends to catch usages of malloc-style allocations on |
88 | objects that require new/delete. */ | |
89 | ||
90 | template<typename T> | |
91 | using IsMallocable = std::is_pod<T>; | |
92 | ||
93 | template<typename T> | |
94 | using IsFreeable = gdb::Or<std::is_trivially_destructible<T>, std::is_void<T>>; | |
95 | ||
96 | template <typename T, typename = gdb::Requires<gdb::Not<IsFreeable<T>>>> | |
97 | void free (T *ptr) = delete; | |
98 | ||
99 | template<typename T> | |
100 | static T * | |
101 | xnew () | |
102 | { | |
103 | static_assert (IsMallocable<T>::value, "Trying to use XNEW with a non-POD \ | |
104 | data type. Use operator new instead."); | |
105 | return XNEW (T); | |
106 | } | |
107 | ||
108 | #undef XNEW | |
109 | #define XNEW(T) xnew<T>() | |
110 | ||
111 | template<typename T> | |
112 | static T * | |
113 | xcnew () | |
114 | { | |
115 | static_assert (IsMallocable<T>::value, "Trying to use XCNEW with a non-POD \ | |
116 | data type. Use operator new instead."); | |
117 | return XCNEW (T); | |
118 | } | |
119 | ||
120 | #undef XCNEW | |
121 | #define XCNEW(T) xcnew<T>() | |
122 | ||
123 | template<typename T> | |
124 | static void | |
125 | xdelete (T *p) | |
126 | { | |
127 | static_assert (IsFreeable<T>::value, "Trying to use XDELETE with a non-POD \ | |
128 | data type. Use operator delete instead."); | |
129 | XDELETE (p); | |
130 | } | |
131 | ||
132 | #undef XDELETE | |
6d83e819 | 133 | #define XDELETE(P) xdelete (P) |
8172f16b SM |
134 | |
135 | template<typename T> | |
136 | static T * | |
137 | xnewvec (size_t n) | |
138 | { | |
139 | static_assert (IsMallocable<T>::value, "Trying to use XNEWVEC with a \ | |
140 | non-POD data type. Use operator new[] (or std::vector) instead."); | |
141 | return XNEWVEC (T, n); | |
142 | } | |
143 | ||
144 | #undef XNEWVEC | |
145 | #define XNEWVEC(T, N) xnewvec<T> (N) | |
146 | ||
147 | template<typename T> | |
148 | static T * | |
149 | xcnewvec (size_t n) | |
150 | { | |
151 | static_assert (IsMallocable<T>::value, "Trying to use XCNEWVEC with a \ | |
152 | non-POD data type. Use operator new[] (or std::vector) instead."); | |
153 | return XCNEWVEC (T, n); | |
154 | } | |
155 | ||
156 | #undef XCNEWVEC | |
157 | #define XCNEWVEC(T, N) xcnewvec<T> (N) | |
158 | ||
159 | template<typename T> | |
160 | static T * | |
161 | xresizevec (T *p, size_t n) | |
162 | { | |
163 | static_assert (IsMallocable<T>::value, "Trying to use XRESIZEVEC with a \ | |
164 | non-POD data type."); | |
165 | return XRESIZEVEC (T, p, n); | |
166 | } | |
167 | ||
168 | #undef XRESIZEVEC | |
169 | #define XRESIZEVEC(T, P, N) xresizevec<T> (P, N) | |
170 | ||
171 | template<typename T> | |
172 | static void | |
173 | xdeletevec (T *p) | |
174 | { | |
175 | static_assert (IsFreeable<T>::value, "Trying to use XDELETEVEC with a \ | |
176 | non-POD data type. Use operator delete[] (or std::vector) instead."); | |
177 | XDELETEVEC (p); | |
178 | } | |
179 | ||
180 | #undef XDELETEVEC | |
181 | #define XDELETEVEC(P) xdeletevec (P) | |
182 | ||
183 | template<typename T> | |
184 | static T * | |
185 | xnewvar (size_t s) | |
186 | { | |
187 | static_assert (IsMallocable<T>::value, "Trying to use XNEWVAR with a \ | |
188 | non-POD data type."); | |
189 | return XNEWVAR (T, s);; | |
190 | } | |
191 | ||
192 | #undef XNEWVAR | |
193 | #define XNEWVAR(T, S) xnewvar<T> (S) | |
194 | ||
195 | template<typename T> | |
196 | static T * | |
197 | xcnewvar (size_t s) | |
198 | { | |
199 | static_assert (IsMallocable<T>::value, "Trying to use XCNEWVAR with a \ | |
200 | non-POD data type."); | |
201 | return XCNEWVAR (T, s); | |
202 | } | |
203 | ||
204 | #undef XCNEWVAR | |
205 | #define XCNEWVAR(T, S) xcnewvar<T> (S) | |
206 | ||
207 | template<typename T> | |
208 | static T * | |
209 | xresizevar (T *p, size_t s) | |
210 | { | |
211 | static_assert (IsMallocable<T>::value, "Trying to use XRESIZEVAR with a \ | |
212 | non-POD data type."); | |
213 | return XRESIZEVAR (T, p, s); | |
214 | } | |
215 | ||
216 | #undef XRESIZEVAR | |
217 | #define XRESIZEVAR(T, P, S) xresizevar<T> (P, S) | |
218 | ||
b0b92aeb | 219 | #endif /* COMMON_POISON_H */ |