Como se determina onde está o erro no código que causa uma falha de segmentação ?
Meu compilador ( gcc
) pode mostrar a localização da falha no programa?
c++
c
debugging
segmentation-fault
Trilarion
fonte
fonte
Respostas:
O GCC não pode fazer isso, mas o GDB (um depurador ) com certeza pode. Compile seu programa usando o
-g
switch, desta forma:Então use gdb:
Aqui está um bom tutorial para você começar a usar o GDB.
Onde o segfault ocorre geralmente é apenas uma pista de onde "o erro que causa" está no código. O local fornecido não é necessariamente onde o problema reside.
fonte
bt
como uma abreviação debacktrace
.Além disso, você pode
valgrind
tentar: se você instalarvalgrind
e executarEm seguida, ele executará seu programa e exibirá rastreamentos de pilha para quaisquer segfaults, além de leituras ou gravações inválidas de memória e vazamentos de memória. É realmente bastante útil.
fonte
--leak-check=full
não ajudará a depurar segfaults. É útil apenas para depurar vazamentos de memória.Você também pode usar um dump principal e examiná-lo com gdb. Para obter informações úteis, você também precisa compilar com o
-g
sinalizador.Sempre que você receber a mensagem:
um arquivo principal é gravado em seu diretório atual. E você pode examiná-lo com o comando
O arquivo contém o estado da memória quando o programa travou. Um dump principal pode ser útil durante a implantação do seu software.
Verifique se o seu sistema não define o tamanho do arquivo de despejo principal como zero. Você pode configurá-lo para ilimitado com:
ulimit -c unlimited
Cuidado embora! esse core dumps pode se tornar enorme.
fonte
Existem várias ferramentas disponíveis que ajudam a depurar falhas de segmentação e eu gostaria de adicionar minha ferramenta favorita à lista: Desinfetantes de endereços (geralmente abreviado como ASAN) .
Os compiladores modernos vêm com o prático
-fsanitize=address
sinalizador , adicionando algum tempo de compilação e sobrecarga de tempo de execução, o que faz mais verificação de erros.De acordo com a documentação, essas verificações incluem a captura de falhas de segmentação por padrão. A vantagem aqui é que você obtém um rastreamento de pilha semelhante à saída do gdb, mas sem executar o programa dentro de um depurador. Um exemplo:
A saída é um pouco mais complicada do que o que o gdb produziria, mas existem vantagens:
Não há necessidade de reproduzir o problema para receber um rastreamento de pilha. Basta ativar a flag durante o desenvolvimento.
Os ASANs capturam muito mais do que apenas falhas de segmentação. Muitos acessos fora dos limites serão capturados, mesmo que essa área de memória esteja acessível ao processo.
¹ Isso é Clang 3.1+ e GCC 4.8+ .
fonte
A resposta de Lucas sobre lixões centrais é boa. No meu .cshrc eu tenho:
para exibir o backtrace digitando 'core'. E o carimbo de data, para garantir que eu estou olhando para o arquivo certo :(.
Adicionado : se houver um bug de corrupção de pilha , o backtrace aplicado ao dump principal geralmente será lixo. Nesse caso, a execução do programa no gdb pode fornecer melhores resultados, conforme a resposta aceita (assumindo que a falha é facilmente reproduzível). E também tenha cuidado com vários processos despejando núcleo simultaneamente; alguns SOs adicionam o PID ao nome do arquivo principal.
fonte
ulimit -c unlimited
de ativar os core dumps em primeiro lugar.Todas as respostas acima estão corretas e recomendadas; esta resposta é planejada apenas como último recurso, se nenhuma das abordagens mencionadas puder ser usada.
Se tudo mais falhar, você sempre pode recompilar seu programa com várias instruções temporárias de depuração-impressão (por exemplo,
fprintf(stderr, "CHECKPOINT REACHED @ %s:%i\n", __FILE__, __LINE__);
) espalhadas pelo que você acredita serem as partes relevantes do seu código. Em seguida, execute o programa e observe qual foi a última impressão de depuração impressa pouco antes da falha - você sabe que seu programa chegou tão longe, então a falha deve ter acontecido após esse ponto. Adicione ou remova debug-prints, recompile e execute o teste novamente, até reduzi-lo a uma única linha de código. Nesse ponto, você pode corrigir o erro e remover todas as impressões de depuração temporárias.É bastante entediante, mas tem a vantagem de trabalhar em qualquer lugar - as únicas vezes que não podem ser, se você não tiver acesso ao stdout ou stderr por algum motivo, ou se o bug que você está tentando corrigir for uma corrida -condição cujo comportamento muda quando o tempo do programa muda (uma vez que as impressões de depuração desaceleram o programa e alteram o tempo)
fonte