Menu
Coddy logo textTech

O que é uma falha de segmentação (segmentation fault)?

Uma falha de segmentação (segmentation fault, ou segfault) é um travamento que acontece quando um programa tenta ler ou escrever em uma memória que não tem permissão para acessar, como o endereço 0 por meio de um ponteiro nulo. O sistema operacional encerra o programa com o sinal SIGSEGV.

Por Kevin Spektor, Cofundador e CTO

Atualizado em 24 de setembro de 2026

Um programa C imprime a primeira linha e depois para com uma mensagem que ninguém escreveu:

#include <stdio.h>

int main(void) {
    int *score = NULL;

    printf("About to read the score\n");
    printf("Score: %d\n", *score);
    return 0;
}
About to read the score
bash: line 1: 64030 Segmentation fault: 11  ./seg

Essa saída é do bash no macOS, onde 64030 é o ID do processo e 11 é o número do sinal. No Linux o mesmo travamento costuma aparecer como Segmentation fault (core dumped), ou, com o sistema em português, "Falha de segmentação (imagem do núcleo gravada)". De qualquer forma, o programa nunca imprimiu a nota. score guarda o endereço 0, e *score pede ao processador para ler a memória nesse endereço, o que nenhum programa tem permissão de fazer.

Como uma falha de segmentação acontece

Todo programa executa no seu próprio espaço de endereçamento virtual, uma faixa enorme de endereços que o sistema operacional preenche aos poucos. Ele mapeia o código do programa, as variáveis globais, a pilha (stack) e o heap nessa faixa, em blocos chamados páginas (4 KB na maioria dos sistemas Linux x86, 16 KB nos Macs com Apple silicon). A maioria dos endereços fica sem mapeamento, e o endereço 0 está sempre entre eles, para que bugs de ponteiro nulo sejam detectados.

  1. O programa executa uma instrução que lê ou escreve em um endereço. Aqui é a leitura de *score, endereço 0.
  2. A unidade de gerenciamento de memória do processador procura o endereço na tabela de páginas. A página não está mapeada, ou o programa está tentando escrever em uma página somente leitura.
  3. O processador interrompe a instrução e passa o controle ao kernel com uma falha de página (page fault).
  4. O kernel verifica se o acesso poderia ser legítimo, por exemplo uma pilha que precisa crescer. Não é, então o kernel envia ao processo o sinal 11, SIGSEGV.
  5. A ação padrão para SIGSEGV é encerrar o processo e, quando o sistema permite, salvar um core dump. O shell então imprime a mensagem e define o status de saída como 139, que é 128 mais o número do sinal.

Então uma falha de segmentação não é informada pelo compilador, e não é uma exceção lançada pela linguagem. É o hardware e o kernel protegendo a memória, o que a torna um erro de tempo de execução do tipo mais abrupto. O Windows trata o mesmo evento como uma violação de acesso, código de exceção 0xC0000005.

Causas comuns de falhas de segmentação

C e C++ deixam um programa calcular qualquer endereço e usá-lo, então as causas se resumem a usar um endereço que não é válido.

  • Desreferenciar um ponteiro nulo. int *p = NULL; *p = 5; Uma função que retorna NULL quando falha, como malloc ou fopen, leva a isso quando o resultado não é verificado.
  • Um índice muito além do fim de um array. O C não verifica limites, então arr[1000000] é simplesmente um endereço um milhão de elementos adiante.
  • Usar memória depois do free. O ponteiro ainda guarda o endereço antigo, mas a memória não pertence mais a você.
  • Um ponteiro não inicializado. int *p; *p = 5; escreve por meio de qualquer valor lixo que p estiver guardando.
  • Estouro de pilha (stack overflow). Uma função recursiva sem caso de parada continua adicionando quadros à pilha até passar do fim dela. O exemplo abaixo travou no macOS com Segmentation fault: 11 e status de saída 139.
  • Escrever em uma string literal. char *name = "coddy"; name[0] = 'C'; tenta mudar memória somente leitura. No Linux isso é um segfault. No macOS o mesmo programa parou com Bus error: 10, um sinal parecido.
#include <stdio.h>

int depth(int n) {
    return depth(n + 1) + 1;   /* never stops calling itself */
}

int main(void) {
    printf("%d\n", depth(0));
    return 0;
}

Um erro pequeno muitas vezes nem trava, o que o torna mais perigoso. Este loop lê um elemento além do fim de um array de três elementos:

#include <stdio.h>

int main(void) {
    int scores[3] = {72, 88, 95};
    int total = 0;

    for (int i = 0; i <= 3; i++) {   /* <= reads scores[3] */
        total += scores[i];
    }
    printf("Total: %d\n", total);
    return 0;
}

Compilado com o Clang em um Mac, ele imprimiu Total: 256. O total correto é 255. scores[3] eram os 4 bytes seguintes da pilha, que pertenciam ao programa, então nenhuma falha ocorreu e o valor lixo foi somado em silêncio. O sistema operacional só interrompe acessos a memória que não pertence ao programa de jeito nenhum.

A correção para os dois erros é o mesmo hábito: saiba quantos elementos existem e verifique um ponteiro antes de segui-lo.

Best: 95
No scores, nothing to read

O que significa "core dumped"

Um core dump é um arquivo que guarda uma cópia da memória do programa no momento em que ele travou. Um depurador pode abri-lo depois e mostrar exatamente onde o programa estava e o que as variáveis guardavam: gdb ./app core. Em muitas distribuições Linux, o systemd-coredump coleta esses arquivos, e coredumpctl list os mostra. Quando os core dumps estão desativados, por exemplo com ulimit -c 0, a mensagem é só Segmentation fault, sem as palavras entre parênteses.

Como encontrar a linha que travou

A linha em que o programa trava muitas vezes não é a linha com o bug. Um ponteiro pode se tornar inválido em uma função e ser usado em outra muito depois. Estas ferramentas mostram as duas.

Um depurador. Compile com informações de depuração e execute o programa dentro do depurador. Quando ele parar, bt (backtrace) imprime a cadeia de chamadas de função com nomes de arquivo e números de linha. No Linux o depurador costuma ser o gdb; no macOS é o lldb, onde bt funciona do mesmo jeito.

gcc -g app.c -o app
gdb ./app
(gdb) run
(gdb) bt

AddressSanitizer. Compile com -fsanitize=address (GCC e Clang suportam) e execute o programa normalmente. Em vez de um segfault seco, ele imprime um relatório que nomeia o tipo de erro, como heap-use-after-free ou stack-buffer-overflow, com a linha que fez o acesso e a linha que alocou a memória. Ele também detecta a leitura silenciosa de um elemento além do fim mostrada acima, que nunca trava sozinha.

Valgrind. No Linux, valgrind ./app executa um programa sem modificações e informa toda leitura ou escrita inválida, como Invalid read of size 4.

Falhas de segmentação em outras linguagens

Python, Java e JavaScript verificam cada índice e cada referência antes de usá-los, então os mesmos erros viram exceções com mensagens claras: IndexError ou AttributeError em Python, ArrayIndexOutOfBoundsException ou NullPointerException em Java, TypeError em JavaScript. Essas podem ser capturadas com tratamento de exceções. Um segfault não pode ser tratado assim: é um sinal, e um bloco catch do C++ não o vê.

Programas Python ainda podem ter segfault quando o código C por baixo deles falha. Esta linha pede ao ctypes para ler o endereço 0:

import ctypes
ctypes.string_at(0)

Executado com python3 -X faulthandler, o Python 3.12 imprimiu Fatal Python error: Segmentation fault, seguido das linhas Python que estavam executando. O mesmo travamento acontece quando uma extensão em C ou uma biblioteca nativa tem um bug de memória. O Rust segue outro caminho: o compilador rejeita, antes de o programa ser gerado, a maior parte do código que poderia acessar memória inválida.

Próximos passos

O guia de C sobre falhas de segmentação percorre cada causa com um programa mínimo e a sua correção. Para evitar os erros desde o início, leia sobre ponteiros, ponteiros nulos e a pilha e o heap, e depois pratique no curso de C. Para ver como os erros são informados em linguagens que verificam a memória por você, veja a página de erro de tempo de execução.

Perguntas frequentes

Como corrigir uma falha de segmentação?
Primeiro encontre a linha: compile com -g e execute o programa dentro do gdb ou do lldb, depois digite bt após o travamento, ou compile com -fsanitize=address para um relatório detalhado. Então corrija o ponteiro ou o índice que essa linha usa: verifique se os ponteiros são NULL, mantenha os índices de array abaixo do tamanho, pare de usar a memória depois do free e garanta que a recursão termine.
Uma falha de segmentação é um vazamento de memória?
Não, são problemas opostos. Um vazamento de memória é memória que o programa alocou e nunca liberou, então ele continua executando enquanto usa cada vez mais memória. Uma falha de segmentação é um acesso a uma memória que não pertence ao programa, e ele é encerrado na hora. Erros com free, como usar um ponteiro depois de liberá-lo, podem causar segfaults, enquanto esquecer o free causa vazamentos.
Por que se chama falha de segmentação?
O nome vem da segmentação de memória, um projeto mais antigo em que a memória de um programa era dividida em segmentos com limites fixos, e tocar em um endereço fora do seu segmento era uma falha. Os sistemas modernos gerenciam a memória em páginas, mas o nome, e o nome do sinal SIGSEGV, ficaram. O Windows chama o mesmo evento de violação de acesso (access violation).
Um programa Python pode ter segmentation fault?
Código Python comum não causa isso, porque o Python verifica cada índice e cada referência e lança uma exceção no lugar. Um programa Python ainda pode ter um segfault dentro de código C: um módulo de extensão em C, uma biblioteca como um framework de machine learning, ou ctypes. Executar python -X faulthandler script.py imprime as linhas Python que estavam executando quando ele travou.
O que significa o código de saída 139?
O código de saída 139 significa que o processo foi encerrado pelo sinal 11, que é o SIGSEGV, uma falha de segmentação. Os shells informam uma morte por sinal como 128 mais o número do sinal, e 128 + 11 = 139. No Docker e no Kubernetes, um contêiner que sai com 139 teve um segfault no processo principal.
Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR