From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id ITtqHA/vBmrO7DwAWB0awg (envelope-from ) for ; Fri, 15 May 2026 06:01:51 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=BKS9EnNx; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 6D2421E0B1; Fri, 15 May 2026 06:01:51 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 632671E093 for ; Fri, 15 May 2026 06:01:47 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E7D7240A24AC for ; Fri, 15 May 2026 10:01:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E7D7240A24AC Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=BKS9EnNx Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 0CEA240A248A for ; Fri, 15 May 2026 10:01:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0CEA240A248A Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 0CEA240A248A Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778839261; cv=none; b=x1QMq2hxm/I3eEqH1d7J7ojYzYS8dbtuumHPy7+4h44GFQj5gDl3lmLvfQo4NEgIdi4ScH99a/CDt6LbUvpmTLyRLMHF59YL7mnn/FpvZ4cRgO47BtLcwHQqMFlYhZzmm/2ofa93udCXdoVytzlyTiEPLyPZGPoS2MJ5CyDRXao= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778839261; c=relaxed/simple; bh=eRtrGtGQQOjmxtYUiEWQSvWOaoqflJ83biabfL0shiw=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=l+3E2jgMkwKO6FTdcwEGzv2Qs395q/83ev5QcELlZtXnksy/gdRzZlxLWaqQXFYLUJID+4RdhAXUSsfMN+QIRgZ2f1pdsiW3X+dQNwDMieha/QZ1weeQel4lb5MP3ltTxVMemxx0GIiQUc7BF6p4EPKwCVmVWXHRfcnKNUKz2Cc= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=BKS9EnNx DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0CEA240A248A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778839260; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0CP36XEo1cymtBteK8dyXUeYlhSnB6yYjbl17HYYjAQ=; b=BKS9EnNxQmUT0zIt0nXUzO2+wy8sU6iXn64SGIPWdgHyLd/YM5/3sAEcVBvENJlfjrD03X 8W3eTNqfKrw8t28PSYQsJW1pjUe+hZxNdl6BflKt0imdHbuETnUutf8zwIwqBhrnmeVDYT KkZA3XRYxfoYLS4pdw7LC20sgxAp67M= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-569-allsEtDxOp-QFUvi4zMkSQ-1; Fri, 15 May 2026 06:00:59 -0400 X-MC-Unique: allsEtDxOp-QFUvi4zMkSQ-1 X-Mimecast-MFC-AGG-ID: allsEtDxOp-QFUvi4zMkSQ_1778839258 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-45b7ff2140eso3448119f8f.3 for ; Fri, 15 May 2026 03:00:59 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778839257; x=1779444057; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=0CP36XEo1cymtBteK8dyXUeYlhSnB6yYjbl17HYYjAQ=; b=BC9osjuk9mybEo+JjeUs0WcnYi7efGWnii000Uvd2XkKAGHGgKY2TAwhD5A0pHNRoc c6PxNalVmF4zIbFlyHisdlvYUtKy9oTaqcnQGzcTxXbFOIoqkOhnpPcUqfYdBcyKI8if ovLrmOnM82BJe5fY0T0oJFuuj9KbqA2atRvyGOBHBTp8Wrm8cst0f+grJirA5oWsbVdf xibAdPaMek4wklXx+m0Xoq2uiMMvN4qyXrqj3H9flaTiUhXkjZ46jFkTIQwhk17o6GHW ou5MRoxfDu5jHSOrOfF60YtvxEQosOLJ1YT7opjsRRUyUuIPHpmHGoTBjL1zeXxX2BKg C3fg== X-Gm-Message-State: AOJu0YwpPOHNt2wponDPZlV99g2dV1/x3Em2w/f/pu7jJyCzabrfyV6p RHczy/FOlh1b8kcTrz1bqwJjCerUQe336HND2UswyNZI1NlA6lUH635Pe787rGX8xIOxrW33u2B Zkw5rUjWj42YLvdEedWPCxqKNmnkHznv2dA5i3F2I0ecvyHv++E6N09maQ95KKQiUZFBaXpEyDT ilCGWbiVCVgRZt2WF/7R1pyX84pd967lljDKoTAtklhanNvSo= X-Gm-Gg: Acq92OFXD5N7pQR7gPmkut+d3UnGaQxF/bWTMlCtvbDipi1E0PhY705md+90GlarHGD pEIa+4zjCB7pWFV7qJqfeSyKRIx+kJD4er3WCtzMCXFA5kk9U7N2YvQLuGyrYhebByyW4/fhlgW PCzpLMLgdbHTHoNQxPQtYELW3O6HgAQN4Vgn2obiZq51R7+infzQWvbhPWcgR1EGHwBQK3cemNb iQwv2Hxls1ICaJ/g/6VAgtK6khYruCIEaJm0HTwr+vK/Q0SJldf2hN+JO+mEjJCr8SGSFRqD237 4R0qaPYLTUmoE+xp/eJafrX5OYtU8UVhYdsuZgNy5l7xjL7M+ARFb/IkxfPigVNJzY+1gx6V8h4 ayQAXol9rGwpXe/Vp X-Received: by 2002:a05:600c:858d:b0:48f:e230:80a3 with SMTP id 5b1f17b1804b1-48fe6514c31mr35235665e9.33.1778839256337; Fri, 15 May 2026 03:00:56 -0700 (PDT) X-Received: by 2002:a05:600c:858d:b0:48f:e230:80a3 with SMTP id 5b1f17b1804b1-48fe6514c31mr35234675e9.33.1778839255188; Fri, 15 May 2026 03:00:55 -0700 (PDT) Received: from localhost ([31.111.84.232]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-48fe4c8344asm86551285e9.1.2026.05.15.03.00.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 May 2026 03:00:54 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 1/3] gdb/python: add type traits check for all PyObject sub-classes Date: Fri, 15 May 2026 11:00:46 +0100 Message-Id: <491de87828ea40daa77a485da4e14e476e0c7a1d.1778839043.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 9dvHcwL77WQLouti-XOWMhfAdfu7iZTCNvApt0Zb88Y_1778839258 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org All of our custom Python types are created as structs, like this: struct some_new_type : public PyObject { ... various fields ... }; Then instances of this struct are created by calling PyObject_New, either directly within GDB's C++ code, or within Python when a user's Python script creates an instance of that class. The problem is that Python is written in C, and PyObject_New doesn't call any constructors for `some_new_type`, nor for any of the fields within `some_new_type`. If `some_new_type` is Plain Old Data (POD), then this is fine. Or, to be more C++ specific, if `some_new_type` is trivially default constructable, then we're fine. But if a field within `some_new_type` has a non-trivial constructor, then we're in trouble as that constructor will never be run. An example of a problematic field type is frame_info_ptr. The constructor for this type registers the new object with a central management object, recording the `this` pointer, using this type within `some_new_type` will not work as expected; frame invalidation will not show up within the frame_info_ptr as you might expect. And so, this type trait exists. Whenever a struct is created to define a new Python type we should add a line like: static_assert (gdb::is_python_allocatable_v); This will fail if any field of `some_new_type` are unsuitable for this use. We don't actually check is_trivially_default_constructible here. Some types, e.g. ui_file_style::color, have non-trivial (or no default) constructors, but are still safe to use within `some_new_type` because their constructors just initialise data fields; there's nothing "special" that the constructor does that cannot be achieved by assigning the fields after creation with PyObject_New. What actually matters is that the type is trivially destructible (Python won't call C++ destructors, so destructors with side effects, like deregistering from a list, would be skipped) and trivially copyable (Python may copy objects with memcpy). Types like frame_info_ptr, whose constructors and destructors have side effects such as registering with a central management object, will be caught because they are neither trivially destructible nor trivially copyable. Simple POD types like ui_file_style are trivially destructible and copyable, so pass this trait. This commit adds the new type trait, and makes use of it in all cases but one, pending_frame_object in python/py-unwind.c, has a field of type frame_info_ptr, which is currently broken. This will be fixed, and the static_assert added, in the next commit. --- gdb/python/py-arch.c | 2 + gdb/python/py-block.c | 4 ++ gdb/python/py-breakpoint.c | 2 + gdb/python/py-cmd.c | 2 + gdb/python/py-color.c | 2 + gdb/python/py-connection.c | 2 + gdb/python/py-corefile.c | 4 ++ gdb/python/py-disasm.c | 8 +++ gdb/python/py-events.h | 2 + gdb/python/py-frame.c | 2 + gdb/python/py-instruction.c | 2 + gdb/python/py-lazy-string.c | 2 + gdb/python/py-linetable.c | 6 +++ gdb/python/py-membuf.c | 2 + gdb/python/py-micmd.c | 2 + gdb/python/py-param.c | 2 + gdb/python/py-prettyprint.c | 2 + gdb/python/py-record-btrace.c | 2 + gdb/python/py-record.c | 2 + gdb/python/py-record.h | 4 ++ gdb/python/py-ref.h | 3 ++ gdb/python/py-registers.c | 8 +++ gdb/python/py-style.c | 2 + gdb/python/py-symbol.c | 2 + gdb/python/py-symtab.c | 4 ++ gdb/python/py-tui.c | 2 + gdb/python/py-type.c | 4 ++ gdb/python/py-unwind.c | 2 + gdb/python/py-value.c | 2 + gdb/python/python-internal.h | 2 + gdb/python/python-traits.h | 92 +++++++++++++++++++++++++++++++++++ 31 files changed, 179 insertions(+) create mode 100644 gdb/python/python-traits.h diff --git a/gdb/python/py-arch.c b/gdb/python/py-arch.c index ac0c40dcf45..7a0cb0a2a59 100644 --- a/gdb/python/py-arch.c +++ b/gdb/python/py-arch.c @@ -27,6 +27,8 @@ struct arch_object : public PyObject struct gdbarch *gdbarch; }; +static_assert (gdb::is_python_allocatable_v); + static const registry::key> arch_object_data; diff --git a/gdb/python/py-block.c b/gdb/python/py-block.c index d9751d26378..39ec52ae373 100644 --- a/gdb/python/py-block.c +++ b/gdb/python/py-block.c @@ -33,6 +33,8 @@ struct block_object : public PyObject struct objfile *objfile; }; +static_assert (gdb::is_python_allocatable_v); + struct block_syms_iterator_object : public PyObject { /* The block. */ @@ -47,6 +49,8 @@ struct block_syms_iterator_object : public PyObject block_object *source; }; +static_assert (gdb::is_python_allocatable_v); + /* Require a valid block. All access to block_object->block should be gated by this call. */ #define BLPY_REQUIRE_VALID(block_obj, block) \ diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c index d96c67694b3..fb6fab6b60b 100644 --- a/gdb/python/py-breakpoint.c +++ b/gdb/python/py-breakpoint.c @@ -46,6 +46,8 @@ struct gdbpy_breakpoint_location_object : public PyObject gdbpy_breakpoint_object *owner; }; +static_assert (gdb::is_python_allocatable_v); + /* Require that BREAKPOINT and LOCATION->OWNER are the same; throw a Python exception if they are not. */ #define BPLOCPY_REQUIRE_VALID(Breakpoint, Location) \ diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c index 3fbc26b0cde..a1a02bd7eb5 100644 --- a/gdb/python/py-cmd.c +++ b/gdb/python/py-cmd.c @@ -63,6 +63,8 @@ struct cmdpy_object : public PyObject struct cmd_list_element *sub_list; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject cmdpy_object_type; /* Constants used by this module. */ diff --git a/gdb/python/py-color.c b/gdb/python/py-color.c index 971209958cf..29a42977adc 100644 --- a/gdb/python/py-color.c +++ b/gdb/python/py-color.c @@ -43,6 +43,8 @@ struct colorpy_object : public PyObject ui_file_style::color color; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject colorpy_object_type; /* See py-color.h. */ diff --git a/gdb/python/py-connection.c b/gdb/python/py-connection.c index a8bea4d832f..8f9fc4a7eee 100644 --- a/gdb/python/py-connection.c +++ b/gdb/python/py-connection.c @@ -42,6 +42,8 @@ struct connection_object : public PyObject struct process_stratum_target *target; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject connection_object_type; extern PyTypeObject remote_connection_object_type; diff --git a/gdb/python/py-corefile.c b/gdb/python/py-corefile.c index 0fa4e90488c..1cdbae98149 100644 --- a/gdb/python/py-corefile.c +++ b/gdb/python/py-corefile.c @@ -65,6 +65,8 @@ struct corefile_mapped_file_object : public PyObject bool is_main_exec_p; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject corefile_mapped_file_object_type; /* A gdb.CorefileMappedFileRegion object. */ @@ -80,6 +82,8 @@ struct corefile_mapped_file_region_object : public PyObject ULONGEST file_offset; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject corefile_mapped_file_region_object_type; /* Clear the inferior pointer in a Corefile object OBJ when an inferior is diff --git a/gdb/python/py-disasm.c b/gdb/python/py-disasm.c index 1c5661dd307..9591cb82133 100644 --- a/gdb/python/py-disasm.c +++ b/gdb/python/py-disasm.c @@ -50,6 +50,8 @@ struct disasm_info_object : public PyObject struct disasm_info_object *next; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject disasm_info_object_type; /* Implement gdb.disassembler.DisassembleAddressPart type. An object of @@ -69,6 +71,8 @@ struct disasm_addr_part_object : public PyObject struct gdbarch *gdbarch; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject disasm_addr_part_object_type; /* Implement gdb.disassembler.DisassembleTextPart type. An object of @@ -84,6 +88,8 @@ struct disasm_text_part_object : public PyObject enum disassembler_style style; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject disasm_text_part_object_type; extern PyTypeObject disasm_part_object_type; @@ -103,6 +109,8 @@ struct disasm_result_object : public PyObject std::vector> *parts; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject disasm_result_object_type; /* When this is false we fast path out of gdbpy_print_insn, which should diff --git a/gdb/python/py-events.h b/gdb/python/py-events.h index e44b4b4a761..169a5f4a4db 100644 --- a/gdb/python/py-events.h +++ b/gdb/python/py-events.h @@ -32,6 +32,8 @@ struct eventregistry_object : public PyObject PyObject *callbacks; }; +static_assert (gdb::is_python_allocatable_v); + /* Struct holding references to event registries both in python and c. This is meant to be a singleton. */ diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c index 1420d2ac5b9..ad590c7f55a 100644 --- a/gdb/python/py-frame.c +++ b/gdb/python/py-frame.c @@ -44,6 +44,8 @@ struct frame_object : public PyObject int frame_id_is_next; }; +static_assert (gdb::is_python_allocatable_v); + /* Require a valid frame. This must be called inside a TRY_CATCH, or another context in which a gdb exception is allowed. */ #define FRAPY_REQUIRE_VALID(frame_obj, frame) \ diff --git a/gdb/python/py-instruction.c b/gdb/python/py-instruction.c index df64d85988f..d8dad094ee9 100644 --- a/gdb/python/py-instruction.c +++ b/gdb/python/py-instruction.c @@ -32,6 +32,8 @@ PyTypeObject py_insn_type = { struct py_insn_obj: public PyObject {}; +static_assert (gdb::is_python_allocatable_v); + /* Getter function for gdb.Instruction attributes. */ static PyObject * diff --git a/gdb/python/py-lazy-string.c b/gdb/python/py-lazy-string.c index fe191451e54..79592b10aa6 100644 --- a/gdb/python/py-lazy-string.c +++ b/gdb/python/py-lazy-string.c @@ -51,6 +51,8 @@ struct lazy_string_object : public PyObject PyObject *type; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject lazy_string_object_type; static PyObject * diff --git a/gdb/python/py-linetable.c b/gdb/python/py-linetable.c index 2afa9b033e7..c0368355148 100644 --- a/gdb/python/py-linetable.c +++ b/gdb/python/py-linetable.c @@ -27,6 +27,8 @@ struct linetable_entry_object : public PyObject CORE_ADDR pc; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject linetable_entry_object_type; struct linetable_object : public PyObject @@ -37,6 +39,8 @@ struct linetable_object : public PyObject PyObject *symtab; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject linetable_object_type; struct ltpy_iterator_object : public PyObject @@ -49,6 +53,8 @@ struct ltpy_iterator_object : public PyObject PyObject *source; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject ltpy_iterator_object_type; /* Internal helper function to extract gdb.Symtab from a gdb.LineTable diff --git a/gdb/python/py-membuf.c b/gdb/python/py-membuf.c index e3bf5e2ceab..fa5156b885e 100644 --- a/gdb/python/py-membuf.c +++ b/gdb/python/py-membuf.c @@ -31,6 +31,8 @@ struct membuf_object : public PyObject CORE_ADDR length; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject membuf_object_type; /* Wrap BUFFER, ADDRESS, and LENGTH into a gdb.Membuf object. ADDRESS is diff --git a/gdb/python/py-micmd.c b/gdb/python/py-micmd.c index 6edea04ccb5..241e80bea5b 100644 --- a/gdb/python/py-micmd.c +++ b/gdb/python/py-micmd.c @@ -74,6 +74,8 @@ struct micmdpy_object : public PyObject char *mi_command_name; }; +static_assert (gdb::is_python_allocatable_v); + /* The MI command implemented in Python. */ struct mi_command_py : public mi_command diff --git a/gdb/python/py-param.c b/gdb/python/py-param.c index bc028f1746c..35f55c3dbd0 100644 --- a/gdb/python/py-param.c +++ b/gdb/python/py-param.c @@ -141,6 +141,8 @@ struct parmpy_object : public PyObject const char **enumeration; }; +static_assert (gdb::is_python_allocatable_v); + /* Wraps a setting around an existing parmpy_object. This abstraction is used to manipulate the value in S->VALUE in a type safe manner using the setting interface. */ diff --git a/gdb/python/py-prettyprint.c b/gdb/python/py-prettyprint.c index 0cf0cde881c..b0a296d8010 100644 --- a/gdb/python/py-prettyprint.c +++ b/gdb/python/py-prettyprint.c @@ -784,6 +784,8 @@ gdbpy_get_print_options (value_print_options *opts) struct printer_object : public PyObject {}; +static_assert (gdb::is_python_allocatable_v); + /* The ValuePrinter type object. */ PyTypeObject printer_object_type = { diff --git a/gdb/python/py-record-btrace.c b/gdb/python/py-record-btrace.c index 6026de91e67..267429832d9 100644 --- a/gdb/python/py-record-btrace.c +++ b/gdb/python/py-record-btrace.c @@ -48,6 +48,8 @@ struct btpy_list_object : public PyObject PyTypeObject* element_type; }; +static_assert (gdb::is_python_allocatable_v); + /* Python type for btrace lists. */ static PyTypeObject btpy_list_type = { diff --git a/gdb/python/py-record.c b/gdb/python/py-record.c index 294da0725e1..5394d63c803 100644 --- a/gdb/python/py-record.c +++ b/gdb/python/py-record.c @@ -67,6 +67,8 @@ struct recpy_gap_object : public PyObject Py_ssize_t number; }; +static_assert (gdb::is_python_allocatable_v); + /* Implementation of record.method. */ static PyObject * diff --git a/gdb/python/py-record.h b/gdb/python/py-record.h index 35ab54cf6ab..f62fcc2a7e9 100644 --- a/gdb/python/py-record.h +++ b/gdb/python/py-record.h @@ -34,6 +34,8 @@ struct recpy_record_object : public PyObject enum record_method method; }; +static_assert (gdb::is_python_allocatable_v); + /* Python recorded element object. This is generic enough to represent recorded instructions as well as recorded function call segments, hence the generic name. */ @@ -49,6 +51,8 @@ struct recpy_element_object : public PyObject Py_ssize_t number; }; +static_assert (gdb::is_python_allocatable_v); + /* Python RecordInstruction type. */ extern PyTypeObject recpy_insn_type; diff --git a/gdb/python/py-ref.h b/gdb/python/py-ref.h index dc0b14814af..3d2906fd7f5 100644 --- a/gdb/python/py-ref.h +++ b/gdb/python/py-ref.h @@ -21,6 +21,7 @@ #define GDB_PYTHON_PY_REF_H #include "gdbsupport/gdb_ref_ptr.h" +#include "python-traits.h" /* A policy class for gdb::ref_ptr for Python reference counting. */ struct gdbpy_ref_policy @@ -102,4 +103,6 @@ struct gdbpy_dict_wrapper : public PyObject } }; +static_assert (gdb::is_python_allocatable_v); + #endif /* GDB_PYTHON_PY_REF_H */ diff --git a/gdb/python/py-registers.c b/gdb/python/py-registers.c index c6e0748e935..af75cb81bbe 100644 --- a/gdb/python/py-registers.c +++ b/gdb/python/py-registers.c @@ -45,6 +45,8 @@ struct register_descriptor_iterator_object : public PyObject struct gdbarch *gdbarch; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject register_descriptor_iterator_object_type; /* A register descriptor. */ @@ -57,6 +59,8 @@ struct register_descriptor_object : public PyObject struct gdbarch *gdbarch; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject register_descriptor_object_type; /* Structure for iterator over register groups. */ @@ -69,6 +73,8 @@ struct reggroup_iterator_object : public PyObject struct gdbarch *gdbarch; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject reggroup_iterator_object_type; /* A register group object. */ @@ -78,6 +84,8 @@ struct reggroup_object : public PyObject const struct reggroup *reggroup; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject reggroup_object_type; /* Map from GDB's internal reggroup objects to the Python diff --git a/gdb/python/py-style.c b/gdb/python/py-style.c index 60a9ea4792f..c45eba60867 100644 --- a/gdb/python/py-style.c +++ b/gdb/python/py-style.c @@ -46,6 +46,8 @@ struct style_object : public PyObject char *style_name; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject style_object_type; /* Initialize the 'style' module. */ diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c index 6293b658ea1..a3b10d3df24 100644 --- a/gdb/python/py-symbol.c +++ b/gdb/python/py-symbol.c @@ -31,6 +31,8 @@ struct symbol_object : public PyObject struct symbol *symbol; }; +static_assert (gdb::is_python_allocatable_v); + /* Require a valid symbol. All access to symbol_object->symbol should be gated by this call. */ #define SYMPY_REQUIRE_VALID(symbol_obj, symbol) \ diff --git a/gdb/python/py-symtab.c b/gdb/python/py-symtab.c index c5e18543740..dffddecb412 100644 --- a/gdb/python/py-symtab.c +++ b/gdb/python/py-symtab.c @@ -32,6 +32,8 @@ struct symtab_object : public PyObject struct symtab *symtab; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject symtab_object_type; static const gdbpy_registry> stpy_registry; @@ -61,6 +63,8 @@ struct sal_object : public PyObject sal_object *next; }; +static_assert (gdb::is_python_allocatable_v); + /* This is called when an objfile is about to be freed. Invalidate the sal object as further actions on the sal would result in bad data. All access to obj->sal should be gated by diff --git a/gdb/python/py-tui.c b/gdb/python/py-tui.c index be19193770f..4db04941d2d 100644 --- a/gdb/python/py-tui.c +++ b/gdb/python/py-tui.c @@ -53,6 +53,8 @@ struct gdbpy_tui_window: public PyObject bool is_valid () const; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject gdbpy_tui_window_object_type; /* A TUI window written in Python. */ diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c index 263d48a9365..4b6ac0e9eef 100644 --- a/gdb/python/py-type.c +++ b/gdb/python/py-type.c @@ -33,6 +33,8 @@ struct type_object : public PyObject struct type *type; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject type_object_type; /* A Field object. */ @@ -52,6 +54,8 @@ struct typy_iterator_object : public PyObject type_object *source; }; +static_assert (gdb::is_python_allocatable_v); + extern PyTypeObject type_iterator_object_type; /* This is used to initialize various gdb.TYPE_ constants. */ diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c index dcf86f7db3d..ed0ba89d267 100644 --- a/gdb/python/py-unwind.c +++ b/gdb/python/py-unwind.c @@ -104,6 +104,8 @@ struct unwind_info_object : public PyObject std::vector *saved_regs; }; +static_assert (gdb::is_python_allocatable_v); + /* The data we keep for a frame we can unwind: frame ID and an array of (register_number, register_value) pairs. */ diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c index a5b2303728c..ca88a35e357 100644 --- a/gdb/python/py-value.c +++ b/gdb/python/py-value.c @@ -64,6 +64,8 @@ struct value_object : public PyObject PyObject *content_bytes; }; +static_assert (gdb::is_python_allocatable_v); + /* List of all values which are currently exposed to Python. It is maintained so that when an objfile is discarded, preserve_values can copy the values' types if needed. */ diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 37bc37691fe..ac01fa5a385 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -364,6 +364,8 @@ struct gdbpy_breakpoint_object : public PyObject int is_finish_bp; }; +static_assert (gdb::is_python_allocatable_v); + /* Require that BREAKPOINT be a valid breakpoint ID; throw a Python exception if it is invalid. */ #define BPPY_REQUIRE_VALID(Breakpoint) \ diff --git a/gdb/python/python-traits.h b/gdb/python/python-traits.h new file mode 100644 index 00000000000..7babb0fc131 --- /dev/null +++ b/gdb/python/python-traits.h @@ -0,0 +1,92 @@ +/* Type traits relating to GDB's Python integration. + + Copyright (C) 2008-2026 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 GDB_PYTHON_PYTHON_TRAITS_H +#define GDB_PYTHON_PYTHON_TRAITS_H + +namespace gdb +{ +/* All of our custom Python types are created as structs, like this: + + struct some_new_type : public PyObject + { + ... various fields ... + }; + + Then instances of this struct are created by calling PyObject_New, + either directly within GDB's C++ code, or within Python when a user's + Python script creates an instance of that class. + + The problem is that Python is written in C, and PyObject_New doesn't + call any constructors for `some_new_type`, nor for any of the fields + within `some_new_type`. + + If `some_new_type` is Plain Old Data (POD), then this is fine. Or, to + be more C++ specific, if `some_new_type` is trivially default + constructable, then we're fine. + + But if a field within `some_new_type` has a non-trivial constructor, + then we're in trouble as that constructor will never be run. + + An example of a problematic field type is frame_info_ptr. The + constructor for this type registers the new object with a central + management object, recording the `this` pointer, using this type within + `some_new_type` will not work as expected; frame invalidation will not + show up within the frame_info_ptr as you might expect. + + And so, this type trait exists. Whenever a struct is created to define + a new Python type we should add a line like: + + static_assert (gdb::is_python_allocatable_v); + + This will fail if any field of `some_new_type` is unsuitable for this + use. + + We don't actually check is_trivially_default_constructible here. Some + types, e.g. ui_file_style::color, have non-trivial (or no default) + constructors, but are still safe to use within `some_new_type` because + their constructors just initialise data fields; there's nothing + "special" that the constructor does that cannot be achieved by + assigning the fields after creation with PyObject_New. + + What actually matters is that the type is trivially destructible + (Python won't call C++ destructors, so destructors with side effects, + like deregistering from a list, would be skipped) and trivially + copyable (Python may copy objects with memcpy). Types like + frame_info_ptr, whose constructors and destructors have side effects + such as registering with a central management object, will be caught + because they are neither trivially destructible nor trivially copyable. + Types like ui_file_style are trivially destructible and copyable, so + pass this trait. */ + +template +struct is_python_allocatable { + static constexpr bool value = + std::is_trivially_destructible_v && + std::is_trivially_copyable_v; +}; + +/* Helper for the above trait to make it more usable. */ + +template +inline constexpr bool is_python_allocatable_v + = is_python_allocatable::value; +} + +#endif /* GDB_PYTHON_PYTHON_TRAITS_H */ -- 2.25.4