A interceptação de estouro de pilha em um aplicativo Visual C++

IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine Translation ou MT), não tendo sido portanto traduzido ou revisto por pessoas. A Microsoft possui artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais, com o objetivo de oferecer em português a totalidade dos artigos existentes na base de dados de suporte. No entanto, a tradução automática não é sempre perfeita, podendo conter erros de vocabulário, sintaxe ou gramática. A Microsoft não é responsável por incoerências, erros ou prejuízos ocorridos em decorrência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza atualizações freqüentes ao software de tradução automática (MT). Obrigado.

Clique aqui para ver a versão em Inglês deste artigo: 315937
Este artigo foi arquivado. É oferecido "como está" e não será mais atualizado.
Sumário
Um thread que excede a alocação de pilha irá disparar uma exceção. Essa exceção pode ser interceptada com as palavras-chave __try e __except no Microsoft Visual C++. No entanto, sem tratamento correto, estouros de pilha subseqüente irão gerar exceções de violação de acesso. Este artigo mostra como tratar de estouros de pilha mais verdadeiramente.

back to the top

Requisitos

Os seguintes itens descrevem o hardware recomendado, software, infra-estrutura de rede, habilidades e conhecimento e service packs que você precisa.
  • Microsoft Windows NT, Microsoft Windows 2000 ou Microsoft Windows XP
Conhecimento prévio necessário:
  • Você deve ter um bom conhecimento de programação do Visual C++, incluindo o tratamento de exceção.
back to the top

Criando um programa de teste para demonstrar o estouro de pilha

  1. Inicie o Microsoft Visual C++ 6.0 e crie um novo aplicativo de Console Win32 chamado StackOverflowDemo. No Assistente do aplicativo de console do Win32, selecione um aplicativo simples e, em seguida, clique em Concluir . Clique em OK para criar o novo aplicativo.
  2. Na janela do espaço de trabalho, clique guia FileView expandir o nó de arquivos StackOverflowDemo e, em seguida, expanda o nó Source Files . Clique duas vezes em StackOverflowDemo.cpp para editar esse arquivo na janela código.
  3. No StackOverflowDemo.cpp, adicione as seguintes diretivas # include após a diretiva de "stdafx.h" # include existente:
    #include <windows.h>#include <stdio.h>						
  4. Após as diretivas # include , digite a função a seguir. Isso causa um estouro de pilha deliberadamente:
    void StackOverflow(int depth){    char blockdata[10000];    printf("Overflow: %d\n", depth);    StackOverflow(depth+1);}						
  5. Editar a função principal da seguinte maneira: main(int argc, char * argv[])
    {    StackOverflow(0);    return 0;}						
    int
  6. Pressione F5 para executar o programa no depurador. O programa exibe uma série de mensagens para o console. Essas mensagens que o formulário "estouro: n". Cada mensagem indica uma chamada recursiva para a função de StackOverflow. Finalmente, uma caixa de mensagem aparece que exibe a seguinte mensagem de erro:
    Exceção no StackOverflowDemo.exe sem tratamento: 0xC00000FD: estouro de pilha.
  7. Pressione OK para fechar a caixa de diálogo. Dependendo da sua configuração, o IDE pode tentar localizar a origem para CHKSTK.ASM. Se esta caixa de diálogo aparecer, pressione Cancelar . Clique no menu Debug e, em seguida, clique em Stop Debugging para fechar o programa.
back to the top

Ajuste de registro de exceção com __try e __except (solução parcial)

Nesta seção, você interceptar a exceção de estouro de pilha usando __try e __except . Essa solução está incompleta. O estouro de pilha primeiro irá disparar uma exceção de estouro de pilha. No entanto, os estouros de pilha subseqüente causa exceções de violação de acesso.
  1. Modificar a função principal da seguinte maneira: main(int argc, char * argv[])
    {    for (;;)    {            __try        {            StackOverflow(0);        }        __except (EXCEPTION_EXECUTE_HANDLER)        {            printf("Exception handler %lX\n", _exception_code());             Sleep(2000);        }    }    return 0;}						
    int
  2. Pressione F5 para executar o programa no depurador.
  3. A saída do console como antes, continua até que o estouro de pilha ocorre. A mensagem de manipulador de exceção, em seguida, é impresso. O loop assegura que a função de StackOverflow é repetida.
  4. O programa exibe a seguinte saída:
    Overflow: 0Overflow: 1Overflow: 2..Exception Handler C00000FDOverflow: 0Overflow: 1Overflow: 2..Exception Handler C0000005Overflow: 0Overflow: 1Overflow: 2..Exception Handler C0000005						
    a primeira exceção é um estouro de pilha (C00000FD), mas as chamadas subseqüentes para a função de StackOverflow causar uma exceção de violação de acesso (C0000005).
  5. Clique no menu Debug no Visual C++ e, em seguida, clique em Stop Debugging para fechar o programa.
back to the top

Ajuste de registro exceção com __try e __except (Total Solution)

Se um thread em seu aplicativo faz com que uma exceção EXCEPTION_STACK_OVERFLOW, em seguida, seu thread deixou sua pilha em um estado danificado. Isso é contrário outras exceções, como EXCEPTION_ACCESS_VIOLATION ou EXCEPTION_INT_DIVIDE_BY_ZERO, onde a pilha não está danificada. Isso ocorre porque a pilha é definida como um valor arbitrariamente pequeno quando o programa é carregado pela primeira vez. A pilha cresce, em seguida, sob demanda para atender às necessidades do thread. Isso é implementado colocando uma página com acesso PAGE_GUARD no final da pilha atual. Quando seu código faz com que o ponteiro da pilha apontar para um endereço nesta página, ocorre uma exceção. O sistema, em seguida, faz as três seguintes ações:
  1. Remova a proteção PAGE_GUARD na página de proteção, para que o thread pode ler e gravar dados para a memória.
  2. Alocar uma proteção nova página que seja localizado um abaixo da última.
  3. Execute novamente a instrução que gerou a exceção.
Dessa forma, o sistema pode aumentar a pilha para o thread automaticamente. Cada thread em um processo tem um tamanho de pilha máximo. O tamanho de pilha é definido em tempo de compilação pelo /STACK:reserve [, confirmar] a opção de vinculador, ou pela instrução STACKSIZE no arquivo .def para o projeto. Quando esse tamanho de pilha máximo for excedido, o sistema faz três seguintes ações:
  • Remova a proteção PAGE_GUARD na página de proteção, conforme descrito anteriormente.
  • Tente alocar uma nova página de proteção abaixo da última. No entanto, isso falhar porque excedeu o tamanho máximo da pilha.
  • Gerar uma exceção, para que o thread pode manipulá-lo no bloco de exceção.
Observe um ponto importante: A pilha não tem uma página de proteção. Na próxima vez que o seu programa cresce a pilha até o final (onde deve haver uma página de proteção), seu programa grava além do fim da pilha e faz com que uma violação de acesso.

Você pode reparar a página de proteção no manipulador de exceção usando o exemplo mostrado nesta seção.

Modificar a função principal da seguinte maneira:
int main(int argc, char* argv[]){    for (;;)    {        __try        {            StackOverflow(0);        }        __except(EXCEPTION_EXECUTE_HANDLER)        {            LPBYTE lpPage;            static SYSTEM_INFO si;            static MEMORY_BASIC_INFORMATION mi;            static DWORD dwOldProtect;            // Get page size of system            GetSystemInfo(&si);                        // Find SP address            _asm mov lpPage, esp;            // Get allocation base of stack            VirtualQuery(lpPage, &mi, sizeof(mi));            // Go to page beyond current page            lpPage = (LPBYTE)(mi.BaseAddress)-si.dwPageSize;            // Free portion of stack just abandoned            if (!VirtualFree(mi.AllocationBase,                            (LPBYTE)lpPage - (LPBYTE)mi.AllocationBase,                             MEM_DECOMMIT))				{                // If we get here, exit                exit(1);            }				// Reintroduce the guard page				if (!VirtualProtect(lpPage, si.dwPageSize,                                 PAGE_GUARD | PAGE_READWRITE,                                 &dwOldProtect))				{                exit(1);            }				printf("Exception handler %lX\n", _exception_code());             Sleep(2000);        }	}	return 0;}				
back to the top

Verificar se ele funciona

  1. Pressione F5 para executar o programa no depurador.
  2. Observe a saída do seu programa. Verifique se todas as exceções são pilha estouro exceções (C00000FD). Essa saída mostra que você tenha substituído com êxito a página de proteção como parte do mecanismo de tratamento de exceção.
  3. Selecione o menu Debug no Visual C++ e, em seguida, clique em Stop Debugging para fechar o programa.
back to the top

Solução de problemas

Esta solução usa instruções assembly in-line. Isso significa que a solução é válida somente para versões do Intel (x 86) do Microsoft Windows. Não é adequado para implementações do Windows em arquiteturas de não-Intel (MIPS ou Alpha).

back to the top

Aviso: este artigo foi traduzido automaticamente

Propriedades

ID do Artigo: 315937 - Última Revisão: 12/07/2015 08:37:28 - Revisão: 3.0

Microsoft Visual C++ 6.0 Standard Edition, Microsoft Visual C++ 6.0 Service Pack 5, Microsoft Visual C++ 6.0 Professional Edition, Microsoft Visual C++ 6.0 Enterprise Edition

  • kbnosurvey kbarchive kbmt kbhowtomaster KB315937 KbMtpt
Comentários
ERROR: at System.Diagnostics.Process.Kill() at Microsoft.Support.SEOInfrastructureService.PhantomJS.PhantomJSRunner.WaitForExit(Process process, Int32 waitTime, StringBuilder dataBuilder, Boolean isTotalProcessTimeout)