Compartilhar via


_resetstkoflw

Recupera o excedente de pilha.

Importante

Esta API não pode ser usada em aplicativos executados no Windows Runtime. Para obter mais informações, confira Funções do CRT sem suporte em aplicativos da Plataforma Universal do Windows.

Sintaxe

int _resetstkoflw( void );

Valor retornado

Será diferente de zero se a função obtiver êxito, zero se ela falhar.

Comentários

A função _resetstkoflw recupera de uma condição de excedente de pilha, permitindo que um programa continue em vez de falhar com um erro de exceção fatal. Se a função _resetstkoflw não for chamada, não existirão páginas de proteção após a exceção anterior. Na próxima vez que houver um excedente de pilha, não haverá nenhuma exceção e o processo terminará sem aviso.

Se um thread em um aplicativo causa uma exceção EXCEPTION_STACK_OVERFLOW, o thread deixou a pilha desse thread em um estado danificado. Essa exceção é diferente de outras exceções, como EXCEPTION_ACCESS_VIOLATION ou EXCEPTION_INT_DIVIDE_BY_ZERO, em que a pilha não está danificada. A pilha é definida para um valor arbitrariamente pequeno quando o programa é carregado pela primeira vez. Em seguida, a pilha aumenta conforme a demanda para atender às necessidades do thread. O crescimento sob demanda é implementado colocando uma página com PAGE_GUARD acesso no final 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 executa as três ações a seguir:

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

  • Aloca uma nova página de proteção que é localizada 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 do thread automaticamente. Cada thread em um processo tem um tamanho máximo de pilha. O tamanho da pilha é definido em tempo de compilação pela opção (Alocações de /STACK Pilha) ou pela STACKSIZE instrução no .def arquivo do projeto.

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

  • Remove a proteção de 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, a alocação falha porque o tamanho máximo da pilha foi excedido.

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

Nesse ponto, a pilha não tem uma página de proteção. Na próxima vez que o programa aumentar a pilha para onde ele grava além do final da pilha, ele causará uma violação de acesso.

Chame _resetstkoflw para restaurar a página de proteção sempre que a recuperação for feita após uma exceção de excedente 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 isso deve ser usado. _resetstkoflw não deve ser usado de:

  • Uma expressão de filtro.

  • Uma função de filtro.

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

  • Um bloco catch.

  • Um bloco __finally.

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

Exceções de excedente de pilha são geradas como exceções estruturadas, não exceções C++, por isso _resetstkoflw não é útil em um bloco catch comum, pois ele não vai capturar uma exceção de excedente de pilha. No entanto, se _set_se_translator for usado para implementar um conversor de exceção estruturada que gere exceções C++ (como no segundo exemplo), uma exceção de excedente de pilha resultará em uma exceção C++ que poderá ser manipulada por um bloco catch de C++.

Não é seguro chamar _resetstkoflw em um bloco catch de C++ que é alcançado de uma exceção gerada pela função do conversor de exceção estruturada. Nesse caso, o espaço de pilha não é liberado e o ponteiro de pilha não é redefinido até estar fora do bloco catch, embora os destruidores tenham sido chamados para todos os objetos destrutíveis antes do bloco catch. Essa função não deve ser chamada até o espaço de pilha ser liberado e o ponteiro de pilha ser redefinido. Portanto, ele deve ser chamado somente depois de sair do bloco catch. O menor espaço possível na pilha deve ser usado no bloco catch. Um estouro de pilha que ocorre no bloco catch que está tentando se recuperar de um estouro de pilha anterior não é recuperável. Isso pode fazer com que o programa pare de responder, pois o estouro no bloco catch aciona uma exceção que é tratada pelo mesmo bloco catch.

Há situações em que _resetstkoflw pode falhar, mesmo se usado em um local correto, como em um bloco __except. Pode não haver espaço suficiente para executar _resetstkoflw sem gravar na última página da pilha, mesmo depois de desenrolar a pilha. Em seguida, _resetstkoflw falha ao redefinir a última página da pilha como a página de proteção e retorna 0, indicando falha. O uso seguro desta função deve incluir a verificação do valor retornado em vez de supor que é seguro usar a pilha.

O tratamento de exceção estruturada não captura uma exceção STATUS_STACK_OVERFLOW quando o aplicativo é compilado com /clr (confira /clr (Compilação Common Language Runtime)).

Por padrão, o estado global dessa função tem como escopo o aplicativo. Para alterar esse comportamento, confira Estado global no CRT.

Requisitos

Rotina Cabeçalho necessário
_resetstkoflw <malloc.h>

Para obter informações sobre compatibilidade, consulte Compatibilidade.

Bibliotecas: todas as versões dos 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 isn't 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 nenhuma outra iteração.

Com argumentos do 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 em que exceções estruturadas são convertidas em exceções de 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;
}
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.

Confira também

_alloca