From: Simon Marchi <simon.marchi@polymtl.ca>
To: Pedro Alves <palves@redhat.com>
Cc: Simon Marchi <simon.marchi@ericsson.com>, gdb-patches@sourceware.org
Subject: Re: [PATCH 4/4] Poison XNEW and friends for types that should use new/delete
Date: Thu, 23 Nov 2017 17:27:00 -0000 [thread overview]
Message-ID: <c225643d40ebb855e7779dfd0e462c00@polymtl.ca> (raw)
In-Reply-To: <ad4f7bb0-a3cb-1077-206b-ed20437e8e67@redhat.com>
On 2017-11-23 10:02, Pedro Alves wrote:
> On 11/22/2017 04:41 PM, Simon Marchi wrote:
>> From: Simon Marchi <simon.marchi@polymtl.ca>
>>
>> This patch (finally!) makes it so that trying to use XNEW with a type
>> that requires "new" will cause a compilation error.
>
> Yay!
>
> 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:
>>
>
> Yeah, in the memset poisoning I just disabled the poisoning on older
> compilers. This is the "#if HAVE_IS_TRIVIALLY_COPYABLE" check in
> poison.h.
I'm not sure if you are suggesting adding
HAVE_IS_TRIVIALLY_CONSTRUCTIBLE, but since we can use std::is_pod
easily, I think it's simpler just to use that (even if it's a bit more
strict than needed).
>> using IsMallocatable = std::is_pod<T>;
>>
>
> Nit, I think "malloc-able" is more common than "malloc-atable".
> At least, the latter sounds odd to me. Or sounds like
> "m-allocatable", which is a different thing. :-)
Agreed.
>
>> 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>>;
>>
>> For simplicity, we could also do for std::is_pod for IsFreeable as
>> well,
>> if you prefer.
>>
>> I chose to put static_assert in the functions, instead of using
>> gdb::Requires in the template as SFINAE, because it allows to put a
>> message, which I think makes the compiler error more understandable.
>> With gdb::Requires, the error is:
>
> Right, I think static_assert is what I had suggest initially too.
> SFINAE alone wouldn't sound right to me here.
>
> The right alternative to static_assert would be SFINAE+"=delete;",
> which is what we do for the memcpy/memcpy poisoning, and what
> you're doing to "free".
>
> =delete keeps the function/overload in the overload set, serving
> as "honeypot", so you get an error about trying to call a
> deleted function.
>
> You could do that to xfree instead
> of the static_assert, but I guess inlining xfree ends up being
> a good thing.
Ah yeah, it would probably make the message a bit clearer. Instead of
saying "I can't find a function that matches", it would say "I found a
function that matches, but you can't use it". I'll just keep
static_assert for xfree as well, since it ends up clearer anyway.
>> I think the first one is more likely to just make people yell at their
>> screen, especially those less used to C++.
>
> Yes, don't do that. :-)
>
>>
>> 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.
>
> Good.
>
>>
>> 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.
>> ---
>> gdb/common/common-utils.c | 7 ---
>> gdb/common/common-utils.h | 14 ++++-
>> gdb/common/poison.h | 132
>> ++++++++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 145 insertions(+), 8 deletions(-)
>>
>> diff --git a/gdb/common/common-utils.c b/gdb/common/common-utils.c
>> index 7139302..66d6161 100644
>> --- a/gdb/common/common-utils.c
>> +++ b/gdb/common/common-utils.c
>> @@ -95,13 +95,6 @@ xzalloc (size_t size)
>> }
>>
>> void
>> -xfree (void *ptr)
>> -{
>> - if (ptr != NULL)
>> - free (ptr); /* ARI: free */
>> -}
>> -
>> -void
>> xmalloc_failed (size_t size)
>> {
>> malloc_failure (size);
>> diff --git a/gdb/common/common-utils.h b/gdb/common/common-utils.h
>> index 4926a32..feb4790 100644
>> --- a/gdb/common/common-utils.h
>> +++ b/gdb/common/common-utils.h
>> @@ -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. */
>> diff --git a/gdb/common/poison.h b/gdb/common/poison.h
>> index 37dd35e..de4cefa 100644
>> --- a/gdb/common/poison.h
>> +++ b/gdb/common/poison.h
>> @@ -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 IsMallocatable = 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 (IsMallocatable<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 (IsMallocatable<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*
>
> Missing space after T in several of these functions.
Oops, thanks.
>> +xnewvec (size_t n)
>> +{
>> + static_assert (IsMallocatable<T>::value, "Trying to use XNEWVEC
>> with a \
>> +non-POD data type. Use operator new[] (or std::vector) instead.");
>> + return XNEWVEC (T, n);
>> +}
>> +
>
> Other than the formatting, this LGTM. Thanks a lot for doing this.
Thanks, I'm glad that I won't have to carry that branch on the side
anymore :)
Simon
next prev parent reply other threads:[~2017-11-23 17:27 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-11-22 16:41 [PATCH 0/4] Poison XNEW and friends for non-POD types Simon Marchi
2017-11-22 16:41 ` [PATCH 1/4] Create private_inferior class hierarchy Simon Marchi
2017-11-22 22:20 ` Joel Brobecker
2017-11-24 15:46 ` Simon Marchi
2017-11-24 21:31 ` Joel Brobecker
2017-11-23 14:09 ` Pedro Alves
2017-11-23 16:17 ` Simon Marchi
2017-11-22 16:42 ` [PATCH 3/4] Create private_thread_info hierarchy Simon Marchi
2017-11-23 14:41 ` Pedro Alves
2017-11-23 16:54 ` Simon Marchi
2017-11-23 16:56 ` Simon Marchi
2017-11-22 16:42 ` [PATCH 4/4] Poison XNEW and friends for types that should use new/delete Simon Marchi
2017-11-23 15:02 ` Pedro Alves
2017-11-23 17:27 ` Simon Marchi [this message]
2017-11-23 17:31 ` Pedro Alves
2017-11-22 16:42 ` [PATCH 2/4] remote: C++ify thread_item and threads_listing_context Simon Marchi
2017-11-23 14:22 ` Pedro Alves
2017-11-23 16:48 ` Simon Marchi
2017-11-23 16:52 ` Pedro Alves
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=c225643d40ebb855e7779dfd0e462c00@polymtl.ca \
--to=simon.marchi@polymtl.ca \
--cc=gdb-patches@sourceware.org \
--cc=palves@redhat.com \
--cc=simon.marchi@ericsson.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox