Freigeben über


_resetstkoflw

Führt nach einem Stapelüberlauf eine Wiederherstellung durch.

Wichtig

Diese API kann nicht in Anwendungen verwendet werden, die in Windows-Runtime ausgeführt werden. Weitere Informationen finden Sie im Artikel CRT functions not supported in Universal Windows Platform apps (In Apps für die universelle Windows-Plattform nicht unterstützte CRT-Funktionen).

Syntax

int _resetstkoflw( void );

Rückgabewert

Bei erfolgreicher Funktion ist der Wert ungleich 0 (null), sonst Null.

Hinweise

Die _resetstkoflw-Funktion sorgt nach Stapelüberläufen für eine Wiederherstellung, sodass ein Programm fortgesetzt werden kann, statt mit einem schwerwiegenden Ausnahmefehler fehlzuschlagen. Wenn die _resetstkoflw Funktion nicht aufgerufen wird, gibt es nach der vorherigen Ausnahme keine Schutzseiten. Wenn es das nächste Mal einen Stapelüberlauf gibt, gibt es überhaupt keine Ausnahmen, und der Prozess wird ohne Warnung beendet.

Wenn ein Thread in einer Anwendung eine EXCEPTION_STACK_OVERFLOW Ausnahme verursacht, hat der Thread seinen Stapel in einem beschädigten Zustand verlassen. Diese Ausnahme unterscheidet sich von anderen Ausnahmen wie EXCEPTION_ACCESS_VIOLATION z. B. oder EXCEPTION_INT_DIVIDE_BY_ZERO, bei denen der Stapel nicht beschädigt ist. Der Stapel ist auf einen beliebig kleinen Wert festgelegt, wenn das Programm das erste Mal geladen wird. Der Stapel vergrößert sich dann bei Bedarf, um die Anforderungen des Threads zu erfüllen. On-Demand-Wachstum wird implementiert, indem eine Seite mit PAGE_GUARD Zugriff am Ende des aktuellen Stapels platziert wird. Weitere Informationen finden Sie unter Erstellen von Schutzseiten.

Wenn der Code den Stapelzeiger veranlasst, auf eine Adresse auf dieser Seite zu zeigen, wird eine Ausnahme ausgelöst und das System führt die folgenden drei Schritte durch:

  • Entfernt den PAGE_GUARD Schutz auf der Schutzseite, damit der Thread Daten im Arbeitsspeicher lesen und schreiben kann.

  • Zuordnen einer neuen Schutzseite, die sich eine Seite unterhalb der letzten befindet.

  • Wiederholen der Anweisung, die die Ausnahme ausgelöst hat.

Auf diese Weise kann das System die Größe des Stapels für den Thread automatisch erhöhen. Jeder Thread in einem Prozess hat eine maximale Stapelgröße. Die Stapelgröße wird zur Kompilierungszeit durch die /STACK Option (Stack Allocations) oder durch die Anweisung in der .def STACKSIZE Datei für das Projekt festgelegt.

Wenn die maximale Stapelgröße überschritten wird, führt das System die folgenden drei Schritte aus:

  • Entfernen des PAGE_GUARD-Schutzes auf der Schutzseite, wie zuvor beschrieben.

  • Versuchen, eine neue Schutzseite unterhalb des letzten zuzuweisen. Die Zuordnung schlägt jedoch fehl, da die maximale Stapelgröße überschritten wurde.

  • Auslösen einer Ausnahme, sodass der Thread diese im Ausnahmeblock behandeln kann.

An diesem Punkt verfügt der Stapel nicht mehr über eine Schutzseite. Wenn das Programm das nächste Mal den Stapel vergrößert, auf den er über das Ende des Stapels schreibt, verursacht es eine Zugriffsverletzung.

Rufen Sie _resetstkoflw auf, um die Schutzseite wiederherzustellen, wenn die Wiederherstellung nach einer Stapelüberlauf-Ausnahme ausgeführt wird. Diese Funktion kann innerhalb des Haupttexts eines __except Blocks oder außerhalb eines __except Blocks aufgerufen werden. Es gibt jedoch einige Einschränkungen hinsichtlich der Verwendung. _resetstkoflw sollte nicht von:

  • einem Filterausdruck

  • einer Filterfunktion

  • einer Funktion, die von einer Filterfunktion aufgerufen wurde.

  • Einem catch-Block.

  • Einem __finally-Block.

An diesen Stellen ist der Stapel noch nicht ausreichend aufgewockt.

Stapelüberlaufausnahmen werden als strukturierte Ausnahmen und nicht als C++-Ausnahmen generiert. Dies ist daher _resetstkoflw in einem normalen catch Block nicht hilfreich, da sie keine Stapelüberlaufausnahme abfangen wird. Wenn _set_se_translator jedoch zum Implementieren eines strukturierten Ausnahmeübersetzers verwendet wird, der C++-Ausnahmen auslöst (wie im zweiten Beispiel), führt eine Stapelüberlaufausnahme zu einer C++-Ausnahme, die von einem C++-Catch-Block behandelt werden kann.

Es ist nicht sicher, einen C++-Catch-Block aufzurufen _resetstkoflw , der von einer Ausnahme erreicht wird, die von der strukturierten Ausnahmeübersetzerfunktion ausgelöst wird. In diesem Fall wird der Stapelbereich nicht freigegeben, und der Stapelzeiger wird erst zurückgesetzt, wenn außerhalb des Catch-Blocks Destruktoren für destruktible Objekte vor dem Catch-Block aufgerufen wurden. Diese Funktion sollte erst aufgerufen werden, wenn der Stapelplatz freigegeben wird und der Stapelzeiger zurückgesetzt wurde. Daher sollte sie erst nach dem Beenden des Catch-Blocks aufgerufen werden. So wenig Stapelplatz wie möglich sollte im Catch-Block verwendet werden. Ein Stapelüberlauf, der im Catch-Block auftritt, der selbst versucht, aus einem vorherigen Stapelüberlauf wiederherzustellen, kann nicht wiederhergestellt werden. Es kann dazu führen, dass das Programm nicht mehr reagiert, da der Überlauf im Catch-Block eine Ausnahme auslöst, die von demselben Catch-Block selbst behandelt wird.

Es gibt Situationen, in denen _resetstkoflw Fehler auftreten können, auch wenn sie an einer richtigen Stelle verwendet werden, z. B. innerhalb eines __except Blocks. Es ist möglicherweise nicht genügend Stapelplatz vorhanden, um ausgeführt zu werden, ohne in die letzte Seite des Stapels zu schreiben _resetstkoflw , auch nach dem Entspannen des Stapels. _resetstkoflw Anschließend kann die letzte Seite des Stapels nicht als Schutzseite zurückgesetzt werden, und gibt "0" zurück, was auf einen Fehler hinweist. Die sichere Verwendung dieser Funktion sollte die Überprüfung des Rückgabewerts umfassen, anstatt davon auszugehen, dass der Stapel sicher zu verwenden ist.

Die strukturierte Ausnahmebehandlung fängt STATUS_STACK_OVERFLOW keine Ausnahme ab, wenn die Anwendung kompiliert /clr wird (siehe /clr (siehe Common Language Runtime Compilation).)

Standardmäßig gilt der globale Zustand dieser Funktion für die Anwendung. Wie Sie dieses Verhalten ändern, erfahren Sie unter Globaler Status in der CRT.

Anforderungen

Routine Erforderlicher Header
_resetstkoflw <malloc.h>

Weitere Informationen zur Kompatibilität finden Sie unter Kompatibilität.

Bibliotheken: Alle Versionen der CRT-Bibliotheksfeatures.

Beispiel

Das folgende Beispiel zeigt die empfohlene Verwendung der _resetstkoflw-Funktion.

// 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;
}

Beispielausgabe ohne Programmargumente:

loop #1

Das Programm reagiert nicht mehr, ohne weitere Iterationen auszuführen.

Mit Programmargumenten:

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

Beschreibung

Das folgenden Beispiel zeigt die empfohlene Verwendung von _resetstkoflw in einem Programm, in dem strukturierte Ausnahmen in C++-Ausnahmen konvertiert werden.

Code

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

Siehe auch

_alloca