| /* Poison symbols at compile time. |
| |
| Copyright (C) 2017-2023 Free Software Foundation, Inc. |
| |
| This file is part of GDB. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| #ifndef COMMON_POISON_H |
| #define COMMON_POISON_H |
| |
| #include "traits.h" |
| #include "obstack.h" |
| |
| /* Poison memset of non-POD types. The idea is catching invalid |
| initialization of non-POD structs that is easy to be introduced as |
| side effect of refactoring. For example, say this: |
| |
| struct S { VEC(foo_s) *m_data; }; |
| |
| is converted to this at some point: |
| |
| struct S { |
| S() { m_data.reserve (10); } |
| std::vector<foo> m_data; |
| }; |
| |
| and old code was initializing S objects like this: |
| |
| struct S s; |
| memset (&s, 0, sizeof (S)); // whoops, now wipes vector. |
| |
| Declaring memset as deleted for non-POD types makes the memset above |
| be a compile-time error. */ |
| |
| /* Helper for SFINAE. True if "T *" is memsettable. I.e., if T is |
| either void, or POD. */ |
| template<typename T> |
| struct IsMemsettable |
| : gdb::Or<std::is_void<T>, |
| std::is_pod<T>> |
| {}; |
| |
| template <typename T, |
| typename = gdb::Requires<gdb::Not<IsMemsettable<T>>>> |
| void *memset (T *s, int c, size_t n) = delete; |
| |
| #if HAVE_IS_TRIVIALLY_COPYABLE |
| |
| /* Similarly, poison memcpy and memmove of non trivially-copyable |
| types, which is undefined. */ |
| |
| /* True if "T *" is relocatable. I.e., copyable with memcpy/memmove. |
| I.e., T is either trivially copyable, or void. */ |
| template<typename T> |
| struct IsRelocatable |
| : gdb::Or<std::is_void<T>, |
| std::is_trivially_copyable<T>> |
| {}; |
| |
| /* True if both source and destination are relocatable. */ |
| |
| template <typename D, typename S> |
| using BothAreRelocatable |
| = gdb::And<IsRelocatable<D>, IsRelocatable<S>>; |
| |
| template <typename D, typename S, |
| typename = gdb::Requires<gdb::Not<BothAreRelocatable<D, S>>>> |
| void *memcpy (D *dest, const S *src, size_t n) = delete; |
| |
| template <typename D, typename S, |
| typename = gdb::Requires<gdb::Not<BothAreRelocatable<D, S>>>> |
| void *memmove (D *dest, const S *src, size_t n) = delete; |
| |
| #endif /* HAVE_IS_TRIVIALLY_COPYABLE */ |
| |
| /* Poison XNEW and friends to catch usages of malloc-style allocations on |
| objects that require new/delete. */ |
| |
| template<typename T> |
| #if HAVE_IS_TRIVIALLY_CONSTRUCTIBLE |
| using IsMallocable = std::is_trivially_constructible<T>; |
| #else |
| using IsMallocable = std::true_type; |
| #endif |
| |
| template<typename T> |
| using IsFreeable = gdb::Or<std::is_trivially_destructible<T>, std::is_void<T>>; |
| |
| template <typename T, typename = gdb::Requires<gdb::Not<IsFreeable<T>>>> |
| void free (T *ptr) = delete; |
| |
| template<typename T> |
| static T * |
| xnew () |
| { |
| static_assert (IsMallocable<T>::value, "Trying to use XNEW with a non-POD \ |
| data type. Use operator new instead."); |
| return XNEW (T); |
| } |
| |
| #undef XNEW |
| #define XNEW(T) xnew<T>() |
| |
| template<typename T> |
| static T * |
| xcnew () |
| { |
| static_assert (IsMallocable<T>::value, "Trying to use XCNEW with a non-POD \ |
| data type. Use operator new instead."); |
| return XCNEW (T); |
| } |
| |
| #undef XCNEW |
| #define XCNEW(T) xcnew<T>() |
| |
| template<typename T> |
| static void |
| xdelete (T *p) |
| { |
| static_assert (IsFreeable<T>::value, "Trying to use XDELETE with a non-POD \ |
| data type. Use operator delete instead."); |
| XDELETE (p); |
| } |
| |
| #undef XDELETE |
| #define XDELETE(P) xdelete (P) |
| |
| template<typename T> |
| static T * |
| xnewvec (size_t n) |
| { |
| static_assert (IsMallocable<T>::value, "Trying to use XNEWVEC with a \ |
| non-POD data type. Use operator new[] (or std::vector) instead."); |
| return XNEWVEC (T, n); |
| } |
| |
| #undef XNEWVEC |
| #define XNEWVEC(T, N) xnewvec<T> (N) |
| |
| template<typename T> |
| static T * |
| xcnewvec (size_t n) |
| { |
| static_assert (IsMallocable<T>::value, "Trying to use XCNEWVEC with a \ |
| non-POD data type. Use operator new[] (or std::vector) instead."); |
| return XCNEWVEC (T, n); |
| } |
| |
| #undef XCNEWVEC |
| #define XCNEWVEC(T, N) xcnewvec<T> (N) |
| |
| template<typename T> |
| static T * |
| xresizevec (T *p, size_t n) |
| { |
| static_assert (IsMallocable<T>::value, "Trying to use XRESIZEVEC with a \ |
| non-POD data type."); |
| return XRESIZEVEC (T, p, n); |
| } |
| |
| #undef XRESIZEVEC |
| #define XRESIZEVEC(T, P, N) xresizevec<T> (P, N) |
| |
| template<typename T> |
| static void |
| xdeletevec (T *p) |
| { |
| static_assert (IsFreeable<T>::value, "Trying to use XDELETEVEC with a \ |
| non-POD data type. Use operator delete[] (or std::vector) instead."); |
| XDELETEVEC (p); |
| } |
| |
| #undef XDELETEVEC |
| #define XDELETEVEC(P) xdeletevec (P) |
| |
| template<typename T> |
| static T * |
| xnewvar (size_t s) |
| { |
| static_assert (IsMallocable<T>::value, "Trying to use XNEWVAR with a \ |
| non-POD data type."); |
| return XNEWVAR (T, s);; |
| } |
| |
| #undef XNEWVAR |
| #define XNEWVAR(T, S) xnewvar<T> (S) |
| |
| template<typename T> |
| static T * |
| xcnewvar (size_t s) |
| { |
| static_assert (IsMallocable<T>::value, "Trying to use XCNEWVAR with a \ |
| non-POD data type."); |
| return XCNEWVAR (T, s); |
| } |
| |
| #undef XCNEWVAR |
| #define XCNEWVAR(T, S) xcnewvar<T> (S) |
| |
| template<typename T> |
| static T * |
| xresizevar (T *p, size_t s) |
| { |
| static_assert (IsMallocable<T>::value, "Trying to use XRESIZEVAR with a \ |
| non-POD data type."); |
| return XRESIZEVAR (T, p, s); |
| } |
| |
| #undef XRESIZEVAR |
| #define XRESIZEVAR(T, P, S) xresizevar<T> (P, S) |
| |
| template<typename T> |
| static T * |
| xobnew (obstack *ob) |
| { |
| static_assert (IsMallocable<T>::value, "Trying to use XOBNEW with a \ |
| non-POD data type."); |
| return XOBNEW (ob, T); |
| } |
| |
| #undef XOBNEW |
| #define XOBNEW(O, T) xobnew<T> (O) |
| |
| template<typename T> |
| static T * |
| xobnewvec (obstack *ob, size_t n) |
| { |
| static_assert (IsMallocable<T>::value, "Trying to use XOBNEWVEC with a \ |
| non-POD data type."); |
| return XOBNEWVEC (ob, T, n); |
| } |
| |
| #undef XOBNEWVEC |
| #define XOBNEWVEC(O, T, N) xobnewvec<T> (O, N) |
| |
| #endif /* COMMON_POISON_H */ |