GDB showing garbage for C++ member variables on 2 Linux distros, not on OS X/FreeBSD
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
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:
string::string() : buf(NULL), _length(0), _size(0) {
init();
}
/* This is redundant in this case (right?), but the function is used elsewhere,
and I added the above initialization list while debugging this. */
void string::init() {
this->buf = NULL;
this->_length = 0;
this->_size = 0;
}
string string::reverse(void) const {
string rev;
rev.alloc(this->_length + 1);
for (size_t i=0; i<this->_length; i++) {
...
Here's what I get from running the above through gdb 7.0 (on Linux), with "FEDCBA" as the input string:
Code:
Breakpoint 1, exscape::string::reverse (this=0x7fffffffd580) at string.cpp:368
368 string rev;
(gdb) next
378 rev.alloc(this->_length + 1); <<<< not yet executed when we print below!
(gdb) p rev
$1 = {buf = 0x7fffffffd560 "", _length = 140737488344448, _size = 140737488344128}
(gdb) n
380 for (size_t i=0; i<this->_length; i++) {
(gdb)
381 rev.buf[this->_length-i-1] = this->buf[i];
380 for (size_t i=0; i<this->_length; i++) {
(gdb) p rev
$2 = {buf = 0x7fffffffd560 "P\321`", _length = 140737488344448, _size = 140737488344128}
(gdb) n
381 rev.buf[this->_length-i-1] = this->buf[i];
(gdb)
380 for (size_t i=0; i<this->_length; i++) {
...
384 rev._length = this->_length;
(gdb)
386 }
(gdb) p rev
$3 = {buf = 0x7fffffffd560 "P\321`", _length = 140737488344448, _size = 140737488344128}
(gdb) next
main () at tests.cpp:72
(gdb) p r2 <<<< r2 is the name of the variable returned by reverse()
$4 = {buf = 0x60d150 "ABCDEF", _length = 6, _size = 7}
As you can see, the GDB output is just gibberish, but the method works just as expected. I also tried GDB 6.8, 6.6 and 6.3 on Linux, none of which worked.
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.
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
GNU gdb (GDB) 7.0-ubuntu
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 "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
serenity@ubuntu:~/test$ gcc --version
gcc (Ubuntu 4.4.1-4ubuntu8) 4.4.1
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
serenity@ubuntu:~/test$ uname -a
Linux ubuntu 2.6.31-14-server #48-Ubuntu SMP Fri Oct 16 15:07:34 UTC 2009 x86_64 GNU/Linux
I believe that you need to explicitly call the constructor for the object in you method.
Didn't help, unfortunately:
Code:
/* Initializes a string to an empty state */
void string::init(void) {
std::cerr << "In init() for string " << this << std::endl;
this->buf = NULL;
this->_length = 0;
this->_size = 0;
}
/* Copy constructor from const char * */
string::string(const char *in = NULL) : buf(NULL), _length(0), _size(0) {
std::cerr << "In const char* copy/default constructor for string " << this << std::endl;
this->init();
this->append(in);
}
// Copy constructor from another string instance
string::string(const string &in) : buf(NULL), _length(0), _size(0) {
std::cerr << "In const string & copy instructor" << std::endl;
this->init();
this->append(in.c_str());
}
string string::reverse(void) const {
string rev(0);
...
... still causes nonsense variables.
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.
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() {
exscape::string s = "ABCDEF";
std::cout << "Reversed: " << s.reverse() << std::endl;
I've cut the code down from 1151 lines in 3 files to 153 lines in 1 file to remove things that cannot affect this bug, and during the cutting down I noticed that the const string& constructor was the culprit, somehow...
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();
When you exit the method you will call the copy constructor to make a copy of your local object to the return object.
Didn't help.
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
Reversed: FEDCBA
With cerr statements in all the constructors and init, I get this from the same calling code:
Code:
$ ./a.out
In const char* copy constructor for string 0x7fff19b60840
In init() for string 0x7fff19b60840
In default constructor for string 0x7fff19b60860
In init() for string 0x7fff19b60860
Reversed: FEDCBA
The full version is >1100 lines. The cut-down version is probably useless since the workaround that fixes it doesn't fix the full version.
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.
Distribution: M$ Windows / Debian / Ubuntu / DSL / many others
Posts: 2,339
Rep:
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
375 for (size_t i=0; i<this->_length; i++) {
(gdb) prev
Undefined command: "prev". Try "help".
(gdb) p rev
$3 = (string *) 0x22fe00
(gdb) p rev
$4 = (string *) 0x22fe00
(gdb) p *rev
$5 = {buf = 0x8d2bf0 "", _length = 0, _size = 7}
(gdb) next
376 rev.buf[this->_length-i-1] = this->buf[i];
(gdb) p *rev
$6 = {buf = 0x8d2bf0 "", _length = 0, _size = 7}
(gdb) next
375 for (size_t i=0; i<this->_length; i++) {
(gdb) p *rev
$7 = {buf = 0x8d2bf0 "", _length = 0, _size = 7}
(gdb) next
376 rev.buf[this->_length-i-1] = this->buf[i];
(gdb) next
375 for (size_t i=0; i<this->_length; i++) {
(gdb) p *rev
$8 = {buf = 0x8d2bf0 "", _length = 0, _size = 7}
(gdb)
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:
$ gcc --version
gcc (Gentoo 4.3.4 p1.0, pie-10.1.5) 4.3.4
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gdb --version
warning: Can not parse XML syscalls information; XML support was disabled at compile time.
GNU gdb (Gentoo 7.0 p1) 7.0
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 "x86_64-pc-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.gentoo.org/>.
Distribution: M$ Windows / Debian / Ubuntu / DSL / many others
Posts: 2,339
Rep:
Heres what I used:
Code:
C:\MinGW\bin>gcc --version
gcc (GCC) 3.4.5 (mingw-vista special r3)
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
C:\MinGW\bin>gdb --version
GNU gdb 5.2.1
Copyright 2002 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-mingw32".
C:\MinGW\bin>
Also what is your expected output? i am not trying to be a pain in your behind, i am just trying to track down the problem.
[/code]
Also what is your expected output? i am not trying to be a pain in your behind, i am just trying to track down the problem.
The program itself runs as it should, it's the GDB output in "print rev" that is way off. It should show buf=0x0, _length=0 and _size=0 since they have just been initialized, and no code has run since then.
Debugging the functions is impossible on my Linux boxes due to this.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.