This is the mail archive of the
gdb-prs@sourceware.org
mailing list for the GDB project.
c++/2132: gdb 6.4 SIGSEGVs on g++ 2.95.3 built binaries with particular class layouts
- From: simon_baldwin at yahoo dot com
- To: gdb-gnats at sources dot redhat dot com
- Date: 2 Jun 2006 17:54:43 -0000
- Subject: c++/2132: gdb 6.4 SIGSEGVs on g++ 2.95.3 built binaries with particular class layouts
- Reply-to: simon_baldwin at yahoo dot com
>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
>