_resetstkoflw

Se recupera de un desbordamiento de pila.

Importante

Esta API no se puede usar en aplicaciones que se ejecutan en Windows en tiempo de ejecución. Para obtener más información, vea Funciones de CRT no admitidas en aplicaciones de la Plataforma universal de Windows.

Sintaxis

int _resetstkoflw( void );

Valor devuelto

Valor distinto de cero si la función se ejecuta correctamente, cero si se produce un error.

Comentarios

La función _resetstkoflw se recupera de una condición del desbordamiento de pila, lo que permite que el continúe en lugar de generar un error de excepción grave. Si no se llama a la función _resetstkoflw, no queda ninguna página de protección después de la excepción anterior. La próxima vez que haya un desbordamiento de pila, no habrá ninguna excepción en absoluto y el proceso finalizará sin avisar.

Si un subproceso de una aplicación provoca una excepción EXCEPTION_STACK_OVERFLOW, el subproceso ha dejado la pila en estado dañado. Esta excepción es diferente de otras excepciones, como EXCEPTION_ACCESS_VIOLATION o EXCEPTION_INT_DIVIDE_BY_ZERO, donde la pila no está dañada. La pila se establece de forma arbitraria en un valor pequeño la primera vez que se carga el programa. Después, la pila aumenta de tamaño a petición para satisfacer las necesidades del subproceso. El crecimiento a petición se implementa colocando una página con PAGE_GUARD acceso al final de la pila actual. Para obtener más información, consulte Creación de páginas de protección.

Si el código hace que el puntero de pila señale a una dirección de esta página, se produce una excepción y el sistema realiza las tres operaciones siguientes:

  • Quita la PAGE_GUARD protección de la página de protección para que el subproceso pueda leer y escribir datos en la memoria.

  • Asigna una nueva página de protección que se ubica una página por detrás de la última.

  • Vuelve a ejecutar la instrucción que provocó la excepción.

De esta manera, el sistema puede aumentar automáticamente el tamaño de la pila del subproceso. Cada subproceso de un proceso tiene un tamaño de pila máximo. El tamaño de la pila se establece en tiempo de compilación mediante la /STACK opción (Asignaciones de pila) o por la STACKSIZE instrucción del .def archivo del proyecto.

Cuando se supera este tamaño de pila máximo, el sistema realiza las tres operaciones siguientes:

  • Quite la protección de PAGE_GUARD de la página de protección, como ya se ha descrito.

  • Intenta asignar una nueva página de protección detrás de la última. Sin embargo, se produce un error en la asignación porque se ha superado el tamaño máximo de la pila.

  • Provoca una excepción para que el subproceso pueda controlarla en el bloque de excepciones.

En este punto, la pila ya no tiene una página de protección. La próxima vez que el programa aumente la pila a donde escribe más allá del final de la pila, provoca una infracción de acceso.

Llame a _resetstkoflw para restaurar la página de protección siempre que la recuperación se realice después de una excepción de desbordamiento de pila. Se puede llamar a esta función desde dentro del cuerpo principal de un bloque __except o desde fuera de un bloque __except. Sin embargo, hay restricciones en cuanto a cuándo se debe usar. No se puede llamar a _resetstkoflw desde lo siguiente:

  • Una expresión de filtro.

  • Una función de filtro.

  • Una función a la que se llama desde una función de filtro.

  • Un bloque catch.

  • Un bloque __finally.

En estos momentos, la pila no está suficientemente desenredada todavía.

Las excepciones de desbordamiento de pila se generan como excepciones estructuradas, y no excepciones de C++, por lo que _resetstkoflw no resulta útil en un bloque catch normal, porque no detectará excepciones de desbordamiento de pila. Pero si se usa _set_se_translator para implementar un traductor de excepciones estructurado que provoca excepciones de C++ (como en el segundo ejemplo), una excepción de desbordamiento de pila da lugar a una excepción de C++ que un bloque catch de C++ puede controlar.

No es seguro llamar a _resetstkoflw en un bloque catch de C++ al que se llega desde una excepción que provoca la función del traductor de excepciones estructuradas. En este caso, no se libera espacio de pila y el puntero de pila no se restablece hasta que está fuera del bloque catch, aunque se haya llamado a destructores para todos los objetos que se puedan destruir antes del bloque catch. No se debe llamar a esta función hasta que se libere espacio en la pila y se haya restablecido el puntero de la pila. Por consiguiente, solo se debe llamar después de salir del bloque catch. El menor espacio de pila posible debe usarse en el bloque catch. Un desbordamiento de pila que se produce en el bloque catch que intenta recuperarse de un desbordamiento de pila anterior no se puede recuperar. Puede hacer que el programa deje de responder, ya que el desbordamiento del bloque catch desencadena una excepción que el mismo bloque catch controla.

Hay situaciones en las que _resetstkoflw puede producir un error aunque se use en una ubicación adecuada (por ejemplo, en un bloque __except). Puede que no haya suficiente espacio de pila para ejecutarse _resetstkoflw sin escribir en la última página de la pila, incluso después de desenredar la pila. A continuación, _resetstkoflw no se puede restablecer la última página de la pila como página de protección y devuelve 0, lo que indica un error. Para que el uso de esta función sea seguro se debe comprobar el valor devuelto en lugar de suponer que la pila es segura y se puede usar.

El control de excepciones estructuradas no detectará una excepción STATUS_STACK_OVERFLOW cuando la aplicación se compila con /clr (vea /clr (compilación de Common Language Runtime)).

De manera predeterminada, el estado global de esta función está limitado a la aplicación. Para cambiar este comportamiento, consulte Estado global en CRT.

Requisitos

Routine Encabezado necesario
_resetstkoflw <malloc.h>

Para obtener más información sobre compatibilidad, consulte Compatibilidad.

Bibliotecas: todas las versiones de las características de la biblioteca de CRT.

Ejemplo

En el ejemplo siguiente se muestra el uso recomendado de la función _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;
}

Salida de ejemplo sin argumentos de programa:

loop #1

El programa deja de responder sin ejecutar otras iteraciones.

Con 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

Descripción

En el ejemplo siguiente se muestra el uso recomendado de _resetstkoflw en un programa en el que las excepciones estructuradas se convierten en excepciones 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.

Consulte también

_alloca