This is the mail archive of the gdb-prs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

c++/2132: gdb 6.4 SIGSEGVs on g++ 2.95.3 built binaries with particular class layouts


>Number:         2132
>Category:       c++
>Synopsis:       gdb 6.4 SIGSEGVs on g++ 2.95.3 built binaries with particular class layouts
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    unassigned
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Jun 02 17:58:01 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Simon Baldwin
>Release:        6.4, and earlier
>Organization:
>Environment:
Linux/i386, stabs debug from gcc 2.95 compiler.
>Description:
gdb 6.4 SIGSEGVs with g++ 2.95.3 built binaries that happen to have a particular layout of virtual functions in a given class.

The attached file contains example failing code and a suitable patch to gdb to fix the problem.
>How-To-Repeat:
See attached file.
>Fix:
See attached file.
>Release-Note:
>Audit-Trail:
>Unformatted:
----gnatsweb-attachment----
Content-Type: text/plain; name="stabsread.txt"
Content-Disposition: inline; filename="stabsread.txt"

> > 
> > Simon Baldwin <simon_baldwin@yahoo.com> writes:
> > > gdb 6.4 SIGSEGVs with g++ 2.95.3 built binaries that happen to have a
> > > particular layout of virtual functions in a given class.  For example:
> > >
> > >   $ cat vf.cc
> > >   class Foo {
> > >    public:
> > >     virtual ~Foo() {}
> > >     Foo() {}
> > >   };
> > >
> > >   int main() {
> > >     Foo f;
> > >   }
> > >
> > >   $ gcc-2.95.3-glibc-2.2.2 -x c++ -pedantic -g -o vf vf.cc
> > >
> > >   $ gdb-6.4/gdb/gdb /tmp/vf
> > >   GNU gdb 6.4
> > >   Copyright 2005 Free Software Foundation, Inc.
> > >   GDB is free software, covered by the GNU General Public License, and
> > you
> > > are
> > >   welcome to change it and/or distribute copies of it under certain
> > > conditions.
> > >   Type "show copying" to see the conditions.
> > >   There is absolutely no warranty for GDB.  Type "show warranty" for
> > details.
> > >   This GDB was configured as "i686-pc-linux-gnu"...Using host
> > libthread_db
> > > library "/lib/libthread_db.so.1".
> > >
> > >   (gdb) break Foo::Foo
> > >   Segmentation fault
> > >
> > > Running gdb within gdb reveals
> > >
> > >   Program received signal SIGSEGV, Segmentation fault.
> > >   gnuv2_is_destructor_name (name=0x0) at gnu-v2-abi.c:45
> > >   45        if ((name[0] == '_' && is_cplus_marker (name[1]) && name[2]
> > ==
> > > '_')
> > >
> > > The cause turns out to be an unset element in the field lists passed to
> > > add_matching_methods() in linespec.c.  The actual unset element occurs
> > > because of mismatch can occur between the sublist length and the value
> of
> > > 'length' at lines 2549 and later in stabsread.c.  Here, an array of
> > 'length'
> > > elements is allocated (and zeroed), but fewer elements are then copied
> in
> > by
> > > the loop at line 2554.
> > >
> > > The fix, while a long way from the problem symptom, is, I believe:
> > >
> > > *** /local/gdb/gdb-6.4/gdb/stabsread.c  2005-07-04 06:29:12.000000000
> > -0700
> > > --- ./stabsread.c       2006-05-05 12:22:02.000000000 -0700
> > > ***************
> > > *** 2492,2497 ****
> > > --- 2492,2498 ----
> > >                 {
> > >                   if (!is_destructor_name
> > (tmp_sublist->fn_field.physname))
> > >                     {
> > > +                     last_sublist = tmp_sublist;
> > >                       tmp_sublist = tmp_sublist->next;
> > >                       continue;
> > >                     }
> > >
> > > Is this a known problem?  If not, does the above look like a good
> > candidate
> > > patch?
> > 
> > Thanks for tracking this down!  If I'm understanding right, the
> > problem is that the 'if' at the top of the list doesn't update
> > last_sublist, so when it comes time to splice out a destructor that
> > follows a non-destructor, we don't properly update the preceding
> > node's 'next' pointer, and the list gets corrupted.  Is that right?
> 
> 
> Thanks for the reply.  You're understanding the explanation correctly.  If
> the destructor is not the first item on sublist, but rather the second or
> subsequent, last_sublist is (incorrectly) still NULL when loop does locate
> the the destructor in the list.  In this case, sublist itself is moved on,
> resulting in splicing out every list item from the head up to, and
> including,
> the destructor.
> 
> It all works, though, if the destructor happens to be first on sublist. 
> And
> it often is, it seems.  This would be why this problem hasn't been more
> evident.
> 
> 
> > Isn't there a further bug, though, in that when we do remove a
> > destructor from the list, we set last_sublist to point to the node we
> > just removed?  If the next node is a destructor, too, then we'll
> > update the wrong link again.  (Although, why a list would have more
> > than one destructor, I don't know.)
> 
> 
> This could indeed well be a further bug.  As you note, though, probably
> hard,
> if not impossible, to trigger.
> 
> 
> > How does the following look to you?
> > 
> > *** stabsread.c	17 Jan 2006 14:12:08 -0800	1.84
> > --- stabsread.c	05 May 2006 14:41:59 -0700	
> > ***************
> > *** 2492,2511 ****
> >   	      i = 0;
> >   	      while (tmp_sublist != NULL)
> >   		{
> > ! 		  if (!is_destructor_name (tmp_sublist->fn_field.physname))
> > ! 		    {
> > ! 		      tmp_sublist = tmp_sublist->next;
> > ! 		      continue;
> > ! 		    }
> > ! 		  
> > ! 		  destr_fnlist->fn_fieldlist.fn_fields[i++]
> > ! 		    = tmp_sublist->fn_field;
> > ! 		  if (last_sublist)
> > ! 		    last_sublist->next = tmp_sublist->next;
> > ! 		  else
> > ! 		    sublist = tmp_sublist->next;
> > ! 		  last_sublist = tmp_sublist;
> > ! 		  tmp_sublist = tmp_sublist->next;
> >   		}
> >   
> >   	      destr_fnlist->fn_fieldlist.length = has_destructor;
> > --- 2492,2510 ----
> >   	      i = 0;
> >   	      while (tmp_sublist != NULL)
> >   		{
> > ! 		  if (is_destructor_name (tmp_sublist->fn_field.physname))
> > !                     {
> > !                       destr_fnlist->fn_fieldlist.fn_fields[i++]
> > !                         = tmp_sublist->fn_field;
> > !                       if (last_sublist)
> > !                         last_sublist->next = tmp_sublist->next;
> > !                       else
> > !                         sublist = tmp_sublist->next;
> > !                     }
> > !                   else
> > !                     last_sublist = tmp_sublist;
> > ! 
> > !                   tmp_sublist = tmp_sublist->next;
> >   		}
> >   
> >   	      destr_fnlist->fn_fieldlist.length = has_destructor;
> > 
> 
> 
> This looks fine, I think, as a clearer expression of what was intended.
> 
> Thanks for taking the time to look this over.
> 
> --S
> 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]