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:
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:
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):
(Sorry for the horizontal scroll, but it doesn't matter since you can see all you need anyhow.)
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() of course
$4 = {buf = 0x60d150 "ABCDEF", _length = 6, _size = 7}
Why do the member variables appear to end up with gibberish values in gdb? (The gibberish values are always very close this
, by the way! In this running, this
== 0x7fffffffd580 == 140737488344448, the same value as _length
). The function works perfectly, valgrind never complains, and all is well... until I try to rewrite the method and can't debug it properly, that is.
Any advice?
Update: A sample program that calls the function:
#include <iostream>
#include "string.hpp"
int main() {
exscape::string s("Hello, world!");
exscape::string s2; // Use the default constructor
s2 = s.reverse();
std::cout << "Reversed: " << s2 << std::endl;
return 0;
}
(gdb) break exscape::string::reverse
Breakpoint 1 at 0x402ed6: file string.cpp, line 368.
(gdb) run
Starting program: /home/serenity/programming/cpp/string/a.out
Breakpoint 1, exscape::string::reverse (this=0x7fffffffdc80) at string.cpp:368
368 string rev;
(gdb) n
378 rev.alloc(this->_length + 1);
(gdb) p rev
$1 = {buf = 0x7fffffffdca0 "", _length = 140737488346240, _size = 140737488346208}
(gdb) finish
Run till exit from #0 exscape::string::reverse (this=0x7fffffffdc80) at string.cpp:378
0x000000000040163f in main () at bare.cpp:6
6 s2 = s.reverse();
Value returned is $2 = {buf = 0x607030 "!dlrow ,olleH", _length = 13, _size = 14}
(gdb) n
7 std::cout << "Reversed: " << s2 << std::endl;
(gdb) n
Reversed: !dlrow ,olleH
Update:
I copied the code to my Mac, and tried debugging it there - worked like a charm:
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
}
That version of gdb is quite ancient, though - "GNU gdb 6.3.50-20050815 (Apple version gdb-1344)".
I tried downgrading the Linux gdb to 6.8 and 6.6 to no avail. -- I actually tried 6.3 too, doesn't work either (and on a totally unrelated note, it appears the tab completion has gradually been getting better over the years :-).