Suppose we've implemented a very simple linked class:
#include <iostream.h>
class node
{
public:
node(int i, node* n) { item_ = i; next_ = n; }
int item() { return item_; }
node* next() { return next_; }
protected:
int item_;
node* next_;
};
int main()
{
int i;
node* current = 0;
// build list
node* head = new node(1, NULL);
head = new node(2, head); // prepend new node
head = new node(3, head); // prepend new node
// print list
current = head;
for (i = 0; i <= 3; i++) // since list-size is now 3
{
cout << "item " << i << " is " << current -> item() << endl;
current = current -> next();
}
// destroy list
current = head;
for (i = 0; i <= 3; i++)
{
current = head -> next();
delete head;
head = current;
}
return 0;
}
It looks quite simple, but it still contains a bug:
list item 0 is 3 item 1 is 2 item 2 is 1 Memory faultFirst, we let GDB pinpoint the exact location of the memory fault:
GDB is free software and you are welcome to 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.
GDB 4.13 (sparc-sun-solaris2.3),
Copyright 1994 Free Software Foundation, Inc...
gdb list
(gdb) run
Starting program: /home/se/doc/debug/source/list
item 0 is 3
item 1 is 2
item 2 is 1
Program received signal SIGSEGV, Segmentation fault.
node::item (this=0x0) at list.cc:9
9 int item() { return item_; }
(gdb)
If the information provided by GDB is examined closely, it appears that the
this-pointer is 0! This means a member function is called for a
non-existing object and this will indeed cause a memory fault. But how can
this happen? Use the command bt to show the calling sequence that
resulted in the memory fault:
(gdb) bt
#0 node::item (this=0x0) at list.cc:9
#1 0x800896e in main () at list.cc:32
(gdb) list list.cc:32
27
28 // print list
29 current = head;
30 for (i = 0; i <= 3; i++) // since list-size is now 3
31 {
32 cout << "item " << i << " is " << current -> item() << endl;
33 current = current -> next();
34 }
35
36 // destroy list
(gdb)
It appears something goes wrong while printing all values. Since
current is always pointing to the current object, it follows that
current is at some point set to 0. But current can only be 0
at the end of the list (when next_ equals 0). Let's see what happens
when the last item has been printed:
(gdb) br list.cc:32 Breakpoint 1 at 0x8008940: file list.cc, line 32. (gdb) run The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/se/doc/debug/source/list Breakpoint 1, main () at list.cc:32 32 cout << "item " << i << " is " << current -> item() << endl; (gdb) cont Continuing. item 0 is 3 Breakpoint 1, main () at list.cc:32 32 cout << "item " << i << " is " << current -> item() << endl; (gdb) cont Continuing. item 1 is 2 Breakpoint 1, main () at list.cc:32 32 cout << "item " << i << " is " << current -> item() << endl; (gdb)So far, so good. This is the last item to be printed (since there are only 3 list-nodes). We now use tracing to see what happens next:
(gdb) n item 2 is 1 33 current = current -> next(); (gdb) n 34 } (gdb) print current $1 = (node *) 0x0 (gdb)As expected,
current is now 0. But what happens now?
(gdb) n 32 cout << "item " << i << " is " << current -> item() << endl; (gdb)It appears the loop is not finished yet! How can that be?
(gdb) print i $2 = 3 (gdb)After some thinking, the problem is clear: the loop is executed four times instead of three times. The for-loop should be
for (i = 0; i < 3; i++) { ... } and then it will work (the second
loop should of course be changed also).