Don't re-process a DIE in read_lexical_block_scope
authorTom Tromey <tromey@adacore.com>
Fri, 8 May 2020 20:26:11 +0000 (14:26 -0600)
committerTom Tromey <tromey@adacore.com>
Fri, 8 May 2020 20:26:11 +0000 (14:26 -0600)
A customer reported a crash in the DWARF reader.

Investigation showed that the crash occurred in an unusual scenario: a
function was lexically scoped within some other function -- but the
inner function inlined the outer function and referred to its DIE via
DW_AT_abstract_origin.  With the executable in question,
inherit_abstract_dies could eventually call read_lexical_block_scope,
which in turn could recurse into process_die, to process a DIE that
was already being read, triggering an assert.

This came up once before; see:

https://www.sourceware.org/ml/gdb-patches/2014-02/msg00652.html

However, in this case, I don't have an easy way to reproduce.  So,
there is no test case.

I did experiment with the failing executable.  This patch fixes the
bug and doesn't seem to cause other issues.  For example, I can still
set breakpoints on the relevant functions.

gdb/ChangeLog
2020-05-08  Tom Tromey  <tromey@adacore.com>

* dwarf2/read.c (read_lexical_block_scope): Don't process a DIE
already being processed.

gdb/ChangeLog
gdb/dwarf2/read.c

index 59125fd6ded6a9d7e7227b72ee5850125379750a..07bc950502032aae2ba5780d5f93e8846a3e3d48 100644 (file)
@@ -1,3 +1,8 @@
+2020-05-08  Tom Tromey  <tromey@adacore.com>
+
+       * dwarf2/read.c (read_lexical_block_scope): Don't process a DIE
+       already being processed.
+
 2020-05-08  Tom Tromey  <tom@tromey.com>
 
        * printcmd.c (struct display) <next>: Remove.
index 60b56b8ea81be49613c47e8205987b0cf730f6a1..439b889144b96bf9fbac71802021e155a4e2d413 100644 (file)
@@ -13102,7 +13102,16 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu)
       for (child_die = die->child;
           child_die != NULL && child_die->tag;
           child_die = child_die->sibling)
-       process_die (child_die, cu);
+       {
+         /* We might already be processing this DIE.  This can happen
+            in an unusual circumstance -- where a subroutine A
+            appears lexically in another subroutine B, but A actually
+            inlines B.  The recursion is broken here, rather than in
+            inherit_abstract_dies, because it seems better to simply
+            drop concrete children here.  */
+         if (!child_die->in_process)
+           process_die (child_die, cu);
+       }
       return;
     case PC_BOUNDS_INVALID:
       return;