GDB reverse debugging
Let's start with a simple C++ program in the file gdb-test.cpp
:
#include <iostream> const unsigned int SIZE = 10; int main() { int b[SIZE]; // intitialize for(int i=0; i <= SIZE; i++) { b[i]=0; } std::cout << "done!" << std::endl; return 0; }
Let's comple and run it.
$ g++ -g gdb-test.cpp -o gdb-test $ ./gdb-test
??? It doesn't stop!
Let's load it into gdb
.
$ gdb ./gdb-test GNU gdb (GDB) 7.1-ubuntu Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> [...] Reading symbols from /home/larsr/gdb-test...done. (gdb)
Now run it:
(gdb) r Starting program: /home/larsr/gdb-test
Still dosn't stop! Stop it with ctrl-c:
^C Program received signal SIGINT, Interrupt. 0x08048704 in main () at gdb-test.cpp:11 11 for(int i=0; i <= SIZE; i++) { (gdb)
Let's look at the variable i.
(gdb) print i $1 = 4 (gdb)
Looks normal enough! But strange that it didn't get further than 4... Well, let's run some more, break, and look at i.
(gdb) continue Continuing. ^C Program received signal SIGINT, Interrupt. 0x080486fc in main () at gdb-test.cpp:11 11 for(int i=0; i <= SIZE; i++) { (gdb) print i $2 = 7 (gdb) c Continuing. ^C Program received signal SIGINT, Interrupt. 0x080486f8 in main () at gdb-test.cpp:11 11 for(int i=0; i <= SIZE; i++) { (gdb) print i $4 = 6 (gdb)
What? First i
was 7 and then it was 6
! How did that happen? Lets start to record, and run some more!
(gdb) record (gdb) c Continuing. ^C Program received signal SIGINT, Interrupt. main () at gdb-test.cpp:11 11 for(int i=0; i <= SIZE; i++) { (gdb) print i $6 = 2 (gdb)
Something has modified i
to become smaller! When did this happen? Let's watch i
and go backwards.
(gdb) reverse-continue Continuing. Hardware watchpoint 1: i Old value = 2 New value = 1 main () at gdb-test.cpp:11 11 for(int i=0; i <= SIZE; i++) {
This makes sense. We are walking backswards, and in that direction we had a value of 2 which turned into 1. Let's keep going backwards.
(gdb) reverse-continue Continuing. Hardware watchpoint 1: i Old value = 1 New value = 0 main () at gdb-test.cpp:11 11 for(int i=0; i <= SIZE; i++) { (gdb) reverse-continue Continuing. Hardware watchpoint 1: i Old value = 0 New value = 10 0x080486eb in main () at gdb-test.cpp:12 12 b[i]=0; (gdb)
Here we see that as we went backwards, we went from 0 to 10. That means that when we ran forward, i
went from 10 to 0, and it happened when we executed
b[i]=0;
Could it be that writing to b[10]
overwrites the memory of i
? Where are they located in memory?
(gdb) print &i $7 = (int *) 0xbffff7bc (gdb) print &b[i] $8 = (int *) 0xbffff7bc (gdb)
Yup, they are at the same address. Why? Doh! An array indexing error! b[10]
is not within the array bounds! The last element is b[9]
.
Line 11 should use <
instead of <=
and read
for(int i=0; i < SIZE; i++) {
Case closed.
An ugly observation is that programs like this bug out silently and "work" if you change the program to be initialized to 100 (or something bigger than SIZE).
Inga kommentarer:
Skicka en kommentar