Pergunta

Fundo

  • Tenho uma aplicação com um Poof-Bater [ 1 ]. Estou bastante certo de que é devido a uma pilha soprado.
  • A aplicação é multi-threaded.
  • Estou compilando com "Enable C++ Exceptions: Yes With SEH Exceptions (/EHa)".
  • Eu escrevi uma função de tradutor SE e chamou _set_se_translator() com ele.
  • Eu funções escrito para e set_terminate() configuração e set_unexpected().
  • Para obter o estouro de pilha, I deve executar no modo de versão, sob carga pesada, por vários dias. Rodando sob um depurador não é uma opção como a aplicação não pode executar rápido o suficiente para atingir o tempo de execução necessário para ver a questão.
  • eu posso simular o problema adicionando recursão infinita na execução de uma das funções, e, assim, testar a captura de exceção EXCEPTION_STACK_OVERFLOW.
  • Tenho a configuração WinDBG como o programa de despejo de memória, e obter boas informações para todos os outros problemas de colisão, mas não este . O despejo de memória irá conter apenas um segmento, que é 'Sleep ()' ing. Todos os outros segmentos ter saído.

A Pergunta

Nenhuma das coisas que eu tentei resultou em pegar a exceção EXCEPTION_STACK_OVERFLOW.

Alguém sabe como para garantir a obtenção de um a chance de essa exceção durante a execução no modo de versão?

Definições

  1. Poof-Bater :. O aplicativo trava, indo "puf" e desaparecendo sem deixar vestígios

(Considerando-se o nome deste site, eu sou uma espécie de surpresa esta pergunta não é aqui já!)

Notas

  1. Uma resposta foi publicado brevemente sobre como ajustar o tamanho da pilha para potencialmente forçar a questão mais cedo e permitem a captura-lo com um depurador. Esse é um pensamento inteligente, mas, infelizmente, eu não acredito que isso ajudaria. A questão é provavelmente causado por um caso de canto levando a recursão infinita. Encurtando a pilha não iria expor a questão mais cedo e provavelmente iria causar um acidente não relacionado no código validamente profundo. Boa idéia, porém, e obrigado por publicá-la, mesmo se você se removê-lo.
Foi útil?

Solução

Tudo anteriores ao Windows XP não iria (ou seria mais difícil) geralmente será capaz de estouros de pilha armadilha. Com o advento da XP, você pode definir vectored exceção manipulador que tem uma chance de estouro de pilha antes de qualquer (exceção estruturada) manipuladores baseado em pilha (isto é ser a própria razão - manipuladores de exceção estruturados são-stack base).

Mas não há realmente muito que você pode fazer, mesmo se você é capaz de interceptar uma exceção tal.

Na seu blog , cbrumme (desculpe, não tem seu / sua verdadeira nome) discute uma página pilha vizinha a página de proteção (o único, que gera o estouro de pilha) que pode potencialmente ser usado para backout. Se você pode espremer o seu código de backout de usar apenas uma página pilha - você pode liberar tanto quanto sua lógica permite. Caso contrário, a aplicação é praticamente morto em cima de encontrar estouro de pilha. A única outra coisa razoável a fazer, tendo prendido, é escrever um arquivo de despejo para depuração mais tarde.

Hope, isso ajuda.

Outras dicas

Eu não estou convencido de que você está no caminho certo para diagnosticar isso como um estouro de pilha.

Mas em qualquer caso, o fato de que você está recebendo um puf! , mais o que você está vendo no WinDbg

O despejo de memória irá conter apenas um segmento, que é 'Sleep ()' ing. Todos os outros segmentos ter saído.

sugere-me que alguém chamou a função C RTL exit (), ou, eventualmente, chamou a API TerminateProcess Windows () diretamente. Isso poderia ter algo a ver com os seus manipuladores de interrupção ou não. Talvez algo na lógica manipulação de exceção tem uma verificação de re-entrada e decide arbitrariamente para exit () se ele reentrou.

A minha sugestão é para corrigir seus executáveis ??para colocar talvez uma depuração INT 3 no ponto de entrada para exit (), se ele está ligado estaticamente, ou se está ligada de forma dinâmica, consertar a importação e também consertar quaisquer importações de kernel32: :. TerminateProcess para lançar um DebugBreak () em vez

Claro, exit () e / ou TerminateProcess () pode ser chamado em um desligamento normal, também, então você vai ter que filtrar os falsos alarmes, mas se você pode obter a pilha de chamadas para o caso em que é prestes a ir a prova, você deve ter o que você precisa.

EDIT ADD:. Simplesmente escrever sua própria versão de exit () e vinculá-lo em vez da versão CRTL pode fazer o truque

Lembro-me de código a partir de um local de trabalho anterior que soava similar com Bounds verificações explícitas sobre o ponteiro de pilha e lançar uma exceção manualmente.

Tem sido um tempo desde que eu toquei C ++, porém, e mesmo quando eu tocá-lo eu não sabia o que eu estava fazendo, então implementador ressalva sobre a portabilidade / confiabilidade do referido conselho.

Você já considerou ADPlus de Debugging Tools for Windows?

ADPlus anexa o depurador CDB a um processo no modo de "crash" e irá gerar despejos de memória para a maioria das exceções O processo gera. Basicamente, você corre "ADPlus -crash -p yourPIDhere", ele executa um invasor anexar e começa o registo.

Dado o seu comentário acima sobre a execução em um depurador, eu só queria acrescentar que CDB acrescenta praticamente zero sobrecarga no modo -crash em uma máquina decente (dual-core, 2GB RAM), por isso não deixe que espera você de volta de tentá-lo.

Você pode gerar símbolos de depuração sem desativar otimizações. Na verdade, você deveria estar fazendo isso de qualquer maneira. Ele apenas torna a depuração mais difícil.

E a documentação para _set_se_translator diz que cada segmento tem seu próprio tradutor SE. Você está definindo um para cada segmento?

set_unexpected é provavelmente um não-op, pelo menos de acordo com a documentação do VS 2005. E cada thread também tem o seu próprio manipulador terminate, então você deve instalar esse por thread também.

Eu também recomendo fortemente não usando tradução SE. Leva hardware exceções que você não deve ignorar (ou seja, você realmente deve registrar um erro e encerrar) e os transforma em algo que você pode ignorar (exceções C ++). Se você quer pegar esse tipo de erro, use um manipulador __try/__except.

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