_resetstkoflw
Obnoví z přetečení zásobníku.
Důležité |
---|
Toto rozhraní API nelze použít v aplikacích, které jsou spuštěny v systému Windows Runtime.Další informace naleznete v tématu CRT funkce nejsou podporovány s /ZW. |
int _resetstkoflw ( void );
Vrácená hodnota
Nenulová, je-li funkce úspěšná, nula, pokud se nezdaří.
Poznámky
_resetstkoflw Funkce obnoví ze stavu přetečení zásobníku, povolení programu pokračovat místo došlo k selhání s Závažná výjimka chyba.Pokud _resetstkoflw není volána funkce, nejsou žádné stránky guard po předchozí výjimky.Při příštím se zásobníku přetečení, nejsou vůbec žádné výjimky a ukončí proces bez předchozího upozornění.
V případě, že způsobí, že podproces v aplikaci EXCEPTION_STACK_OVERFLOW výjimka, vlákno opustil svůj zásobník poškozeného státu.Tím se liší od další výjimky, jako například EXCEPTION_ACCESS_VIOLATION nebo EXCEPTION_INT_DIVIDE_BY_ZERO, kde není poškozen zásobník.Zásobník je nastavena na libovolně malou hodnotu, při prvním načtení programu.Zásobník pak roste na požádání potřebám vlákna.To je implementována umístěním stránky s PAGE_GUARD přístup na konci aktuálního zásobníku.Další informace naleznete v tématu Vytváření stránek Guard.
Pokud kód způsobí, že ukazatel na zásobník tak, aby odkazovaly na adresu na této stránce, dojde k výjimce a systém provede následující tři věci:
Odebere ochranu PAGE_GUARD na ochranná stránka tak, aby bylo vlákno může číst a zapisovat data do paměti.
Alokuje novou guard stránky je umístěn jeden pod poslední.
Znovu spustí operaci, která vyvolala výjimku.
Tímto způsobem systém může zvětšit velikost zásobníku pro vlákno automaticky.Všechny vlákna v procesu má maximální velikost zásobníku.Velikost zásobníku je nastavena v čase kompilace pomocí / ZÁSOBNÍKU (zásobník rozdělení), nebo STACKSIZE příkaz v souboru .def pro projekt.
Při překročení této maximální velikost zásobníku, systém provede následující tři věci:
Odstraní ochranu PAGE_GUARD na stránce guard podle výše uvedených pokynů.
Systém se pokusí přidělení nové stránky guard pod poslední.To však nezdaří, protože byla překročena maximální velikost zásobníku.
Vyvolá výjimku, tak, aby bylo vlákno může zpracovávat v bloku výjimky.
Všimněte si, že v daném okamžiku zásobníku již má ochranná stránka.Dalším, že program roste až do konce zásobníku v případě, že by měla být ochranná stránka, program zapíše po skončení zásobníku a způsobuje chybu narušení přístupu.
Volání _resetstkoflw Chcete-li obnovit ochranná stránka při každém obnovení se provádí po výjimka přetečení zásobníku.Tuto funkci lze volat z hlavní části __except bloku nebo vnější __except bloku.Existují však některá omezení při by mělo být používáno._resetstkoflwby měl být nikdy volán z:
Výraz filtru.
Funkce filter.
Funkce je volána z funkce filter.
A catch bloku.
A __finally block.
V těchto místech zásobníku ještě není dostatečně pokračuj.
Výjimky přetečení zásobníku jsou generovány jako strukturované výjimky nejsou výjimky C++ tak, aby _resetstkoflw hodí není běžný catch blokovat, protože nebude zachytit výjimky přetečení zásobníku.Nicméně pokud _set_se_translator je používána k implementaci strukturované výjimky překladač, který vyvolá C++ výjimky (viz druhý příklad), výsledkem výjimka přetečení zásobníku výjimek v C++, která může být zpracována v bloku catch C++.
Není bezpečné volat _resetstkoflw v bloku catch C++, který je dosaženo z výjimku vyvolanou překladač funkce strukturované výjimky.V tomto případě není uvolněn prostor v zásobníku a ukazatel na zásobník není vynulován dokud mimo blok catch, přestože destruktory zavolání pro všechny zničitelné objekty před blok catch.Tato funkce by neměl volat, až uvolnění prostoru v zásobníku a ukazatel na zásobník byl resetován.Proto by měla být volána pouze po ukončení bloku catch.Co trochu místa v zásobníku a možná by měla sloužit blok catch, protože přetečení zásobníku, ke kterému dochází v bloku catch, který je sám pokus o obnovení z předchozí přetečení zásobníku je možné příčiny, které program přestane reagovat při přetečení v bloku catch vyvolá výjimku, která sama má na starosti stejné catch blokem.
Existují situace, kde _resetstkoflw může selhat, i v případě, že použití správné místo, například v rámci __except bloku.Je-li i po unwind zásobníku, je stále není dostatek místa v zásobníku vlevo k provedení _resetstkoflw bez psaní do poslední stránky zásobníku, _resetstkoflw se nepodařilo obnovit poslední stránku zásobníku jako ochranná stránka a vrátí hodnotu 0, označující selhání.Proto bezpečné používání této funkce by měl zahrnovat kontrolu vrácenou hodnotu, za předpokladu, že zásobník je bezpečně používat.
Strukturované zpracování výjimek nezachytí STATUS_STACK_OVERFLOW výjimka v případě, že aplikace je kompilována s /clr nebo /clr:pure (viz /CLR (kompilace společné Language Runtime)).
Požadavky
Byla zahájena rutina |
Požadované záhlaví |
---|---|
_resetstkoflw |
<malloc.h> |
Další informace o kompatibilitě v tématu Kompatibilita v úvodu.
Knihovny: všech verzí Funkce knihovny CRT.
Příklad
Následující příklad ukazuje doporučené použití _resetstkoflw funkce.
// 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;
}
Vzorový výstup
Bez argumentů programu:
loop #1
Aplikace přestane reagovat bez dalšího spuštění iterací.
Pomocí programu argumenty:
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
Description
Následující příklad ukazuje doporučené použití _resetstkoflw v programu, kde jsou strukturované výjimky převedeny na výjimky C++.
Kód
// 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;
}
Vzorový výstup
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.
Ekvivalent v rozhraní .NET Framework
Nelze použít Volání funkce standardním C pomocí PInvoke. Další informace naleznete v tématu Platformu vyvolání příklady.