Poison XNEW and friends for types that should use new/delete

This patch (finally!) makes it so that trying to use XNEW with a type
that requires "new" will cause a compilation error.  The criterion I
initially used to allow a type to use XNEW (which calls malloc in the
end) was std::is_trivially_constructible, but then realized that gcc 4.8
did not have it.  Instead, I went with:

  using IsMallocatable = std::is_pod<T>;

which is just a bit more strict, which doesn't hurt.  A similar thing is
done for macros that free instead of allocated, the criterion is:

  using IsFreeable = gdb::Or<std::is_trivially_destructible<T>, std::is_void<T>>;

Trying to use XNEW on a type that requires new will result in an error
like this:

    In file included from /home/simark/src/binutils-gdb/gdb/common/common-utils.h:26:0,
                     from /home/simark/src/binutils-gdb/gdb/common/common-defs.h:78,
                     from /home/simark/src/binutils-gdb/gdb/defs.h:28,
                     from /home/simark/src/binutils-gdb/gdb/lala.c:1:
    /home/simark/src/binutils-gdb/gdb/common/poison.h: In instantiation of ‘T* xnew() [with T = bar]’:
    /home/simark/src/binutils-gdb/gdb/lala.c:13:3:   required from here
    /home/simark/src/binutils-gdb/gdb/common/poison.h:103:3: error: static assertion failed: Trying to use XNEW with a non-POD data type.  Use operator new instead.
       static_assert (IsMallocatable<T>::value, "Trying to use XNEW with a non-POD\
       ^~~~~~~~~~~~~

Generated-code-wise, it adds one more function call (xnew<T>) when using
XNEW and building with -O0, but it all goes away with optimizations
enabled.

gdb/ChangeLog:

	* common/common-utils.h: Include poison.h.
	(xfree): Remove declaration, add definition with static_assert.
	* common/common-utils.c (xfree): Remove.
	* common/poison.h (IsMallocatable): Define.
	(IsFreeable): Define.
	(free): Delete for non-freeable types.
	(xnew): New.
	(XNEW): Undef and redefine.
	(xcnew): New.
	(XCNEW): Undef and redefine.
	(xdelete): New.
	(XDELETE): Undef and redefine.
	(xnewvec): New.
	(XNEWVEC): Undef and redefine.
	(xcnewvec): New.
	(XCNEWVEC): Undef and redefine.
	(xresizevec): New.
	(XRESIZEVEC): Undef and redefine.
	(xdeletevec): New.
	(XDELETEVEC): Undef and redefine.
	(xnewvar): New.
	(XNEWVAR): Undef and redefine.
	(xcnewvar): New.
	(XCNEWVAR): Undef and redefine.
	(xresizevar): New.
	(XRESIZEVAR): Undef and redefine.
This commit is contained in:
Simon Marchi 2017-11-24 10:42:01 -05:00 committed by Simon Marchi
parent 7aabaf9d4a
commit 8172f16b5b
4 changed files with 174 additions and 8 deletions

View File

@ -1,3 +1,32 @@
2017-11-24 Simon Marchi <simon.marchi@polymtl.ca>
* common/common-utils.h: Include poison.h.
(xfree): Remove declaration, add definition with static_assert.
* common/common-utils.c (xfree): Remove.
* common/poison.h (IsMallocatable): Define.
(IsFreeable): Define.
(free): Delete for non-freeable types.
(xnew): New.
(XNEW): Undef and redefine.
(xcnew): New.
(XCNEW): Undef and redefine.
(xdelete): New.
(XDELETE): Undef and redefine.
(xnewvec): New.
(XNEWVEC): Undef and redefine.
(xcnewvec): New.
(XCNEWVEC): Undef and redefine.
(xresizevec): New.
(XRESIZEVEC): Undef and redefine.
(xdeletevec): New.
(XDELETEVEC): Undef and redefine.
(xnewvar): New.
(XNEWVAR): Undef and redefine.
(xcnewvar): New.
(XCNEWVAR): Undef and redefine.
(xresizevar): New.
(XRESIZEVAR): Undef and redefine.
2017-11-24 Simon Marchi <simon.marchi@polymtl.ca>
* gdbthread.h (private_thread_info): Define structure type, add

View File

@ -94,13 +94,6 @@ xzalloc (size_t size)
return xcalloc (1, size);
}
void
xfree (void *ptr)
{
if (ptr != NULL)
free (ptr); /* ARI: free */
}
void
xmalloc_failed (size_t size)
{

View File

@ -23,6 +23,8 @@
#include <string>
#include <vector>
#include "poison.h"
/* If possible, define FUNCTION_NAME, a macro containing the name of
the function being defined. Since this macro may not always be
defined, all uses must be protected by appropriate macro definition
@ -47,7 +49,17 @@
/* Like xmalloc, but zero the memory. */
void *xzalloc (size_t);
void xfree (void *);
template <typename T>
static void
xfree (T *ptr)
{
static_assert (IsFreeable<T>::value, "Trying to use xfree with a non-POD \
data type. Use operator delete instead.");
if (ptr != NULL)
free (ptr); /* ARI: free */
}
/* Like asprintf and vasprintf, but return the string, throw an error
if no memory. */

View File

@ -84,4 +84,136 @@ 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>
using IsMallocable = std::is_pod<T>;
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)
#endif /* COMMON_POISON_H */