A memory fault occurs when a program is trying to read from or write to memory that does not belong to that program. A standard example is reading/writing address 0 (ie. a NULL-pointer), this will always result in a memory fault. A debugger can catch a memory fault and is therefore a useful tool to quickly determine where in your program the memory fault occurs.
Suppose we have a very small program (bug.c
) with a (obvious) bug:
/* simple buggy program to demonstrate GDB */ #include <stdio.h> void printptr(int* iptr) { printf("%d\n", *iptr); } int main() { int a = 5; int* ptr = 0; printptr(&a); printptr(ptr); }After compiling and running, it will generate a memory fault:
bug 5 Memory fault - core dumpedHow to find the bug with a debugger? First, make sure the executable contains debug information. This is done by providing some special flag (
-g
)
to the compiler: gcc -g -o bug bug.cNext, run the debugger with the executable as argument:
(gdb)
is the prompt of the debugger; you have to type the commands
you want to give at the prompt.
Now tell the debugger to run the loaded program:
(gdb) run Starting program: /home/se/doc/debug/source/bug 5 Program received signal SIGSEGV, Segmentation fault. 0x106b4 in printptr (iptr=0x0) at bug.c:8 8 printf("%d\n", *iptr); (gdb)The debugger stops at the offending instruction, here
printf("%d\n", *iptr);
. It states in which function the statement
resides and with what arguments that function was called. It's immediately
clear what the problem is: iptr is a null-pointer. This can be verified by
telling the debugger to print the value of iptr:
(gdb) print iptr $1 = (int *) 0x0 (gdb)
When the offending statement is in some function that's deeply nested, it
can be useful to know the calling sequence from main to the that
function. This is done by giving the command backtrace
(abbreviated
to bt
):
(gdb) bt #0 0x106b4 in printptr (iptr=0x0) at bug.c:8 #1 0x106f4 in main () at bug.c:18 (gdb)