Estou escrevendo um programa C ++ multiplataforma para Windows e Unix. No lado da janela, o código será compilado e executado sem problemas. No lado do Unix, ele irá compilar, mas quando tento executá-lo, recebo uma falha de segmentação. Meu palpite inicial é que há um problema com os ponteiros.
Quais são as boas metodologias para encontrar e corrigir erros de falha de segmentação?
fonte
g
no contexto deCMake
?cmake -DCMAKE_BUILD_TYPE=Debug
.Às vezes, a falha em si não é a verdadeira causa do problema - talvez a memória tenha sido destruída em um ponto anterior, mas demorou um pouco para que a corrupção se manifestasse. Verifique o valgrind , que tem muitas verificações para problemas de ponteiro (incluindo verificação de limites de array). Ele vai te dizer onde está o problema começa , não apenas a linha onde a falha ocorre.
fonte
Antes que o problema surja, tente evitá-lo tanto quanto possível:
Use ferramentas apropriadas para depuração. No Unix:
Com o GCC, você também pode usar mudflapCom GCC, Clang e, desde outubro, experimentalmente MSVC, você pode usar o Address / Memory Sanitizer . Ele pode detectar alguns erros que o Valgrind não detecta e a perda de desempenho é menor. É usado compilando com o-fsanitize=address
sinalizador.Finalmente, recomendaria as coisas habituais. Quanto mais seu programa for legível, fácil de manter, claro e organizado, mais fácil será depurar.
fonte
No Unix, você pode usar
valgrind
para encontrar problemas. É grátis e poderoso. Se você preferir fazer você mesmo, pode sobrecarregar os operadoresnew
edelete
para definir uma configuração em que tenha 1 byte0xDEADBEEF
antes e depois de cada novo objeto. Em seguida, controle o que acontece em cada iteração. Isso pode falhar em capturar tudo (não há garantia de que você toque nesses bytes), mas funcionou para mim no passado em uma plataforma Windows.fonte
new
edelete
possa ser super útil, o uso-fsanitize=address
é uma opção melhor, já que o compilador irá compilar na detecção de tempo de execução para problemas e irá despejar a memória automaticamente na tela, o que torna a depuração mais fácil.new
edelete
, você pode embrulharmalloc
se estiver usandogcc
. Veja--wrap=symbol
. Vou fazer isso no código de lançamento para que possa obter alguns diagnósticos de tempo de execução.Sim, há um problema com os ponteiros. Muito provavelmente você está usando um que não foi inicializado corretamente, mas também é possível que esteja bagunçando o gerenciamento de memória com liberações duplas ou algo parecido.
Para evitar ponteiros não inicializados como variáveis locais, tente declará-los o mais tarde possível, de preferência (e isso nem sempre é possível) quando eles podem ser inicializados com um valor significativo. Convença-se de que eles terão um valor antes de serem usados, examinando o código. Se você tiver dificuldade com isso, inicialize-as a uma constante ponteiro nulo (geralmente escrita como
NULL
ou0
) e verifique-os.Para evitar ponteiros não inicializados como valores de membro, certifique-se de que eles sejam inicializados corretamente no construtor e manipulados corretamente nos construtores de cópia e operadores de atribuição. Não confie em uma
init
função para gerenciamento de memória, embora você possa fazer outra inicialização.Se sua classe não precisa de construtores de cópia ou operadores de atribuição, você pode declará-los como funções-membro privadas e nunca defini-los. Isso causará um erro do compilador se eles forem explícita ou implicitamente usados.
Use ponteiros inteligentes quando aplicável. A grande vantagem aqui é que, se você segui-los e usá-los consistentemente, pode evitar completamente a escrita
delete
e nada será excluído duas vezes.Use strings C ++ e classes de contêiner sempre que possível, em vez de strings e arrays no estilo C. Considere usar em
.at(i)
vez de[i]
, porque isso forçará a verificação dos limites. Veja se seu compilador ou biblioteca pode ser configurado para verificar os limites[i]
, pelo menos no modo de depuração. Falhas de segmentação podem ser causadas por saturações de buffer que gravam lixo sobre ponteiros perfeitamente bons.Fazer essas coisas reduzirá consideravelmente a probabilidade de falhas de segmentação e outros problemas de memória. Eles sem dúvida falharão em consertar tudo, e é por isso que você deve usar valgrind de vez em quando quando não tiver problemas, e valgrind e gdb quando tiver.
fonte
Não conheço nenhuma metodologia a ser usada para consertar coisas como essa. Eu não acho que seria possível chegar a um, pois o problema em questão é que o comportamento do seu programa é indefinido (não sei de nenhum caso em que SEGFAULT não tenha sido causado por algum tipo de UB) .
Existem todos os tipos de "metodologias" para evitar o problema antes que ele surja. Um importante é RAII.
Além disso, você só precisa lançar suas melhores energias psíquicas nisso.
fonte