O Application Verifier combinado com o Debugging Tools for Windows é uma configuração incrível. Você pode obter ambos como parte do Windows Driver Kit ou do Windows SDK mais leve . (Descobri o Application Verifier ao pesquisar uma pergunta anterior sobre um problema de corrupção de heap .) Também usei o BoundsChecker e o Insure ++ (mencionados em outras respostas) no passado, embora tenha ficado surpreso com a quantidade de funcionalidade do Application Verifier.
Vale a pena mencionar o Electric Fence (também conhecido como "efence"), dmalloc , valgrind etc., mas a maioria deles é muito mais fácil de executar com * nix do que o Windows. O Valgrind é ridiculamente flexível: depurei um software de servidor grande com muitos problemas de pilha usando-o.
Quando tudo mais falhar, você poderá fornecer ao seu próprio operador global novas sobrecargas / delete e malloc / calloc / realloc - como fazer isso variará um pouco dependendo do compilador e da plataforma - e isso será um pouco de investimento - mas pode valer a pena a longo prazo. A lista de recursos desejáveis deve parecer familiar no dmalloc e no electricfence, e o surpreendentemente excelente livro Writing Solid Code :
- valores de sentinela : permita um pouco mais de espaço antes e depois de cada alocação, respeitando o requisito máximo de alinhamento; preencher com números mágicos (ajuda a capturar estouros e subfluxos de buffer e o ocasional ponteiro "selvagem")
- atribuir preenchimento : preencha novas alocações com um valor mágico diferente de 0 - o Visual C ++ já fará isso em compilações de depuração (ajuda a capturar o uso de vars não inicializados)
- preenchimento livre : preenche a memória liberada com um valor mágico diferente de 0, projetado para disparar um segfault se for desreferenciado na maioria dos casos (ajuda a capturar ponteiros pendentes)
- atraso na liberação : não retorne a memória liberada para a pilha por um tempo, mantenha-a cheia, mas não disponível (ajuda a capturar mais indicadores pendentes, captura a liberação dupla aproximada)
- rastreamento : poder registrar onde uma alocação foi feita às vezes pode ser útil
Observe que em nosso sistema local de homebrew (para um destino incorporado), mantemos o rastreamento separado da maioria dos outros itens, porque a sobrecarga de tempo de execução é muito maior.
Se você estiver interessado em mais motivos para sobrecarregar essas funções / operadores de alocação, dê uma olhada na minha resposta para "Qualquer motivo para sobrecarregar o operador global novo e excluir?"; autopromoção vergonhosa à parte, lista outras técnicas que são úteis para rastrear erros de corrupção de heap, além de outras ferramentas aplicáveis.
Como eu continuo encontrando minha própria resposta aqui ao pesquisar valores de alocação / livre / cerca que a MS usa, aqui está outra resposta que abrange os valores de preenchimento do dbgheap da Microsoft .
Você pode detectar muitos problemas de corrupção de heap ativando o Page Heap para seu aplicativo. Para fazer isso, você precisa usar o gflags.exe que faz parte do Debugging Tools For Windows
Execute o Gflags.exe e, nas opções de arquivo de imagem do seu executável, marque a opção "Ativar heap de página".
Agora reinicie seu exe e conecte-o a um depurador. Com o Page Heap ativado, o aplicativo entrará no depurador sempre que ocorrer qualquer corrupção no heap.
fonte
Para realmente desacelerar as coisas e executar muitas verificações em tempo de execução, tente adicionar o seguinte na parte superior do seu
main()
ou equivalente no Microsoft Visual Studio C ++fonte
Um artigo muito relevante é Debugging Heap corrompido com Application Verifier e Debugdiag .
fonte
Fazer coisas impertinentes com memória, por exemplo, escrever após o término de um buffer ou gravar em um buffer após ter sido liberado de volta para o heap.
Use um instrumento que adicione verificação automática de limites ao seu executável: por exemplo, valgrind no Unix ou uma ferramenta como BoundsChecker (a Wikipedia sugere também Purify e Insure ++) no Windows.
Lembre-se de que isso reduzirá a velocidade do seu aplicativo, e poderá ser inutilizável se o seu for um aplicativo em tempo real.
Outro possível auxiliar / ferramenta de depuração pode ser o HeapAgent da MicroQuill.
fonte
Uma dica rápida que recebi de Detectando acesso à memória liberada é a seguinte:
fonte
A melhor ferramenta que achei útil e sempre funcionou é a revisão de código (com bons revisores de código).
Além da revisão de código, eu tentaria primeiro o Page Heap . O Page Heap demora alguns segundos para ser configurado e, com sorte, ele pode identificar seu problema.
Se não tiver sorte com o Page Heap, baixe o Microsoft Debugging Tools for Windows e aprenda a usar o WinDbg. Desculpe, não foi possível fornecer ajuda mais específica, mas a depuração de corrupção de heap multithread é mais uma arte do que ciência. Google para "corrupção de heap do WinDbg" e você deve encontrar muitos artigos sobre o assunto.
fonte
Você também pode verificar se está vinculando à biblioteca de tempo de execução C dinâmica ou estática. Se os arquivos DLL estiverem vinculados à biblioteca estática de tempo de execução C, os arquivos DLL terão pilhas separadas.
Portanto, se você criar um objeto em uma DLL e tentar liberá-lo em outra DLL, receberá a mesma mensagem que está vendo acima. Esse problema é mencionado em outra pergunta de estouro de pilha, liberando memória alocada em uma DLL diferente .
fonte
Que tipo de funções de alocação você está usando? Recentemente, encontrei um erro semelhante usando as funções de alocação de estilo Heap *.
Aconteceu que eu estava criando por engano a pilha com o
HEAP_NO_SERIALIZE
opção Isso essencialmente faz com que as funções Heap sejam executadas sem segurança de thread. É uma melhoria de desempenho se usada corretamente, mas nunca deve ser usada se você estiver usando o HeapAlloc em um programa multiencadeado [1]. Só mencionei isso porque sua postagem menciona que você tem um aplicativo com vários threads. Se você estiver usando HEAP_NO_SERIALIZE em qualquer lugar, exclua-o e isso provavelmente resolverá o seu problema.[1] Há certas situações em que isso é legal, mas requer que você serialize as chamadas para o Heap * e normalmente não é o caso de programas com vários threads.
fonte
Se esses erros ocorrerem aleatoriamente, há uma alta probabilidade de você encontrar corridas de dados. Por favor, verifique: você modifica ponteiros de memória compartilhada de diferentes threads? O Intel Thread Checker pode ajudar a detectar esses problemas no programa multithread.
fonte
Além de procurar ferramentas, considere procurar um provável culpado. Existe algum componente que você esteja usando, talvez não tenha sido escrito por você, que pode não ter sido projetado e testado para ser executado em um ambiente multithread? Ou simplesmente um que você não conhece que foi executado em tal ambiente.
A última vez que aconteceu comigo, era um pacote nativo que havia sido usado com sucesso em trabalhos em lotes por anos. Mas foi a primeira vez nesta empresa que foi usada em um serviço da Web .NET (que é multithread). Era isso - eles mentiram sobre o código ser seguro para threads.
fonte
Você pode usar as macros VC CRT Heap-Check para _CrtSetDbgFlag : _CRTDBG_CHECK_ALWAYS_DF ou _CRTDBG_CHECK_EVERY_16_DF .. _CRTDBG_CHECK_EVERY_1024_DF .
fonte
Eu gostaria de adicionar minha experiência. Nos últimos dias, resolvi uma instância desse erro no meu aplicativo. No meu caso particular, os erros no código foram:
Control.Invoke
e descarte um objeto gerenciado que agrupe o objeto nativo ao qual o retorno de chamada pertence.Control.Invoke
final). Devo esclarecer que usoboost::thread
, portanto, uso uma função de membro como a função de thread.Control.BeginInvoke
(minha GUI é feita com Winforms) para que o encadeamento nativo possa terminar antes que o objeto seja destruído (o objetivo do retorno de chamada é notificar com precisão que o encadeamento terminou e o objeto pode ser destruído).fonte
Eu tive um problema semelhante - e ele apareceu de forma aleatória. Talvez algo estivesse corrompido nos arquivos de compilação, mas acabei corrigindo-o limpando o projeto primeiro e depois reconstruindo.
Portanto, além das outras respostas dadas:
Que tipo de coisa pode causar esses erros? Algo corrompido no arquivo de compilação.
Como eu os depuro? Limpando o projeto e reconstruindo. Se estiver corrigido, esse provavelmente foi o problema.
fonte