_resetstkoflw
Odzyskuje z przepełnienia stosu.
Ważne |
---|
Tego API nie można używać w aplikacjach korzystających ze środowiska wykonawczego Windows.Aby uzyskać więcej informacji, zobacz Funkcje CRT nieobsługiwane przez /ZW. |
int _resetstkoflw ( void );
Wartość zwracana
Niezerowe, jeśli funkcja się powiedzie, zero, jeśli nie.
Uwagi
Funkcja _resetstkoflw powraca ze stanu przepełnienia stosu, pozwalając programowi na kontynuowanie zamiast zakończenia pracy, zwracając błąd wyjątku krytycznego.Jeśli funkcja _resetstkoflw nie jest wywoływana, nie ma żadnych stron zabezpieczenia po poprzednim wyjątku.Przy następnym przepełnieniu stosu nie wystąpią żadne wyjątki, a proces zakończy się bez ostrzeżenia.
Jeśli wątek w aplikacji powoduje wyjątek EXCEPTION_STACK_OVERFLOW, wątek opuścił stos w stanie uszkodzonym.Jest to w przeciwieństwie do innych wyjątków takich jak EXCEPTION_ACCESS_VIOLATION lub EXCEPTION_INT_DIVIDE_BY_ZERO, gdy stos nie jest uszkodzony.Stos jest ustawiony na arbitralnie małej wartości, gdy program jest ładowany.Stos następnie rośnie na żądanie do potrzeb wątku.To jest zaimplementowane przez umieszczenie strony z dostępem do PAGE_GUARD na końcu bieżącego stosu.Aby uzyskać więcej informacji, zobacz Tworzenie stron ochrony.
Gdy kod powoduje, że wskaźnik stosu wskazuje adres na tej stronie, wystąpi wyjątek, a system wykonuje następujące trzy rzeczy:
Usuwa ochronę PAGE_GUARD na stronie ochrony, tak aby wątek mógł czytać i zapisywać dane do pamięci.
Przydziela nową stronę ochronną, która znajduje się jedną stronę poniżej ostatniej strony.
Umożliwia ponowne wykonanie instrukcji, która wywołała wyjątek.
W ten sposób system może automatycznie zwiększyć rozmiar stosu dla wątku.Każdy wątek w procesie ma rozmiar maksymalny stosu.Rozmiar stosu jest ustawiony w czasie kompilacji przez /STACK (Twórz stos z alokacji), lub STACKSIZE instrukcja w pliku o rozszerzeniu def dla projektu.
Po przekroczeniu tej wielkości maksymalnej stosu, system wykonuje następujące czynności:
Usuwa ochronę PAGE_GUARD na stronie ochrony w sposób opisany wcześniej.
Próbuje przydzielić nowe strony strażnika poniżej ostatniej z nich.Jednak to się nie powiedzie, ponieważ przekroczono maksymalny rozmiar stosu.
Zgłasza wyjątek, tak aby wątek mógł go obsłużyć w bloku wyjątków.
Należy zauważyć, że w tym momencie stos nie ma już strony ochronnej.Następnym razem, gdy program rozwija stos aż do końca, tam gdzie powinna być strona ochrona, program zapisuje poza końcem stosu i powoduje naruszenie zasad dostępu.
Wywołaj _resetstkoflw, aby przywrócić stronę ochronną przy każdym odzyskiwaniu po wystąpieniu wyjątku przepełnienia stosu.Ta funkcja może zostać wywołana z wnętrza głównego tekstu __except bloku lub poza __except blokiem.Jednakże, istnieją pewne ograniczenia, kiedy należy go stosować._resetstkoflw nigdy nie powinna zostać wywołana z:
Wyrażenie filtru.
Funkcja filtrowania.
Funkcja wywoływana z funkcji filtru.
Blok catch.
Blok __finally.
W tych punktach stos nie jest jeszcze wystarczająco rozwinięty.
Wyjątki przepełnienia stosu są generowane jako wyjątki strukturalne, nie wyjątki C++, więc _resetstkoflw nie jest użyteczny w zwykłej pamięci podręcznej bloku, ponieważ nie będzie przechwytywać wyjątków przepełnienia stosu.Jednakże, jeśli _set_se_translator jest używany do implementowania translatora złożonego wyjątku, który wyrzuca wyjątki C++ (jak w drugim przykładzie), powoduje wyjątek przepełnienia stosu w wyjątku C++, który może być obsługiwany przez blok catch języka C++.
Nie jest bezpieczne wywołanie _resetstkoflw w bloku catch języka C++, który zostanie osiągnięty z wyjątku wyrzuconego przez strukturalną funkcję tłumacza wyjątków.W tym przypadku przestrzeń stosu nie jest zwalniana, a wskaźnik stosu nie jest resetowany poza blok catch, choć destruktory zostały wywołane do wszelkich obiektów zniszczalnych przed blokiem catch.Funkcja ta nie powinna być wywoływana, dopóki nie zostanie zwolnione miejsca na stosie i wskaźnik stosu nie zostanie zresetowany.Dlatego powinna zostać wywołana tylko po wyjściu bloku catch.Tak małe, jak to możliwe, miejsca na stosie powinny być używane w bloku catch, ponieważ występujące w bloku catch przepełnienie stosu, które samo w sobie „próbuje dojść do siebie” po poprzednim przepełnieniu stosu jest nie do odzyskania i może spowodować, że program przestanie odpowiadać, gdyż przepełnienie stosu w bloku catch powoduje wyjątek, który sam jest obsługiwany przez ten sam blok catch.
Istnieją sytuacje, gdzie _resetstkoflw może się nie powieść, nawet jeśli będzie używane w poprawnej lokalizacji, na przykład w ramach bloku __except .Jeśli nawet po odwinięciu stosu, wciąż brak wystarczającego obszaru stosu do wykonania _resetstkoflw bez pisania na ostatniej stronie stosu, _resetstkoflw nie może zresetować ostatniej strony stosu jako strony ochronnej i zwraca wartość 0, wskazując niepowodzenie.W związku z tym, że bezpieczne korzystanie z tej funkcji powinno obejmować sprawdzenie wartości zwracanej, a nie zakładanie, że stos jest bezpieczny w użyciu.
Obsługa wyjątków strukturalnych nie będzie przechwytywać STATUS_STACK_OVERFLOW wyjątku podczas kompilowania aplikacji z /clr lub /clr:pure (patrz /clr (Kompilacja środowiska uruchomieniowego języka wspólnego)).
Wymagania
Procedura |
Wymagany nagłówek |
---|---|
_resetstkoflw |
<malloc.h> |
Aby uzyskać więcej informacji na temat zgodności, zobacz Zgodność.
Biblioteki: Wszystkie wersje Biblioteka CRT — Funkcje.
Przykład
Poniższy przykład pokazuje rekomendowane użycie funkcji _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;
}
Przykładowe dane wyjściowe
Bez argumentów programu:
loop #1
Program przestaje odpowiadać bez dalszego wykonywania iteracji.
Bez argumentów programu:
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
Opis
W poniższym przykładzie pokazano zalecane użycie _resetstkoflw w programie, gdzie strukturalne wyjątki są konwertowane na wyjątki C++.
Kod
// 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;
}
Przykładowe dane wyjściowe
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.
Odpowiednik w programie .NET Framework
Nie dotyczy. Aby wywołać standardową funkcję C, należy użyć PInvoke. Aby uzyskać więcej informacji, zobacz Przykłady wywoływania platformy.