Don't re-process a DIE in read_lexical_block_scope

Message ID 20200424145136.5348-1-tromey@adacore.com
State New
Headers show
Series
  • Don't re-process a DIE in read_lexical_block_scope
Related show

Commit Message

Tom Tromey April 24, 2020, 2:51 p.m.
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-04-24  Tom Tromey  <tromey@adacore.com>

	* dwarf2/read.c (read_lexical_block_scope): Don't process a DIE
	already being processed.
---
 gdb/ChangeLog     |  5 +++++
 gdb/dwarf2/read.c | 11 ++++++++++-
 2 files changed, 15 insertions(+), 1 deletion(-)

-- 
2.21.1

Comments

Tom Tromey May 8, 2020, 8:25 p.m. | #1
>>>>> "Tom" == Tom Tromey <tromey@adacore.com> writes:


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

I'm checking this in.

Tom

Patch

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index e89ed743543..9e4427e3cd7 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -13058,7 +13058,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;