* [PATCH] Do not crash on recursive pointer types
@ 2025-11-14 19:02 Tom Tromey
2025-11-15 21:27 ` Kevin Buettner
0 siblings, 1 reply; 2+ messages in thread
From: Tom Tromey @ 2025-11-14 19:02 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
In Ada, it's possible to create a recursive pointer type, or two
mutually recursive pointer types. gdb will crash when reading the
DWARF for these.
These types aren't actually useful, and so are unlikely to appear in
real code. Still, gdb shouldn't crash.
This patch handles this case by noticing recursive pointer types and
representing them as pointer-to-void.
---
gdb/dwarf2/read.c | 84 ++++++++++++++++++-
gdb/testsuite/gdb.ada/recursive-access.exp | 31 +++++++
.../gdb.ada/recursive-access/pack.ads | 26 ++++++
.../gdb.ada/recursive-access/prog.adb | 23 +++++
4 files changed, 163 insertions(+), 1 deletion(-)
create mode 100644 gdb/testsuite/gdb.ada/recursive-access.exp
create mode 100644 gdb/testsuite/gdb.ada/recursive-access/pack.ads
create mode 100644 gdb/testsuite/gdb.ada/recursive-access/prog.adb
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 29f100b7638..f31f0b30858 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -916,6 +916,9 @@ static const char *dwarf2_physname (const char *name, struct die_info *die,
static struct die_info *dwarf2_extension (struct die_info *die,
struct dwarf2_cu **);
+static die_info *follow_die_offset (const section_and_offset &target,
+ dwarf2_cu **ref_cu);
+
static struct die_info *follow_die_ref_or_sig (struct die_info *,
const struct attribute *,
struct dwarf2_cu **);
@@ -12725,6 +12728,75 @@ namespace_name (struct die_info *die, int *is_anonymous, struct dwarf2_cu *cu)
return name;
}
+/* A convenience structure that holds a CU and a DIE. */
+
+struct cu_die_pair
+{
+ die_info *die;
+ dwarf2_cu *cu;
+
+ /* Return true if this object holds a valid DIE. */
+ bool valid () const
+ {
+ return die != nullptr;
+ }
+
+ /* Compare two cu_die_pair objects. */
+ bool operator!= (const cu_die_pair &other) const
+ {
+ return die != other.die || cu != other.cu;
+ }
+};
+
+/* Follow the DW_AT_type reference, if any, from ORIG. The return
+ value will be valid only when DW_AT_type exists. In other cases,
+ including when the incoming ORIG is not valid, an invalid
+ cu_die_pair is returned. */
+
+static cu_die_pair
+follow_type (cu_die_pair orig)
+{
+ /* This simplifies the caller a little. */
+ if (!orig.valid ())
+ return {};
+
+ attribute *type_attr = dwarf2_attr (orig.die, DW_AT_type, orig.cu);
+ if (type_attr == nullptr || !type_attr->form_is_ref ())
+ return {};
+
+ cu_die_pair result = orig;
+ sect_offset sect_off = type_attr->get_ref_die_offset ();
+ const dwarf2_section_info §ion = get_section_for_ref (*type_attr,
+ orig.cu);
+ result.die = follow_die_offset ({ §ion, sect_off }, &result.cu);
+
+ /* Note that we do not check for DW_TAG_pointer_type here. GNAT, at
+ least, will emit recursive pointers that "indirect" via typedefs,
+ so checkpoint purely for pointer types would not find these. */
+ return result;
+}
+
+/* Return true if DIE is a self-referential pointer type; false
+ otherwise. CU is the origin of DIE. */
+
+static bool
+is_recursive_pointer (die_info *die, dwarf2_cu *cu)
+{
+ cu_die_pair tortoise { die, cu };
+ gdb_assert (tortoise.valid ());
+ cu_die_pair hare = follow_type (tortoise);
+
+ while (tortoise != hare)
+ {
+ tortoise = follow_type (tortoise);
+ hare = follow_type (follow_type (hare));
+ if (!tortoise.valid () || !hare.valid ())
+ return false;
+ }
+
+ return true;
+}
+
/* Extract all information from a DW_TAG_pointer_type DIE and add to
the user defined type vector. */
@@ -12739,7 +12811,17 @@ read_tag_pointer_type (struct die_info *die, struct dwarf2_cu *cu)
int byte_size;
struct type *target_type;
- target_type = die_type (die, cu);
+ /* In Ada, it's possible to create a self-referential pointer type.
+ These aren't useful, but nevertheless we take care to avoid a gdb
+ crash in this situation. Instead just turn these into a
+ pointer-to-void. */
+ if (is_recursive_pointer (die, cu))
+ {
+ type_allocator alloc (cu->per_objfile->objfile, cu->lang ());
+ target_type = alloc.new_type (TYPE_CODE_VOID, 0, nullptr);
+ }
+ else
+ target_type = die_type (die, cu);
/* The die_type call above may have already set the type for this DIE. */
type = get_die_type (die, cu);
diff --git a/gdb/testsuite/gdb.ada/recursive-access.exp b/gdb/testsuite/gdb.ada/recursive-access.exp
new file mode 100644
index 00000000000..833be936a10
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/recursive-access.exp
@@ -0,0 +1,31 @@
+# Copyright 2025 Free Software Foundation, Inc.
+#
+# 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/>.
+
+# Test that recursive access types do not cause a crash.
+
+load_lib "ada.exp"
+
+require allow_ada_tests
+
+standard_ada_testfile prog
+
+if {[gdb_compile_ada "${srcfile}" "${binfile}" executable {debug}] != ""} {
+ return
+}
+
+clean_restart ${testfile}
+
+# The bug was that even reading these types caused a crash.
+gdb_test_no_output "maint expand-symtabs"
diff --git a/gdb/testsuite/gdb.ada/recursive-access/pack.ads b/gdb/testsuite/gdb.ada/recursive-access/pack.ads
new file mode 100644
index 00000000000..fe06edc56e5
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/recursive-access/pack.ads
@@ -0,0 +1,26 @@
+-- Copyright 2025 Free Software Foundation, Inc.
+--
+-- 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/>.
+
+package Pack is
+ -- With GCC, this makes a directly self-referential pointer type.
+ type Direct;
+ subtype Sub is Direct;
+ type Direct is access Sub;
+
+ -- With GCC, this makes two mutually recursive pointer types.
+ type Second;
+ type First is access Second;
+ type Second is access First;
+end Pack;
diff --git a/gdb/testsuite/gdb.ada/recursive-access/prog.adb b/gdb/testsuite/gdb.ada/recursive-access/prog.adb
new file mode 100644
index 00000000000..f740343feb8
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/recursive-access/prog.adb
@@ -0,0 +1,23 @@
+-- Copyright 2025 Free Software Foundation, Inc.
+--
+-- 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/>.
+
+with Pack; use Pack;
+
+procedure Prog is
+ X : Direct := null;
+ Y : Second := new First;
+begin
+ null;
+end Prog;
base-commit: 24e9fdc6ef2c27fab8416737d4ed8129accdc551
--
2.51.1
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: [PATCH] Do not crash on recursive pointer types
2025-11-14 19:02 [PATCH] Do not crash on recursive pointer types Tom Tromey
@ 2025-11-15 21:27 ` Kevin Buettner
0 siblings, 0 replies; 2+ messages in thread
From: Kevin Buettner @ 2025-11-15 21:27 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Fri, 14 Nov 2025 12:02:03 -0700
Tom Tromey <tromey@adacore.com> wrote:
> In Ada, it's possible to create a recursive pointer type, or two
> mutually recursive pointer types. gdb will crash when reading the
> DWARF for these.
>
> These types aren't actually useful, and so are unlikely to appear in
> real code. Still, gdb shouldn't crash.
>
> This patch handles this case by noticing recursive pointer types and
> representing them as pointer-to-void.
A nice application of Robert W. Floyd's cycle detection algorithm!
Approved-by: Kevin Buettner <kevinb@redhat.com>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-11-15 21:27 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-11-14 19:02 [PATCH] Do not crash on recursive pointer types Tom Tromey
2025-11-15 21:27 ` Kevin Buettner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox