GDB showing garbage for C++ member variables on 2 Linux distros, not on OS X/FreeBSD
This is mostly a repost from Stack Overflow, with some edits to bring it more up to date.
I ran in to a (in my eyes) very strange issue with gdb today, while trying to write a more C++-ish version of the reverse() method of my string class (all for learning, of course). Despite having a proper default constructor that initializes all member variables to 0, they start out as gibberish inside the member reverse() - according to gdb (everything except debugging actually works perfectly) - but not in a bare-bones program that just creates an empty string. Could this have something to do with the fact that reverse() is a member function that creates an instance of its own class? If not, why would it not happen in a bare-bones program? BTW, before I mention any code... I compile thusly: Code:
g++ -c -o tests.o tests.cpp -Wall -Werror -DDEBUG=0 -O0 -ggdb3 Code:
string::string() : buf(NULL), _length(0), _size(0) { Code:
Breakpoint 1, exscape::string::reverse (this=0x7fffffffd580) at string.cpp:368 Note that the supposed values of the variables all all very close the value of this. In the above run, _length = 0x7fffffffd580 = this. "GNU gdb 6.3.50-20050815 (Apple version gdb-1344)" on OS X Snow Leopard works perfectly, as does gdb 6.1.1 on FreeBSD/amd64, although I doubt that the GDB version is the problem. Here's sample output from the Mac: Code:
Breakpoint 1, exscape::string::reverse (this=0x7fff5fbff800) at string.cpp:368 |
Update: I did a clean Ubuntu Server 9.10 install just to test on another Linux system. Also amd64, same problem.
Code:
serenity@ubuntu:~/test$ gdb --version Code:
Breakpoint 1, exscape::string::reverse (this=0x7fffffffe050) at string.cpp:368 |
I believe that you need to explicitly call the constructor for the object in you method.
|
Quote:
Code:
/* Initializes a string to an empty state */ I stumbled upon something VERY strange though, that I haven't been able to wrap my head around yet... If I remove the "const string &in" constructor, IT WORKS. It is however, according to the cerr statement, NEVER CALLED. :confused: No matter how broken the code inside it may be, HOW can it possibly affect the program when it is not called?! Edit: Here's the calling code, should it matter: Code:
int main() { Edit: What the hell? Removing the const string& constructor in the "real class", i.e. the whole deal, did NOT work. I'm very confused right now... |
To explicitly call the default constructor I'd do:
Code:
string rev = string::string(); |
Quote:
Also, the copy constructor doesn't seem to be called, as the cerr statement in it is never executed, while it is for the other constructors. Code:
$ ./a.out Code:
$ ./a.out |
how about full code?
|
Quote:
Anyway, the full sources for the current commit are here: http://github.com/exscape/CPlusPlus/...9a15b1d/string I know very well of several things I could do better BTW (a bit embarassed about some parts of the code) - that's the second class I wrote, and my code quality is improving quite rapidly. :) |
actually it looks pretty clean (compared to mine).
one thing is why are you using calloc instead of new ? |
Quote:
|
compiled an ran on windows with mingw and it seems to be ok.
the only things i can think of at this point is a bug in the linux kernel or a bug in gcc for linux (btw what versions?): Code:
(gdb) next |
Thanks.
Yeah, it seems to be related to either the Linux kernel or something in the building toolchain (which I guess is more likely). The Ubuntu gcc/gdb versions are posted above, the ones I use on my main box are: Quote:
|
Heres what I used:
Code:
|
Quote:
Debugging the functions is impossible on my Linux boxes due to this. |
It looks like gdb is using the wrong address for rev. This gdb script show the problem:
Code:
break exscape::string::reverse Code:
~/src/CPlusPlus/string$ gdb '--eval-command=source show-rev.gdb' ./tests |
I think that what is going on is some optimisation from the compiler. I've played around with it and I think that what is happening is that the compiler realises that the rev object will be returned and so it is placing its location directly where it will be used in memory, in your calling function (in this case main). Because the memory is there it is in a location out of bounds for the local method and so the debugger gets confused.
I changed the reverse method slightly as follows and I could see rev build up as expected but this time temp was behaving odd. Code:
string string::reverse(void) const { |
Quote:
One thing is a bit odd, though: shouldn't (even?) these kinds of optimizations be disabled with -O0? :) Lots of thanks to everybody who has replied, even though I still don't really have a proper solution; that doesn't matter too much TBH, at least not for this class... If it happens in the future, it's worse, and I'm more interested in learning the cause and if applicable report the bug somewhere, than actually debug this method (which I already have a FreeBSD computer and an OS X computer perfectly capable of doing!). Edit: Yeah... If I allocate the string on the heap, I get this: Code:
exscape::string *s = new exscape::string("ABCDEF"); |
All times are GMT -5. The time now is 02:46 AM. |