Bug 25065 - GDB segfaults while running gdb.cp/subtypes.exp with -flto
Summary: GDB segfaults while running gdb.cp/subtypes.exp with -flto
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: symtab (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: ---
Assignee: Kevin Buettner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-10-05 20:44 UTC by Kevin Buettner
Modified: 2019-11-27 20:38 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
Patch which fixes this -flto bug (361 bytes, patch)
2019-10-05 20:44 UTC, Kevin Buettner
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Kevin Buettner 2019-10-05 20:44:23 UTC
Created attachment 12018 [details]
Patch which fixes this -flto bug

Using the installed gcc (gcc (GCC) 9.2.1 20190827 (Red Hat 9.2.1-1)) on Fedora 30, GDB dies with a SIGSEGV while testing gdb.cp/subtypes.exp when used with the -flto flag.

The command line to reproduce this is:

make check RUNTESTFLAGS="CFLAGS_FOR_TARGET='-flto' --target_board unix gdb.cp/subtypes.exp"

Here is the relevant part of the log file showing the segfault:

ptype main::Foo
type = struct Foo {
ERROR: GDB process no longer exists
GDB process exited with wait status 9481 exp11 0 0 CHILDKILLED SIGSEGV {segmentation violation}

I've investigated this problem and have a fix for it though I'm still working on a test case which doesn't require running the test with -flto.  I'm attaching my current patch.  I plan to submit this patch (or one that's similar) for upstream consideration once I have a test case.

Another reproducer for this bug is gdb.cp/local.exp:

make check RUNTESTFLAGS="CFLAGS_FOR_TARGET='-flto' --target_board unix gdb.cp/local.exp"

For this one, the relevant lines from the log file are as follows:

ptype l
type = class Local {
  public:
    int loc1;

ERROR: GDB process no longer exists
GDB process exited with wait status 9730 exp12 0 0 CHILDKILLED SIGSEGV {segmentation violation}

I'm fairly confident that these are the same bug. My patch fixes both of them.
Comment 1 Kevin Buettner 2019-10-14 00:29:20 UTC
I've posted a two part patch that fixes this problem and adds a test case (which doesn't depend on compiling w/ -flto).  See:

https://www.sourceware.org/ml/gdb-patches/2019-10/msg00327.html
Comment 2 Sourceware Commits 2019-11-27 20:06:08 UTC
The master branch has been updated by Kevin Buettner <kevinb@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=8d9a2568651d55eb518d3ac6c0dd0b4719da7f77

commit 8d9a2568651d55eb518d3ac6c0dd0b4719da7f77
Author: Kevin Buettner <kevinb@redhat.com>
Date:   Sat Oct 12 14:35:56 2019 -0700

    Fix BZ 25065 - Ensure that physnames are computed for inherited DIEs
    
    This is a fix for BZ 25065.
    
    GDB segfaults when running either gdb.cp/subtypes.exp or
    gdb.cp/local.exp in conjunction with using the -flto compiler/linker
    flag.
    
    A much simpler program, which was used to help create the test for
    this fix, is:
    
    -- doit.cc --
    int main()
    {
      class Foo {
      public:
        int doit ()
        {
          return 0;
        }
      };
    
      Foo foo;
    
      return foo.doit ();
    }
    -- end doit.cc --
    
    gcc -o doit -flto -g doit.cc
    gdb -q doit
    Reading symbols from doit...
    (gdb) ptype main::Foo
    type = class Foo {
    Segmentation fault (core dumped)
    
    The segfault occurs due to a NULL physname in
    c_type_print_base_struct_union in c-typeprint.c.  Specifically,
    calling is_constructor_name() eventually causes the SIGSEGV is this
    code in c-typeprint.c:
    
    	      const char *physname = TYPE_FN_FIELD_PHYSNAME (f, j);
    	      int is_full_physname_constructor =
    		TYPE_FN_FIELD_CONSTRUCTOR (f, j)
    		|| is_constructor_name (physname)
    		|| is_destructor_name (physname)
    		|| method_name[0] == '~';
    
    However, looking at compute_delayed_physnames(), we see that
    the TYPE_FN_FIELD_PHYSNAME field should never be NULL.  This
    field will be set to "" for NULL physnames:
    
          physname = dwarf2_physname (mi.name, mi.die, cu);
          TYPE_FN_FIELD_PHYSNAME (fn_flp->fn_fields, mi.index)
    	= physname ? physname : "";
    
    For this particular case, it turns out that compute_delayed_physnames
    wasn't being called, which left TYPE_FN_FIELD_PHYSNAME set to the NULL
    value that it started with when that data structure was allocated.
    
    The place to fix it, I think, is towards the end of
    inherit_abstract_dies().
    
    My first attempt at fix caused the origin CU's method_list (which is
    simply the list of methods whose physnames still need to be computed)
    to be added to the CU which is doing the inheriting.  One drawback
    with this approach is that compute_delayed_physnames is (eventually)
    called with a CU that's different than the CU in which the methods
    were found.  It's not clear whether this will cause problems or not.
    
    A safer approach, which is what I ultimately settled on, is to call
    compute_delayed_physnames() from inherit_abstract_dies().  One
    potential drawback is that all needed types might not be known at that
    point.  However, in my testing, I haven't seen a problem along these
    lines.
    
    gdb/ChangeLog:
    
    	* dwarf2read.c (inherit_abstract_dies): Ensure that delayed
    	physnames are computed for inherited DIEs.
    
    Change-Id: I6c6ffe96b301a9daab9f653956b89e3a33fa9445
Comment 3 Sourceware Commits 2019-11-27 20:06:13 UTC
The master branch has been updated by Kevin Buettner <kevinb@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=d22670f0780f4d296325d35049f0d57791ef6d73

commit d22670f0780f4d296325d35049f0d57791ef6d73
Author: Kevin Buettner <kevinb@redhat.com>
Date:   Sat Oct 12 23:12:29 2019 -0700

    Test case for BZ 25065
    
    Running a GDB with the fix for BZ 25065 should cause these new tests
    to all pass.
    
    When run against a GDB without the fix, there will be 2 unresolved
    testcases.  This is what I see in the gdb.sum file when I try it using
    a GDB without the fix:
    
    ERROR: GDB process no longer exists
    UNRESOLVED: gdb.dwarf2/imported-unit.exp: ptype main::Foo
    ERROR: Couldn't send ptype main::foo to GDB.
    UNRESOLVED: gdb.dwarf2/imported-unit.exp: ptype main::foo
    
    These are "unresolved" versus outright failures due to the fact that
    GDB dies (segfaults) during the running of the test.
    
    gdb/testsuite/ChangeLog:
    
    	* gdb.dwarf2/imported-unit.exp: New file.
    	* gdb.dwarf2/imported-unit.c: New file.
    
    Change-Id: I073fe69b81bd258951615f752df8e95b6e33a271
Comment 4 Kevin Buettner 2019-11-27 20:38:48 UTC
A fix, along with a test case, has been pushed to GDB's master branch.