From patchwork Thu Apr 13 02:27:51 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 20010 Received: (qmail 108697 invoked by alias); 13 Apr 2017 02:28:07 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 105946 invoked by uid 89); 13 Apr 2017 02:28:02 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=2099, 1558, stolen, declaring X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 13 Apr 2017 02:27:57 +0000 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 82BAC3D941 for ; Thu, 13 Apr 2017 02:27:57 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 82BAC3D941 Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=palves@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 82BAC3D941 Received: from cascais.lan (ovpn04.gateway.prod.ext.phx2.redhat.com [10.5.9.4]) by smtp.corp.redhat.com (Postfix) with ESMTP id D4ABC7DEE6 for ; Thu, 13 Apr 2017 02:27:56 +0000 (UTC) From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH 1/5] Poison non-POD memset & non-trivially-copyable memcpy/memmove Date: Thu, 13 Apr 2017 03:27:51 +0100 Message-Id: <1492050475-9238-2-git-send-email-palves@redhat.com> In-Reply-To: <1492050475-9238-1-git-send-email-palves@redhat.com> References: <1492050475-9238-1-git-send-email-palves@redhat.com> MIME-Version: 1.0 This patch catches invalid initialization of non-POD types with memset, at compile time. This is what I used to catch the problems fixed by the rest of the series: $ make -k 2>&1 | grep "deleted function" src/gdb/breakpoint.c:951:53: error: use of deleted function ‘void* memset(T*, int, size_t) [with T = bp_location; = void; size_t = long unsigned int]’ src/gdb/breakpoint.c:7325:32: error: use of deleted function ‘void* memset(T*, int, size_t) [with T = bp_location; = void; size_t = long unsigned int]’ src/gdb/btrace.c:1153:42: error: use of deleted function ‘void* memset(T*, int, size_t) [with T = btrace_insn; = void; size_t = long unsigned int]’ I'll move this to the end of the series before pushing (if agreed). (I've posted another series recently that adds some of the same traits bits to common/traits.h. They're really useful.) gdb/ChangeLog: yyyy-mm-dd Pedro Alves * common/common-defs.h: Include "common/poison.h". * common/function-view.h: (Not, Or, Requires): Move to traits.h. * common/poison.h: New file. * common/traits.h: Include . (Not, Or, Requires): New, moved from common/function-view.h. (And): New. --- gdb/common/common-defs.h | 1 + gdb/common/function-view.h | 40 +++------------------- gdb/common/poison.h | 83 ++++++++++++++++++++++++++++++++++++++++++++++ gdb/common/traits.h | 55 ++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 36 deletions(-) create mode 100644 gdb/common/poison.h diff --git a/gdb/common/common-defs.h b/gdb/common/common-defs.h index af37111..439bce6 100644 --- a/gdb/common/common-defs.h +++ b/gdb/common/common-defs.h @@ -82,6 +82,7 @@ #include "common-debug.h" #include "cleanups.h" #include "common-exceptions.h" +#include "common/poison.h" #define EXTERN_C extern "C" #define EXTERN_C_PUSH extern "C" { diff --git a/gdb/common/function-view.h b/gdb/common/function-view.h index 66a691b..d4ff2f0 100644 --- a/gdb/common/function-view.h +++ b/gdb/common/function-view.h @@ -153,34 +153,6 @@ namespace gdb { -namespace traits { - /* A few trait helpers. */ - template - struct Not : public std::integral_constant - {}; - - template - struct Or; - - template<> - struct Or<> : public std::false_type - {}; - - template - struct Or : public B1 - {}; - - template - struct Or - : public std::conditional::type - {}; - - template - struct Or - : public std::conditional>::type - {}; -} /* namespace traits */ - namespace fv_detail { /* Bits shared by all function_view instantiations that do not depend on the template parameters. */ @@ -209,9 +181,9 @@ class function_view { template using CompatibleReturnType - = traits::Or, - std::is_same, - std::is_convertible>; + = gdb::Or, + std::is_same, + std::is_convertible>; /* True if Func can be called with Args, and either the result is Res, convertible to Res or Res is void. */ @@ -227,10 +199,6 @@ class function_view : std::is_same::type> {}; - /* Helper to make SFINAE logic easier to read. */ - template - using Requires = typename std::enable_if::type; - public: /* NULL by default. */ @@ -248,7 +216,7 @@ class function_view compatible. */ template >>, + typename = Requires>>, typename = Requires>> function_view (Callable &&callable) noexcept { diff --git a/gdb/common/poison.h b/gdb/common/poison.h new file mode 100644 index 0000000..57a1733 --- /dev/null +++ b/gdb/common/poison.h @@ -0,0 +1,83 @@ +/* Poison symbols at compile time. + + Copyright (C) 2017 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 . */ + +#ifndef COMMON_POISON_H +#define COMMON_POISON_H + +#include "traits.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 m_data; + }; + +and old code was initializing B objects like this: + + struct B b; + memset (&b, 0, sizeof (B)); // 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 +struct IsMemsettable + : gdb::Or, + std::is_pod> +{}; + +template >>> +void *memset (T *s, int c, size_t n) = delete; + +/* 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 +struct IsRelocatable + : gdb::Or, + std::is_trivially_copyable> +{}; + +/* True if both source and destination are relocatable. */ + +template +using BothAreRelocatable + = gdb::And, IsRelocatable>; + +template >>> +void *memcpy (D *dest, const S *src, size_t n) = delete; + +template >>> +void *memmove (D *dest, const S *src, size_t n) = delete; + +#endif /* COMMON_POISON_H */ diff --git a/gdb/common/traits.h b/gdb/common/traits.h index 4b7bac3..1ce2327 100644 --- a/gdb/common/traits.h +++ b/gdb/common/traits.h @@ -18,6 +18,8 @@ #ifndef COMMON_TRAITS_H #define COMMON_TRAITS_H +#include + namespace gdb { /* Pre C++14-safe (CWG 1558) version of C++17's std::void_t. See @@ -29,6 +31,59 @@ struct make_void { typedef void type; }; template using void_t = typename make_void::type; +/* A few trait helpers, mainly stolen from libstdc++. Uppercase + because "and/or", etc. are reserved keywords. */ + +template +struct Not : public std::integral_constant +{}; + +template +struct Or; + +template<> +struct Or<> : public std::false_type +{}; + +template +struct Or : public B1 +{}; + +template +struct Or + : public std::conditional::type +{}; + +template +struct Or + : public std::conditional>::type +{}; + +template +struct And; + +template<> +struct And<> : public std::true_type +{}; + +template +struct And : public B1 +{}; + +template +struct And + : public std::conditional::type +{}; + +template +struct And + : public std::conditional, B1>::type +{}; + +/* Helper to make SFINAE logic easier to read. */ +template +using Requires = typename std::enable_if::type; + } #endif /* COMMON_TRAITS_H */