_resetstkoflw
Recupera da overflow dello stack.
Importante |
---|
Questa API non può essere utilizzata nelle applicazioni che vengono eseguite in Windows Runtime.Per ulteriori informazioni, vedere Funzioni CRT non supportate con /ZW. |
int _resetstkoflw ( void );
Valore restituito
Diverso da zero se la funzione ha esito positivo, zero se non riesce.
Note
La funzione _resetstkoflw consente di recuperare da una condizione di overflow dello stack, consentendo a un programma di continuare invece di restituire un errore di eccezione irreversibile.Se la funzione di _resetstkoflw non viene chiamata, non vi sono pagine di protezione dopo l'eccezione precedente.Al successivo overflow dello stack non ci sarà alcuna eccezione e il processo terminerà senza alcun avviso.
Se un thread in un'applicazione genera un'eccezione EXCEPTION_STACK_OVERFLOW, il thread lasciato il relativo stack in uno stato danneggiato.Ciò si differenzia da altre eccezioni come EXCEPTION_ACCESS_VIOLATION o EXCEPTION_INT_DIVIDE_BY_ZERO, in cui lo stack non è danneggiato.Lo stack viene impostata su un valore arbitrario piccolo se il programma viene caricato.Lo stack si compila su richiesta per soddisfare le esigenze di thread.Questo editor viene implementato inserendo una pagina con accesso di PAGE_GUARD alla fine dello stack corrente.Per ulteriori informazioni, vedere Creare pagine di protezione.
Quando il codice indica il puntatore dello stack a indicare un indirizzo di questa pagina, si verifica un'eccezione e il sistema esegue le tre operazioni:
Rimuovere la protezione di PAGE_GUARD nella pagina di protezione in modo da poter leggere e scrivere il thread i dati in memoria.
Alloca una pagina del nuovo elemento guard situata una pagina in quella più recente.
Riesegue l'istruzione che ha generato l'eccezione.
In questo modo, è possibile aumentare la dimensione dello stack per il thread automaticamente.Ogni thread di un processo ha una dimensione dello stack massima.La dimensione dello stack viene impostata in fase di compilazione da /STACK (Allocazioni stack), o dall'istruzione di STACKSIZE nel file def per il progetto.
Quando la dimensione dello stack massima consentita, il sistema esegue le tre operazioni:
Rimuovere la protezione di PAGE_GUARD nella pagina di protezione, come descritto in precedenza.
Tenta di allocare una pagina del nuovo elemento guard in quella più recente.Tuttavia, questo non viene superato perché la dimensione dello stack massima è stata superata.
Genera un'eccezione in modo che gestisce il thread nel blocco di eccezioni.
Si noti che, a questo punto, lo stack non ha più una pagina di protezione.La volta successiva che il programma ingrandito lo stack fino all'estremità, in cui deve essere disponibile una pagina di protezione, il programma scrive oltre la fine dello stack e provoca una violazione di accesso.
Chiamata _resetstkoflw per ripristinare la pagina di protezione ogni volta che il ripristino viene eseguito dopo un'eccezione di overflow dello stack.Questa funzione può essere chiamata dalla parte principale di un blocco o di un esterno di un __except del blocco __except .Tuttavia, esistono alcune limitazioni su quando devono essere utilizzati._resetstkoflw non deve essere mai chiamato da:
Un'espressione di filtro.
Una funzione di filtro.
Una funzione chiamata da una funzione di filtro.
Un blocco raccolta.
Un blocco di __finally.
A questi punti, lo stack ancora sufficientemente non viene rimosso.
Le eccezioni di overflow dello stack quando vengono generate le eccezioni strutturate, non eccezioni C++, in modo da _resetstkoflw non è utile in un blocco comune raccolta perché non rileverà un'eccezione di overflow dello stack.Tuttavia, se _set_se_translator viene utilizzato per implementare un convertitore strutturato di eccezione che genera eccezioni C++ (come nel secondo esempio), un'eccezione di overflow dello stack genera l'eccezione c++ che può essere gestita dal blocco catch c++.
Non è possibile chiamare _resetstkoflw in blocco catch c++ che viene raggiunto da un'eccezione generata dalla funzione di conversione strutturata delle eccezioni.In questo caso, lo spazio dello stack non viene liberato e il puntatore dello stack non viene reimpostato fino all'esterno del blocco catch, anche se i distruttori sono stati definiti per tutti gli oggetti distruttibili prima del blocco catch.Questa funzione non deve essere chiamata solo a liberare spazio dello stack e il puntatore dello stack sia stato reimpostato.Pertanto, è necessario chiamare solo dopo uscire dal blocco catch.Sebbene poco spazio dello stack possibile utilizzarlo nel blocco catch perché un overflow dello stack che si verifica nel blocco catch che stesso tenta di recuperare da un overflow dello stack precedente non reversibile e può determinare un programma a non rispondere quando un overflow nel blocco catch attiva un'eccezione che a sua volta è gestito dallo stesso blocco catch.
In alcune situazioni _resetstkoflw può avere esito negativo anche se utilizzato in una posizione corretta, ad esempio in un blocco __except di.Se, anche dopo la rimozione dello stack, non esiste ancora sufficientemente spazio dello stack possibile eseguire _resetstkoflw senza scrivere nell'ultima pagina dello stack, _resetstkoflw non riesce a reimpostare l'ultima pagina dello stack come pagina di protezione e restituisce 0, che indica l'errore.Pertanto, l'utilizzo sicuro della funzione deve includere controllare il valore restituito anziché presupporre che lo stack sia sicuro da utilizzare.
La gestione delle eccezioni strutturata non rileverà un'eccezione di STATUS_STACK_OVERFLOW quando l'applicazione viene compilata con /clr o /clr:pure ( /clr (Compilazione Common Language Runtime)vedere).
Requisiti
Routine |
Intestazione obbligatoria |
---|---|
_resetstkoflw |
<malloc.h> |
Per ulteriori informazioni sulla compatibilità, vedere Compatibilità.
Raccolte: tutte le versioni di Funzionalità della libreria CRT.
Esempio
Nell'esempio seguente viene illustrato l'utilizzo consigliato della funzione di _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;
}
Esempio di output
Senza argomenti del programma:
loop #1
Il programma non risponde senza eseguire ulteriori iterazioni.
Con gli argomenti del programma:
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
Descrizione
Nell'esempio seguente viene illustrato l'utilizzo di _resetstkoflw consigliato in un programma in cui le eccezioni strutturate vengono convertite in eccezioni C++.
Codice
// 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;
}
Esempio di output
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.
Equivalente .NET Framework
Non applicabile. Per chiamare la funzione standard C, utilizzare PInvoke. Per ulteriori informazioni, vedere Esempi di Invocazione della Piattaforma.