Fedora Account System
Red Hat Associate
Red Hat Customer
Description of problem: gdb gets confused about class pointer offsets with C++ multiple inheritance and vtables; reports bogus data. Version-Release number of selected component (if applicable): gdb-7.0.1-26.fc12 How reproducible: Every time Steps to Reproduce: 1. Compile the attached test.cpp with |g++ -g test.cpp|. 2. Run |gdb ./a.out|. The following steps to reproduce are a transcript of a gdb session: (gdb) break test.cpp:28 Breakpoint 1 at 0x400728: file test.cpp, line 29. (gdb) run Starting program: /home/bzbarsky/a.out Breakpoint 1, main () at test.cpp:29 29 return 0; (gdb) p b $1 = (B *) 0x601050 (gdb) p (class C*)b $2 = (C *) 0x601030 (gdb) p (class A*)$2 $3 = (A *) 0x601030 (gdb) p (class B*)$2 $4 = (B *) 0x601040 Note that $4 does not equal $1. In particular, when downcasting from B* to C*, the offset gdb seems to use is 2x what it should be. This is very consistent (in my original situation in Mozilla code, the offset used was 176 instead of the correct 88). As a consequence of this, you get this behavior: (gdb) set print object on (gdb) p b $5 = (C *) 0x601040 (gdb) p/x b->mA $6 = 0x31 (gdb) p/x b->mB $7 = 0xaaaaaaaa Actual results: When downcasting to a base class to a derived class when the base class is not the first base class the derived class inherits from, the offset used is 2x the correct one. As a result, the wrong derived class pointer is obtained and incorrect member variable values are read. Expected results: In this case, the B* pointer should be offset from the C* pointer by 16 bytes. Additional info: If I take out either of the virtual functions in the testcase, things start working correctly in terms of the pointers, though if I take out the virtual function b() then gdb claims there is no mA member in |b| when set print object on.
Created attachment 388111 [details] Testcase
I could only reproduce the second part of this bug. On my x86 F12 box, with gdb-7.0.1-30 and gcc-c++-4.4.2-20, (A*)b == (B*)b == b. I was able to reproduce the b->mA bug. This is actually a bit of a strange gdb extension. Are you using the system g++? What version is the RPM? Here's a transcript of my debug session: Script started on Tue 02 Feb 2010 11:19:43 AM MST parfait. gdb -nx ./pr GNU gdb (GDB) Fedora (7.0.1-30.fc12) Copyright (C) 2009 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i686-redhat-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /tmp/pr...done. (gdb) b 28 Breakpoint 1 at 0x804859a: file rh560741.cc, line 28. (gdb) r Starting program: /tmp/pr Breakpoint 1, main () at rh560741.cc:28 28 return 0; Missing separate debuginfos, use: debuginfo-install glibc-2.11.1-1.i686 libgcc-4.4.2-20.fc12.i686 libstdc++-4.4.2-20.fc12.i686 (gdb) p b $1 = (B *) 0x804a010 (gdb) p (A*)b $2 = (A *) 0x804a010 (gdb) p (B*)b $3 = (B *) 0x804a010 (gdb) p (C*)b $4 = (C *) 0x804a000 (gdb) p *b $5 = {_vptr.B = 0x8048708, mB = -1145324613} (gdb) set print object on (gdb) p *b $6 = (C) {<A> = {_vptr.A = 0x80486f8, mA = -1431655766}, <B> = { _vptr.B = 0x8048708, mB = -1145324613}, <No data fields>} (gdb) p /x b->mA $7 = 0x19 (gdb) p /x b->B $8 = 0xaaaaaaaa
> Are you using the system g++? What version is the RPM? Details: ~% rpm -q gdb gdb-7.0.1-26.fc12.x86_64 ~% rpm -q gcc-c++ gcc-c++-4.4.2-20.fc12.x86_64 This is the system gcc. It looks like I forgot to mention in comment 0 that this is a 64bit system, which of course matters if looking at the exact values of the pointer offsets (though not if you look at whether casting |b| to C* and then back to B* recovers the original pointer). Looking at your debug session, it's pretty clearly showing the bug, if you're on a 32-bit system. On a 32-bit system, casting |b| to |C*| should result in a pointer that's pointing to 8 bytes less than |b|, whereas your debug session shows it pointing to 16 bytes less than |b|. In particular, casting your $4 to B* will almost certainly give 0x804a008 instead of the original |b|.
Oops, thanks for pointing that out. I am looking into it.
I checked in a fix upstream: http://sourceware.org/ml/gdb-cvs/2010-02/msg00017.html I am not sure when this will show up in a Fedora package; that is up to Jan.
Hmm. Does that fix work if the code is compiled with -fno-rtti (which is in fact my situation)? Note that in this case there is in fact no virtual inheritance, so looking at the destination type should presumably work ok, right?
I tried the test case with -fno-rtti and it worked fine. The gdb "RTTI" stuff actually works using knowledge of the ABI, it doesn't rely on having the RTTI data compiled in.
Ah, ok. Excellent. Will this bug get updated if that patch does make it downstream?
(In reply to comment #8) > Will this bug get updated if that patch does make it downstream? It looks to be present in Rawhide, forgot to close it: gdb-7.0.50.20100203-13.fc13 https://koji.fedoraproject.org/koji/buildinfo?buildID=154226
Jan, are there any plans to backport to FC12, by any chance? This is making gdb pretty difficult to use for any codebase where multiple inheritance from classes with virtual functions is used (Gecko in my case).... And this certainly used to work in older gdb versions.
OK (unaware why/if it regressed).
I'm surprised to hear it used to work, since AFAICT this area hasn't had much love in recent times. You may want to delay pushing it into F12 (if you decide to do that), because the follow-on bug you found is showing that the rot is deeper than I thought: http://sourceware.org/ml/gdb-patches/2010-02/msg00059.html
> I'm surprised to hear it used to work Well, more precisely it works in gdb 6.3.50-20050815 on Mac (which I realize is more or less a fork) and I _think_ it worked in the system gdb shipped with FC9. So I'm not claiming it's a particularly recent regression, by any means... Thank you again for looking into this!
I checked in the fix for the regression that Jan found. (That is, checked in upstream.)
Sorry but backporting these changes is IMO not acceptable for F-12 stable release, it would nullify the meaning on F-12 testing. Feel free to use even the binary .fc13 *.rpm packages from: https://koji.fedoraproject.org/koji/packageinfo?packageID=295 (the last fix is still not there, there will be a new .fc13 rebase these days)