LinuxQuestions.org
Go Job Hunting at the LQ Job Marketplace
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices



Reply
 
Search this Thread
Old 11-28-2009, 04:53 AM   #1
exscape
Member
 
Registered: Aug 2007
Location: Sweden
Distribution: OS X, Gentoo, FreeBSD
Posts: 82

Rep: Reputation: 15
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
g++ -c -o string.o string.cpp -Wall -Werror -DDEBUG=0 -O0 -ggdb3
g++ -o tests tests.o string.o -Wall -Werror -DDEBUG=0 -O0 -ggdb3
Code:

Code:
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.

Here's sample output from the Mac:
Code:
Breakpoint 1, exscape::string::reverse (this=0x7fff5fbff800) at string.cpp:368
368             string rev;
(gdb) n
378             rev.alloc(this->_length + 1);
(gdb) p rev
$1 = (exscape::string &) @0x7fff5fbff7c0: {
  buf = 0x0, 
  _length = 0, 
  _size = 0
}
Any advice on what might cause this?

Last edited by exscape; 11-28-2009 at 06:19 AM.
 
Old 11-28-2009, 05:59 AM   #2
exscape
Member
 
Registered: Aug 2007
Location: Sweden
Distribution: OS X, Gentoo, FreeBSD
Posts: 82

Original Poster
Rep: Reputation: 15
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
Code:
Breakpoint 1, exscape::string::reverse (this=0x7fffffffe050) at string.cpp:368
368			string rev;
(gdb) n
378			rev.alloc(this->_length + 1);
(gdb) p rev
$1 = {buf = 0x7ffff762e780 "\204*\255", <incomplete sequence \373>, _length = 140737488347088, _size = 140737488346688}
 
Old 11-28-2009, 09:50 AM   #3
graemef
Senior Member
 
Registered: Nov 2005
Location: Hanoi
Distribution: Fedora 13, Ubuntu 10.04
Posts: 2,379

Rep: Reputation: 148Reputation: 148
I believe that you need to explicitly call the constructor for the object in you method.
 
Old 11-28-2009, 10:12 AM   #4
exscape
Member
 
Registered: Aug 2007
Location: Sweden
Distribution: OS X, Gentoo, FreeBSD
Posts: 82

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by graemef View Post
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...

Last edited by exscape; 11-28-2009 at 10:22 AM.
 
Old 11-28-2009, 10:22 AM   #5
graemef
Senior Member
 
Registered: Nov 2005
Location: Hanoi
Distribution: Fedora 13, Ubuntu 10.04
Posts: 2,379

Rep: Reputation: 148Reputation: 148
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.
 
Old 11-28-2009, 10:38 AM   #6
exscape
Member
 
Registered: Aug 2007
Location: Sweden
Distribution: OS X, Gentoo, FreeBSD
Posts: 82

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by graemef View Post
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
 
Old 11-28-2009, 07:20 PM   #7
smeezekitty
Senior Member
 
Registered: Sep 2009
Location: Washington U.S.
Distribution: M$ Windows / Debian / Ubuntu / DSL / many others
Posts: 2,234

Rep: Reputation: 189Reputation: 189
how about full code?
 
Old 11-29-2009, 02:47 AM   #8
exscape
Member
 
Registered: Aug 2007
Location: Sweden
Distribution: OS X, Gentoo, FreeBSD
Posts: 82

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by smeezekitty View Post
how about full code?
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.
 
Old 11-29-2009, 12:03 PM   #9
smeezekitty
Senior Member
 
Registered: Sep 2009
Location: Washington U.S.
Distribution: M$ Windows / Debian / Ubuntu / DSL / many others
Posts: 2,234

Rep: Reputation: 189Reputation: 189
actually it looks pretty clean (compared to mine).
one thing is why are you using calloc instead of new ?
 
Old 11-29-2009, 12:04 PM   #10
exscape
Member
 
Registered: Aug 2007
Location: Sweden
Distribution: OS X, Gentoo, FreeBSD
Posts: 82

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by smeezekitty View Post
one thing is why are you using calloc instead of new ?
Because I need realloc.
 
Old 11-29-2009, 12:32 PM   #11
smeezekitty
Senior Member
 
Registered: Sep 2009
Location: Washington U.S.
Distribution: M$ Windows / Debian / Ubuntu / DSL / many others
Posts: 2,234

Rep: Reputation: 189Reputation: 189
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)
 
Old 11-29-2009, 12:35 PM   #12
exscape
Member
 
Registered: Aug 2007
Location: Sweden
Distribution: OS X, Gentoo, FreeBSD
Posts: 82

Original Poster
Rep: Reputation: 15
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/>.
 
Old 11-29-2009, 12:38 PM   #13
smeezekitty
Senior Member
 
Registered: Sep 2009
Location: Washington U.S.
Distribution: M$ Windows / Debian / Ubuntu / DSL / many others
Posts: 2,234

Rep: Reputation: 189Reputation: 189
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.
 
Old 11-29-2009, 12:50 PM   #14
exscape
Member
 
Registered: Aug 2007
Location: Sweden
Distribution: OS X, Gentoo, FreeBSD
Posts: 82

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by smeezekitty View Post
[/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.
 
Old 11-29-2009, 03:43 PM   #15
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian
Posts: 2,541

Rep: Reputation: 878Reputation: 878Reputation: 878Reputation: 878Reputation: 878Reputation: 878Reputation: 878
It looks like gdb is using the wrong address for rev. This gdb script show the problem:
Code:
break exscape::string::reverse
run
advance exscape::string::alloc
set $real_rev=this
finish
advance 379
printf "===============================\n"
printf "WHAT GDB THINKS IS REV:\n"
print &rev
print rev
printf "THE REAL REV:\n"
print $real_rev
print *$real_rev
You can run it like this:
Code:
~/src/CPlusPlus/string$ gdb '--eval-command=source show-rev.gdb' ./tests
...
===============================
WHAT GDB THINKS IS REV:
$1 = (exscape::string *) 0xbffff2a0
$2 = {buf = 0xbffff33c "0\005\b", _length = 3221222216, _size = 3221222772}
---Type <return> to continue, or q <return> to quit---
THE REAL REV:
$3 = (exscape::string * const) 0xbffff33c
$4 = {buf = 0x80530a8 "ABCDEF", _length = 0, _size = 7}
 
  


Reply

Tags
c++, debugging, gdb


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Garbage Collection in C : Local variables question duryodhan Programming 13 12-04-2006 08:16 AM
shared libraries, dlopen and static member variables? (C/C++) Thinking Programming 2 12-19-2005 01:55 AM
normal gdb and spec gdb for kgdb Igor007 Linux - Newbie 1 09-23-2005 02:41 PM
console font is just showing garbage plisken Linux - General 3 01-11-2005 01:51 PM
detecting out of bound gdb convenience variables Hano Programming 1 07-16-2004 04:01 PM


All times are GMT -5. The time now is 11:13 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration