Compartilhar via


_resetstkoflw

Recupera do estouro de pilha.

Importante

Esta API não pode ser usada em aplicativos que executam no Tempo de Execução do Windows.Para obter mais informações, consulte Funções CRT sem suporte pelo /ZW.

int _resetstkoflw ( void );

Valor de retorno

Diferente de zero se a função tiver êxito, zero se falhar.

Comentários

A função de _resetstkoflw é recuperada de uma condição de estouro de pilha, permitindo que um programa continue em vez de falhar com um erro fatal de exceção. Se a função de _resetstkoflw não for chamada, não há nenhuma página de proteção após a exceção anterior. Na próxima vez em que houver um estouro de pilha, não haverá exceções e o processo será encerrado sem nenhum aviso.

Se um segmento em um aplicativo causar uma exceção EXCEPTION_STACK_OVERFLOW, o segmento deixa a pilha em um estado corrompido. Isso está em contraste com outras exceções, como EXCEPTION_ACCESS_VIOLATION ou EXCEPTION_INT_DIVIDE_BY_ZERO, onde a pilha não é danificada. A pilha é definida como um valor arbitrariamente pequeno quando o programa é carregado pela primeira vez. Assim, a pilha aumenta sob demanda para atender às necessidades do thread. Isso é implementado colocando uma página com acesso PAGE_GUARD no fim da pilha atual. Para obter mais informações, consulte Criando páginas de proteção.

Quando o código faz com que o ponteiro de pilha aponte para um endereço nessa página, ocorre uma exceção e o sistema realiza estas três ações:

  • Remove a proteção PAGE_GUARD na página de proteção de modo que o thread possa ler e gravar dados na memória.

  • Atribui uma página de proteção nova que fica localizada em uma página, abaixo da última.

  • Executa novamente a instrução que gerou a exceção.

Dessa forma, o sistema pode aumentar o tamanho da pilha para o segmento automaticamente. Cada segmento em um processo tem um tamanho máximo de pilha. O tamanho da pilha é definido no tempo de compilação pela instrução /STACK (alocações da pilha) ou STACKSIZE no arquivo .def do projeto.

Quando esse tamanho máximo de pilha é excedido, o sistema realiza as três ações a seguir:

  • Remove a proteção PAGE_GUARD na página de proteção, conforme descrito anteriormente.

  • Tenta alocar uma nova página de proteção abaixo da última. No entanto, isso falha porque o tamanho máximo da pilha foi excedido.

  • Gera uma exceção de modo que o thread possa manipulá-la no bloco de exceção.

Observe que, nesse ponto, a pilha não tem mais uma página de proteção. Na próxima vez que o programa expandir a pilha até o fim, onde deve haver uma página de proteção, o programa gravará além do fim da pilha e causará uma violação de acesso

Chame _resetstkoflw para restaurar a página de proteção sempre que for feita a recuperação, após uma exceção de estouro de pilha. Essa função pode ser chamada de dentro do corpo principal de um bloco __except ou fora de um bloco __except. No entanto, há algumas restrições sobre quando deve ser usado. _resetstkoflw nunca deve ser chamado de:

  • Uma expressão de filtro.

  • Uma função de filtro.

  • Uma função chamada de uma função de filtro.

  • Um bloco de catch.

  • Um bloco __finally.

Nesses pontos, a pilha ainda não está desenrolada o suficiente.

As exceções de estouro de pilha são geradas como exceções estruturadas, não como exceções C++, portanto, _resetstkoflw não é útil em um bloco de catch comum, pois ele não irá capturar uma exceção de estouro de pilha. No entanto, se _set_se_translator for usado para implementar um tradutor de exceção estruturada que lança exceções de C++ (como o segundo exemplo), uma exceção de estouro de pilha resultará na exceção de C++ que pode ser tratada pelo bloco catch de C++.

Não é seguro chamar _resetstkoflw em um bloco catch de C++ que é alcançado de uma exceção acionada pela função estruturada de tradutor de exceção. Nesse caso, o espaço de pilha não é liberado e o ponteiro de pilha não é redefinido até estar fora do bloco catch, mesmo que os destruidores tenham sido chamados para todos os objetos destrutíveis antes do bloco catch. Essa função não deve ser chamada até que o espaço de pilha seja liberado e o ponteiro de pilha tenha sido redefinido. Portanto, ela deve ser chamada apenas após a saída do bloco catch. Deve ser usado o menor espaço de pilha possível no bloco catch, pois a ocorrência de um estouro de pilha no próprio bloco catch que está tentando se recuperar de um estouro de pilha anterior não pode ser recuperado e pode fazer com que o programa pare de responder, pois o estouro no bloco catch aciona uma exceção em si que será manipulada pelo mesmo bloco catch.

Há situações onde _resetstkoflw pode falhar se usado em um local correto, como em um bloco __except. Se, mesmo após o desenrolamento de pilha, ainda não houver espaço suficiente de pilha sobrando para executar _resetstkoflw sem escrever na última página da pilha, _resetstkoflw falhará ao redefinir a última página de pilha como página de proteção e retornará 0, indicando uma falha. Portanto, o uso seguro dessa função deve incluir a verificação do valor de retorno, em vez de pressupor que a pilha é segura para ser usada.

A manipulação de exceção estruturada não irá capturar uma exceção de STATUS_STACK_OVERFLOW quando o aplicativo for compilado com /clr ou /clr:pure (consulte /clr (compilação do Common Language Runtime)).

Requisitos

Rotina

Cabeçalho necessário

_resetstkoflw

<malloc.h>

Para obter mais informações de compatibilidade, consulte Compatibilidade.

Bibliotecas: Todas as versões das Recursos da biblioteca CRT.

Exemplo

O exemplo a seguir mostra o uso recomendado da função _resetstkoflw.

// crt_resetstkoflw.c
// Launch program with and without arguments to observe
// the difference made by calling _resetstkoflw.

#include <malloc.h>
#include <stdio.h>
#include <windows.h>

void recursive(int recurse)
{
   _alloca(2000);
   if (recurse)
      recursive(recurse);
}

// Filter for the stack overflow exception.
// This function traps the stack overflow exception, but passes
// all other exceptions through. 
int stack_overflow_exception_filter(int exception_code)
{
   if (exception_code == EXCEPTION_STACK_OVERFLOW)
   {
       // Do not call _resetstkoflw here, because
       // at this point, the stack is not yet unwound.
       // Instead, signal that the handler (the __except block)
       // is to be executed.
       return EXCEPTION_EXECUTE_HANDLER;
   }
   else
       return EXCEPTION_CONTINUE_SEARCH;
}

int main(int ac)
{
   int i = 0;
   int recurse = 1, result = 0;

   for (i = 0 ; i < 10 ; i++)
   {
      printf("loop #%d\n", i + 1);
      __try
      {
         recursive(recurse);

      }

      __except(stack_overflow_exception_filter(GetExceptionCode()))
      {
         // Here, it is safe to reset the stack.

         if (ac >= 2)
         {
            puts("resetting stack overflow");
            result = _resetstkoflw();
         }
      }

      // Terminate if _resetstkoflw failed (returned 0)
      if (!result)
         return 3;
   }

   return 0;
}

Saída de Exemplo

Sem argumentos de programa:

loop #1

O programa para de responder sem executar outras iterações.

Com argumentos de programa:

loop #1
resetting stack overflow
loop #2
resetting stack overflow
loop #3
resetting stack overflow
loop #4
resetting stack overflow
loop #5
resetting stack overflow
loop #6
resetting stack overflow
loop #7
resetting stack overflow
loop #8
resetting stack overflow
loop #9
resetting stack overflow
loop #10
resetting stack overflow

Descrição

O exemplo a seguir mostra o uso recomendado de _resetstkoflw em um programa onde as exceções estruturadas são convertidas em exceções C++.

Código

// crt_resetstkoflw2.cpp
// compile with: /EHa
// _set_se_translator requires the use of /EHa
#include <malloc.h>
#include <stdio.h>
#include <windows.h>
#include <eh.h>

class Exception { };

class StackOverflowException : Exception { };

// Because the overflow is deliberate, disable the warning that
// this function will cause a stack overflow.
#pragma warning (disable: 4717)
void CauseStackOverflow (int i)
{
        // Overflow the stack by allocating a large stack-based array
        // in a recursive function.
        int a[10000];
        printf("%d ", i);
        CauseStackOverflow (i + 1);
}

void __cdecl SEHTranslator (unsigned int code, _EXCEPTION_POINTERS*)
{
   // For stack overflow exceptions, throw our own C++ 
   // exception object.
   // For all other exceptions, throw a generic exception object.
   // Use minimal stack space in this function.
   // Do not call _resetstkoflw in this function.

   if (code == EXCEPTION_STACK_OVERFLOW)
      throw StackOverflowException ( );
   else
      throw Exception( );
}

int main ( )
{
        bool stack_reset = false;
        bool result = false;

        // Set up a function to handle all structured exceptions,
        // including stack overflow exceptions.
        _set_se_translator (SEHTranslator);

        try
        {
            CauseStackOverflow (0);
        }
        catch (StackOverflowException except)
        {
                // Use minimal stack space here.
                // Do not call _resetstkoflw here.
                printf("\nStack overflow!\n");
                stack_reset = true;
        }
        catch (Exception except)
        {
                // Do not call _resetstkoflw here.
                printf("\nUnknown Exception!\n");
        }
        if (stack_reset)
        {
          result = _resetstkoflw();
          // If stack reset failed, terminate the application.
          if (result == 0)
             exit(1);
        }

        void* pv = _alloca(100000);
        printf("Recovered from stack overflow and allocated 100,000 bytes"
               " using _alloca.");

   return 0;
}

Saída de Exemplo

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Stack overflow!
Recovered from stack overflow and allocated 100,000 bytes using _alloca.

Equivalência do .NET Framework

Não aplicável. Para chamar a função padrão de C, use PInvoke. Para obter mais informações, consulte Exemplos de chamadas de plataformas.

Consulte também

Referência

_alloca