Segmentation fault (SIGSEGV, falha de segmentação) é um erro muito comum que acontece quando trabalhamos com ponteiros e alocação de memória. Por mais monstruosos que esse problema aparente, podemos analisá-lo e resolve-lo usando o GDB.
Verifique o tutorial de instalação do GDB em Instalação GDB
Nesse tutorial, vamos analisar e consertar um programa que apresenta o erro SIGSEGV.
Programa com SIGSEGV
O seguinte código com erro será usado nesse tutorial.
#include<stdio.h>
#include<stdlib.h>
typedef struct node{
int valor;
struct node *prox;
} Node;
void free_lista(Node *no) {
if (no != NULL) {
free_lista(no->prox);
no->prox = NULL;
free(no);
}
}
void remover(Node **lista, int valor) {
Node *tgt, *par;
tgt = *lista;
par = NULL;
while (tgt->valor != valor) {
par = tgt;
tgt = tgt->prox;
}
tgt->prox = NULL;
free(tgt);
tgt = NULL;
if (par != NULL) {
par->prox = tgt->prox;
} else {
*lista = tgt->prox;
}
}
void inserir(Node **lista, int valor) {
Node *new, *tgt;
new = malloc(sizeof(Node));
new->valor = valor;
new->prox = NULL;
if (*lista == NULL) {
*lista = new;
} else {
tgt = *lista;
while (tgt->prox != NULL)
tgt = tgt->prox;
tgt->prox = new;
}
}
int main (void) {
Node *lista, *tgt;
lista = NULL;
for (int i = 0; i < 10; i++)
inserir(&lista, i);
remover(&lista, 5);
tgt = lista;
while (tgt != NULL) {
printf("%d\n", tgt->valor);
tgt = tgt->prox;
}
free_lista(lista);
lista = NULL;
return 0;
}
Compile e execute o código.
user@desktop:~$ gcc segf.c -o segf -g
user@desktop:~$ ./segf
Segmentation fault (core dumped)
Como esperado, estamos caindo em um segmentation fault. Execute o programa no gdb.
user@desktop:~$ gdb ./segf
.
.
.
(gdb) run
Starting program: /tmp/segf
Program received signal SIGSEGV, Segmentation fault.
0x000055555555523d in remover (lista=0x7fffffffdd00, valor=5) at segf.c:32
32 par->prox = tgt->prox;
Ao inspecionar a variável tgt
, obtemos que a mesma é um ponteiro para a posição
0x0 (NULL). Logo, o acesso tgt->prox
é indevido e resultou no SIGSEGV.
(gdb) p tgt
$1 = (Node *) 0x0
Analisando o código fonte, é possível identificar que o free(tgt)
e tgt = NULL
são feitos antes da atribuição par->prox = tgt->prox
. Assim, para
consertar o problema, basta mover as linhas 27, 28 e 29 para depois do bloco do
if-else
.
Execute o programa e verifique a saída.
user@desktop:~$ ./segf
0
1
2
3
4
6
7
8
9