_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.