Condividi tramite


_resetstkoflw

Recupera dall'overflow dello stack.

Importante

Non è possibile usare questa API nelle applicazioni eseguite in Windows Runtime. Per altre informazioni, vedere Funzioni CRT non supportate nelle app della piattaforma UWP (Universal Windows Platform).

Sintassi

int _resetstkoflw( void );

Valore restituito

Diverso da zero se la funzione ha esito positivo, zero se ha esito negativo.

Osservazioni:

La funzione _resetstkoflw esegue il ripristino da una condizione di overflow dello stack, consentendo di continuare l'esecuzione di un programma anziché interromperlo con un errore di eccezione irreversibile. Se la _resetstkoflw funzione non viene chiamata, non sono presenti pagine di protezione dopo l'eccezione precedente. La volta successiva che è presente un overflow dello stack, non sono presenti eccezioni e il processo termina senza avviso.

Se un thread in un'applicazione causa un'eccezione EXCEPTION_STACK_OVERFLOW , il thread ha lasciato lo stack in uno stato danneggiato. Questa eccezione è diversa da altre eccezioni, EXCEPTION_ACCESS_VIOLATION ad esempio o EXCEPTION_INT_DIVIDE_BY_ZERO, in cui lo stack non è danneggiato. Lo stack è impostato su un valore arbitrario piccolo quando il programma viene caricato per la prima volta. Lo stack poi cresce su richiesta per soddisfare le esigenze del thread. La crescita su richiesta viene implementata inserendo una pagina con PAGE_GUARD accesso alla fine dello stack corrente. Per altre informazioni, vedere Creazione di pagine di protezione.

Quando il codice porta il puntatore dello stack a puntare a un indirizzo di questa pagina, si verifica un'eccezione e il sistema esegue le tre seguenti cose:

  • Rimuove la PAGE_GUARD protezione nella pagina di protezione in modo che il thread possa leggere e scrivere dati nella memoria.

  • Alloca una nuova pagina di protezione che è localizzata una pagina sotto l'ultima.

  • Riesegue l'istruzione che ha generato l'eccezione.

In questo modo, il sistema può aumentare automaticamente la dimensione dello stack per il thread. Ogni thread in un processo ha una dimensione dello stack massima. Le dimensioni dello stack vengono impostate in fase di compilazione dall'opzione /STACK (Allocazioni stack) o dall'istruzione STACKSIZE nel .def file per il progetto.

Quando la dimensione dello stack massima viene superata, il sistema esegue le tre cose seguenti:

  • Rimuove la protezione di PAGE_GUARD nella pagina di protezione, come descritto in precedenza.

  • Tenta di allocare una nuova pagina di protezione sotto l'ultima. Tuttavia, l'allocazione non riesce perché è stata superata la dimensione massima dello stack.

  • Genera un'eccezione in modo che il thread possa gestirla nel blocco di eccezioni.

A questo punto, lo stack non ha più una pagina di protezione. La volta successiva che il programma aumenta lo stack in cui scrive oltre la fine dello stack, causa una violazione di accesso.

Chiamare _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 dall'interno del corpo principale di un __except blocco o all'esterno di un __except blocco. Tuttavia, esistono alcune limitazioni sui casi in cui deve essere utilizzata. _resetstkoflw non deve essere chiamato da:

  • Un'espressione di filtro.

  • Una funzione di filtro.

  • Una funzione chiamata da una funzione di filtro.

  • Un blocco catch.

  • Un blocco __finally.

A questi punti, lo stack non è ancora sufficientemente scollegato.

Le eccezioni di overflow dello stack vengono generate come eccezioni strutturate, non eccezioni C++, quindi _resetstkoflw non è utile in un blocco ordinario catch perché non intercetta un'eccezione di overflow dello stack. Tuttavia, se _set_se_translator viene usato per implementare un traduttore di eccezioni strutturate che genera eccezioni C++ (come nel secondo esempio), un'eccezione di overflow dello stack genera un'eccezione C++ che può essere gestita da un blocco catch C++.

Non è sicuro chiamare _resetstkoflw in un blocco catch C++ raggiunto da un'eccezione generata dalla funzione di traduzione delle eccezioni strutturata. 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 sono stati chiamati distruttori per qualsiasi oggetto distruttore prima del blocco catch. Questa funzione non deve essere chiamata fino a quando lo spazio dello stack non viene liberato e il puntatore dello stack è stato reimpostato. Pertanto, deve essere chiamata solo dopo l'uscita dal blocco catch. Il minor spazio possibile nello stack deve essere usato nel blocco catch. Un overflow dello stack che si verifica nel blocco catch che sta tentando di eseguire il ripristino da un overflow dello stack precedente non è recuperabile. Può causare l'arresto della risposta del programma, perché l'overflow nel blocco catch attiva un'eccezione gestita dallo stesso blocco catch.

In alcune situazioni _resetstkoflw può verificarsi un errore anche se usato in una posizione corretta, ad esempio all'interno di un __except blocco. Potrebbe non essere disponibile spazio dello stack sufficiente per l'esecuzione _resetstkoflw senza scrivere nell'ultima pagina dello stack, anche dopo la rimozione dello stack. Quindi, _resetstkoflw non riesce a reimpostare l'ultima pagina dello stack come pagina di protezione e restituisce 0, a indicare un errore. L'utilizzo sicuro di questa funzione deve includere il controllo del valore restituito invece di presupporre che lo stack sia sicuro da usare.

La gestione delle eccezioni strutturate non intercetta un'eccezione STATUS_STACK_OVERFLOW quando l'applicazione viene compilata con /clr (vedere /clr (Compilazione Common Language Runtime).

Per impostazione predefinita, lo stato globale di questa funzione è limitato all'applicazione. Per modificare questo comportamento, vedere Stato globale in CRT.

Requisiti

Ciclo Intestazione obbligatoria
_resetstkoflw <malloc.h>

Per altre informazioni sulla compatibilità, vedere Compatibility (Compatibilità).

Librerie: tutte le versioni delle funzionalità della libreria CRT.

Esempio

L'esempio riportato di seguito mostra l'utilizzo consigliato della funzione _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;
}

Output di esempio senza argomenti di programma:

loop #1

Il programma non risponde senza eseguire ulteriori iterazioni.

Con 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 raccomandato di _resetstkoflw 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;
}
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.

Vedi anche

_alloca