Pergunta

Estou a depuração de um (nativo) multi-threaded aplicação C ++ em Visual Studio 2008. Em ocasiões aparentemente aleatórios, eu recebo um "Windows provocou um break point ..." Erro com uma nota que isso pode ser devido a uma corrupção no heap. Esses erros nem sempre irá falhar a aplicação de imediato, embora seja provável a falhar pouco depois.

O grande problema com esses erros é que eles aparecem somente após a corrupção realmente ocorreu, o que os torna muito difícil de rastrear e depurar, especialmente em uma aplicação multi-threaded.

  • Que tipo de coisas podem causar esses erros?

  • Como faço para depurá-los?

Dicas, ferramentas, métodos, enlightments ... são bem-vindos.

Foi útil?

Solução

aplicação Verificador combinada com Ferramentas de depuração para Windows é uma configuração incrível. Você pode obter tanto como uma parte do Windows Driver Kit ou o isqueiro Windows SDK . (Constatou-se sobre aplicação Verificador quando se pesquisa um pergunta anterior sobre um problema de corrupção de pilha .) Eu usei BoundsChecker e garantir ++ (mencionado em outras respostas) no passado também, embora I foi surpreendido quanta funcionalidade estava em Application Verifier.

Cerca Elétrica (aka "efence"), Dmalloc , valgrind , e assim por diante são todos vale a pena mencionar, mas a maioria delas são muito mais fáceis de obter em execução no * nix que o Windows. Valgrind é ridiculamente flexível:. Eu depurado software de servidor grande, com muitas questões heap usá-lo

Quando tudo mais falhar, você pode fornecer o seu próprio operador global novo / apagar e malloc / calloc / realloc sobrecargas - como fazê-lo pode variar um pouco dependendo do compilador e da plataforma - e isso vai ser um pouco de um investimento - mas pode pagar no longo prazo. A lista característica desejável deve ser familiar a partir Dmalloc e ElectricFence, e surpreendentemente excelente livro Escrevendo Sólidos Código :

  • Os valores sentinela : permitir um pouco mais de espaço antes e depois de cada alocação, respeitando exigência máxima alinhamento; preenchimento com números mágicas (ajuda transborda de captura tampão e underflows, e o ponteiro ocasional "selvagem")
  • preenchimento alloc : preenchimento novas atribuições com um não-0 valor mágica - Visual C ++ já vai fazer isso por você em compilações de depuração (ajuda a utilização de capturas de vars não inicializadas)
  • preenchimento livre : preenchimento na memória liberada com um não-0 valor mágica, projetado para disparar um segfault se é dereferenced na maioria dos casos (ajuda ponteiros captura pendurado)
  • atrasada livre : não retornar memória liberada para a pilha por um tempo, mantê-lo livre cheio, mas não disponível (ajuda a captura mais pendurado ponteiros, as capturas pr�ima duplas-livra)
  • tracking : ser capaz de gravar em uma alocação foi feito às vezes pode ser útil

Note que em nosso sistema homebrew local (para um alvo incorporado) mantemos o separado rastreamento da maioria das outras coisas, porque a sobrecarga de tempo de execução é muito maior.


Se você estiver interessado em mais razões para sobrecarregar estas alocação de funções / operadores, dê uma olhada minha resposta à pergunta "Você tem algum motivo para sobrecarga de operador global de novo e excluir "; desavergonhada auto-promoção de lado, ele lista outras técnicas que são úteis na localização de erros montão de corrupção, bem como outras ferramentas aplicáveis.


Porque eu manter a encontrar a minha própria resposta aqui na busca de alocação / livre / Vedação valores MS usos, aqui está outra resposta que cobre Microsoft dbgheap valores de preenchimento .

Outras dicas

Você pode detectar um monte de problemas de corrupção de heap, permitindo Página Heap para sua aplicação. Para fazer isso você precisa usar gflags.exe que vem como parte de Debugging Tools for Windows

Executar Gflags.exe e nas opções de arquivo de imagem para seu executável, marque a opção "Ativar Página Heap" opção.

Agora reinicie o exe e anexar a um depurador. Com Página Heap ativado, o aplicativo vai quebrar em depurador sempre que qualquer corrupção de pilha ocorre.

Para que as coisas realmente desacelerar e executar um monte de verificação de tempo de execução, tente adicionar o seguinte no topo de sua main() ou equivalente no Microsoft Visual Studio C ++

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_ALWAYS_DF );

Que tipo de coisas podem causar esses erros?

Fazer as coisas impertinentes com a memória, por exemplo, escrevendo após o fim de um tampão, ou escrever para um buffer depois de ter sido libertado de volta para o heap.

Como faço para depurá-los?

Use um instrumento que adiciona automatizado limites de verificação para seu executável:. Ou seja valgrind em Unix, ou uma ferramenta como BoundsChecker (Wikipedia sugere também Purify e garantir ++) no Windows

Tenha em atenção que estes irão retardar a sua aplicação, para que eles possam ser inutilizável se o seu é um aplicativo de tempo macio real.

Outra possível ajuda de depuração / ferramenta pode ser HeapAgent de MicroQuill.

Uma dica rápida, que eu tenho de acesso Detectando a memória liberada é esta:

Se você deseja localizar o erro rapidamente, sem verificar todos os declaração de que acessa a memória bloco, você pode definir o ponteiro de memória com um valor inválido depois de afastada a bloquear:

#ifdef _DEBUG // detect the access to freed memory
#undef free
#define free(p) _free_dbg(p, _NORMAL_BLOCK); *(int*)&p = 0x666;
#endif

A melhor ferramenta eu achei úteis e trabalhado cada vez é revisão de código (com bons revisores de código).

Além de revisão de código, eu tente primeiro Página heap. Página Heap leva alguns segundos para configurar e, com sorte, pode identificar o seu problema.

Se nenhuma sorte com Página Heap, baixar Debugging Tools for Windows da Microsoft e aprender a usar o WinDbg. Desculpe não poderia dar-lhe uma ajuda mais específica, mas debuging corrupção de pilha de multi-threaded é mais uma arte do que ciência. Google por "WinDbg corrupção de pilha" e você deve encontrar muitos artigos sobre o assunto.

Você também pode querer verificar para ver se você está ligando contra o dinâmico ou biblioteca C tempo de execução estática. Se os seus arquivos DLL estão ligando com a biblioteca de tempo de execução estática C, em seguida, os arquivos DLL tem pilhas separadas.

Por isso, se você fosse para criar um objeto em uma DLL e tentar libertá-lo em outro DLL, você teria a mesma mensagem que você está vendo acima. Este problema é referenciada em outra pergunta Stack Overflow, memória Liberação alocado em um DLL diferente .

Que tipo de funções de alocação você está usando? I recentemente atingiu um erro semelhante usando o * funções de alocação de estilo Heap.

Acontece que eu estava erroneamente criando a pilha com a opção HEAP_NO_SERIALIZE. Isso faz essencialmente as funções Heap executados sem a segurança do thread. É uma melhoria de desempenho, se usado corretamente, mas não deve nunca ser usado se você estiver usando HeapAlloc em um programa multi-threaded [1]. Eu só mencionei isso porque seu post menciona você tiver um aplicativo de multi-threaded. Se você estiver usando HEAP_NO_SERIALIZE em qualquer lugar, eliminar isso e ele provavelmente vai resolver o seu problema.

[1] Há certas situações em que isso é legal, mas requer que você chamadas serialize para Heap * e não é tipicamente o caso para programas multi-threaded.

Se estes erros ocorrem aleatoriamente, há grande probabilidade de que você encontrou dados-raças. Por favor, verifique: você modificar ponteiros de memória compartilhada de segmentos diferentes? Intel Thread Checker pode ajudar a detectar tais questões no programa multithread.

Além de olhar para ferramentas, considerar olhando para um provável culpado. Existe algum componente que você está usando, talvez não 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 sei foi executado em tal ambiente.

A última vez que isso aconteceu comigo, era um pacote nativo que tinha sido utilizado com sucesso de trabalhos em lote por anos. Mas foi a primeira vez nesta empresa que tinha sido usado de um serviço .NET web (que é multithreaded). Era isso - eles haviam mentido sobre o código sendo o segmento de seguros

.

Você pode usar VC CRT Heap-Check macros para _CrtSetDbgFlag :. _CRTDBG_CHECK_ALWAYS_DF ou _CRTDBG_CHECK_EVERY_16_DF .. _CRTDBG_CHECK_EVERY_1024_DF

Eu gostaria de acrescentar a minha experiência. Nos últimos dias, eu resolvi um caso de esse erro no meu aplicativo. No meu caso particular, os erros no código foram:

  • Remover elementos de uma coleção STL enquanto Iterando sobre ele (eu acredito que há sinalizadores de depuração no Visual Studio para pegar essas coisas, eu pego durante a revisão do código)
  • Este é mais complexa, vou dividi-lo em etapas:
    • A partir de um C ++ nativo fio, chamada de volta em código gerenciado
    • Em terra gerida, Control.Invoke chamada e descartar um objeto gerenciado que envolve o objeto nativo para o qual o callback pertence.
    • Uma vez que o objeto ainda está viva dentro da thread nativa (ele permanecerá bloqueado na chamada de retorno de chamada até fins Control.Invoke). Devo esclarecer que eu uso boost::thread, então eu uso uma função membro como a função thread.
    • Solução : Use Control.BeginInvoke (minha GUI é feito com WinForms) em vez para que o segmento nativo pode terminar antes do objeto é destruído (o propósito do retorno é precisamente notificando que o segmento terminou e o objeto pode ser destruído).

Eu tive um problema semelhante - e ela apareceu bastante aleatoriamente. Talvez algo estava corrompida nos arquivos de compilação, mas acabei corrigi-lo por limpar o projeto primeiro e depois reconstruir.

Assim, além de outras respostas dadas:

Que tipo de coisas podem causar esses erros? Algo corrupto do arquivo de construção.

Como faço para depurá-los? Limpeza do projeto e reconstrução. Se ele é fixo, este foi provavelmente o problema.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top