.. | ||
exemplos | ||
README.org |
Curso prático de introdução ao GDB
5. Casos de uso
Objetivo
Demonstrar o uso do GDB para localizar e solucionar bugs comuns, como:
- Falha de segmentação;
- Variável não inicializada;
- Loop infinito;
- Índice de vetor inválido;
- Parâmetro incorreto na chamada de uma função;
- Registradores incorretos em uma chamada de sistema;
- Desalinhamento da pilha;
- Erro de empilhamento e desempilhamento de registros;
- Estouro de buffer;
- Estouro de pilha;
- Vazamento de memória.
Falha de segmentação
Acesso inválido à memória causado por um ponteiro não inicializado.
Código (segfault.c
):
#include <stdio.h>
int main() {
int *p = NULL;
*p = 42; // ERRO: tentativa de escrever em um ponteiro nulo
printf("%d\n", *p);
return 0;
}
Compilação:
:~$ gcc -g -o segfault segfault.c $ gdb ./segfault Reading symbols from ./segfault...
Processo de depuração
Verificar o que acontece ao executar:
(gdb) r Starting program: /home/blau/git/gdb-pratico/mods/05/exemplos/segfault [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Program received signal SIGSEGV, Segmentation fault. 0x000055555555514d in main () at segfault.c:5 5 *p = 42; // ERRO: tentativa de escrever em um ponteiro nulo
Matando o processo:
(gdb) k [Inferior 1 (process 1034793) killed]
Definindo main
como ponto de parada e executando:
(gdb) b main Breakpoint 5 at 0x555555555141: file segfault.c, line 4. (gdb) r Starting program: /home/blau/git/gdb-pratico/mods/05/exemplos/segfault [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Breakpoint 5, main () at segfault.c:4 4 int *p = NULL;
Listando variáveis locais antes e após a inicialização do ponteiro p
:
(gdb) i locals p = 0x7fffffffdf40 (gdb) n 5 *p = 42; // ERRO: tentativa de escrever em um ponteiro nulo (gdb) i locals p = 0x0
O endereço de memória no ponteiro é claramente nulo (0x0
)!
Variável não inicializada
Uso de uma variável antes da atribuição de um valor (seu valor é lixo de memória).
Código do exemplo (notinit.c
):
#include <stdio.h>
int main(void) {
int a; // PROBLEMA: Variável não inicializada!
printf("Digite um número: ");
scanf("%d", &a); // Se scanf falhar, o valor de a será lixo!
printf("Depois de %d vem %d\n", a, a + 1);
return 0;
}
Compilação e teste:
:~$ gcc -g -o notinit notinit.c :~$ ./notinit Digite um número: (teclar CTRL+D) Depois de 32765 vem 32766
Processo de depuração
Basta executar o programa passo a passo examinando o valor da variável a
:
:~$ gdb ./notinit Reading symbols from ./notinit... (gdb) b main Breakpoint 1 at 0x1151: file notinit.c, line 7. (gdb) r Starting program: /home/blau/git/gdb-pratico/mods/05/exemplos/notinit [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Breakpoint 1, main () at notinit.c:7 7 printf("Digite um número: "); (gdb) p a $1 = 32767 (gdb) n 8 scanf("%d", &a); // Se scanf falhar, o valor de a será lixo! (gdb) n Digite um número: 10 printf("Depois de %d vem %d\n", a, a + 1); (gdb) p a $2 = 32767 (gdb) n Depois de 32767 vem 32768 12 return 0; (gdb) c Continuing. [Inferior 1 (process 1039355) exited normally]
Com o erro na execução de scanf
(simulado com o atalho CTRL+D
), o valor
da variável não inicializada continuou sendo lixo de memória (32767).
Loop infinito
Uma condição de parada incorreta faz com que as repetições não tenham fim.
Código de exemplo (iloop.c
):
#include <stdio.h>
int main() {
int i = 0;
// A condição de parada nunca será atendida!
while (i < 100) {
printf("i = %d\n", i);
i *= 2; // Sempre zero!
}
return 0;
}
Compilação e teste:
:~$ gcc -g -o iloop iloop.c :~$ ./iloop i = 0 i = 0 i = 0 i = 0 i = 0 i = 0 i = 0 i = 0 ^C
Processo de depuração
$ gdb ./iloop Reading symbols from ./iloop... (gdb) b main Breakpoint 1 at 0x1141: file iloop.c, line 4. (gdb) r Starting program: /home/blau/git/gdb-pratico/mods/05/exemplos/iloop [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Breakpoint 1, main () at iloop.c:4 4 int i = 0; (gdb) n 7 while (i < 100) { (gdb) p i $1 = 0 (gdb) n 8 printf("i = %d\n", i); (gdb) n i = 0 9 i *= 2; // Sempre zero! (gdb) p i $2 = 0 (gdb) n 7 while (i < 100) { (gdb) p i $3 = 0
Fica claro que o valor de nunca foi alterado, porque 2 × 0 = 0
!