_resetstkoflw
Zotavuje z přetečení zásobníku.
![]() |
---|
Toto API nelze použít v aplikacích, které jsou spuštěny v modulu Windows Runtime.Další informace naleznete v tématu CRT funkce nejsou podporovány s /ZW. |
int _resetstkoflw ( void );
Vrácená hodnota
Nenulová, pokud je funkce úspěšná, nula, pokud se nezdaří.
Poznámky
Funkce _resetstkoflw obnoví ze stavu přetečení zásobníku, čímž povolí programu pokračovat místo selhání se závažnou chybou výjimky programu.Pokud funkce _resetstkoflw není volána, nejsou žádné ochranné stránky po předchozí výjimce.Při dalším přetečení zásobníku nebudou vůbec žádné výjimky a proces skončí bez varování.
Pokud vlákno v aplikaci způsobí výjimku EXCEPTION_STACK_OVERFLOW, vlákno opustí svůj zásobník v poškozeném stavu.To se liší od jiných výjimek, jako je EXCEPTION_ACCESS_VIOLATION nebo EXCEPTION_INT_DIVIDE_BY_ZERO, kde zásobník není poškozen.Zásobník je nastaven na libovolně malou hodnotu při prvním načtení programu.Zásobník pak roste na požádání, aby vyhověl potřebám vlákna.To je implementováno umístěním stránky s přístupem PAGE_GUARD na konec aktuálního zásobníku.Další informace naleznete v tématu Vytváření ochranné stránky.
Pokud kód způsobí, že ukazatel zásobníku ukazuje 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ánce tak, aby vlákno mohlo číst a zapisovat data do paměti.
Přidělí novou ochrannou stránku, která je umístěna jednu stránku za poslední stránkou.
Znovu spustí operaci, která způsobila výjimku.
Tímto způsobem může systém zvětšit velikost zásobníku pro vlákno automaticky.Každé vlákno v procesu má maximální velikost zásobníku.Velikost zásobníku je nastavena v čase kompilace pomocí příkazu /STACK (přidělení zásobníku) nebo VELIKOST ZÁSOBNÍKU v souboru .def projektu.
Při překročení maximální velikosti zásobníku systém provede následující tři věci:
Odstraní ochranu PAGE_GUARD na stránce guard, jak je uvedeno výše.
Pokusí se o přidělení nové stránky guard pod poslední.Nicméně to se nezdaří, protože byla překročena maximální velikost zásobníku.
Vyvolá výjimku, takže ji vlákno může zpracovat v bloku výjimky.
Všimněte si, že v tomto okamžiku, zásobník již nemá ochrannou stránku.Příště, až program rozšíří zásobník až na konec, kde by měla být ochranná stránka, program zapíše za konec zásobníku a způsobí narušení přístupu.
Volání _resetstkoflw k obnovení ochranné stránky při každém provedení obnovení po výjimce přetečení zásobníku.Tato funkce může být volána zevnitř hlavní části bloku __except nebo zvnějšku bloku __except .Existují však některá omezení, kdy by mělo být používáno._resetstkoflw by neměl být nikdy volán z:
Výraz filtru.
Funkce filtru.
Funkce volána z funkce filtru.
Blok zachycení.
Blok __finally.
V těchto bodech zásobník ještě není dostatečně oddělen.
Výjimky přetečení zásobníku jsou generovány jako strukturované výjimky, ne výjimky jazyka C++, takže _resetstkoflw není k ničemu v běžném bloku catch, protože nezachytí výjimku přetečení zásobníku.Nicméně pokud je _set_se_translator použit k implementaci překladače strukturovaných výjimek, který vyvolá výjimky C++ (viz druhý příklad), výjimka přetečení zásobníku povede k výjimce C++, která může být zpracována v bloku catch C++.
Není bezpečné volat rsetstkoflw v bloku catch jazyka C++, který je dosažen z výjimky vyvolané funkcí překladače 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 není mimo blok catch, přestože destruktory byly volány pro zničitelné objekty před blokem catch.Dokud není uvolněno místo v zásobníku a ukazatel zásobníku nebyl obnoveno, neměla by být tato funkce volána.Proto by měla být volána jedině po ukončení bloku catch.V bloku zachycení by mělo být použito co nejméně místa zásobníku, protože přetečení zásobníku, ke kterému dochází v bloku zachycení, který se sám pokouší o obnovení z předchozí přetečení zásobníku, není obnovitelné a může způsobit, že program přestane reagovat, jak přetečení v bloku zachycení vyvolá výjimku, která je zpracována stejným blokem zachycení.
Existují situace, kde _resetstkoflw může selhat, i když je použito na správném místě, například v bloku __except.Pokud ani po uvolnění zásobníku stále není dostatek místa k provedení _resetstkoflw bez zápisu do poslední stránky zásobníku, _resetstkoflw se nezdaří obnovit poslední stránku zásobníku jako ochrannou stránku a vrátí hodnotu 0 označující selhání.Proto by bezpečné používání této funkce mělo zahrnovat kontrolu návratové hodnoty, a nepředpokládat, že zásobník je bezpečné používat.
Strukturované zpracování výjimek nezachytí výjimku STATUS_STACK_OVERFLOW v případě, že aplikace je kompilována s /clr nebo /clr:pure (viz /clr (Common Language Runtime)).
Požadavky
Rutina |
Požadované záhlaví |
---|---|
_resetstkoflw |
<malloc.h> |
Další informace o kompatibilitě naleznete v tématu Kompatibilita.
Knihovny: Všechny verze běhových knihoven Funkce knihovny CRT.
Příklad
Následující příklad ukazuje doporučené použití funkce _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;
}
Výstup ukázky
Bez argumentů programu:
loop #1
Program přestane reagovat bez provedení dalších iterací.
S argumenty 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
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;
}
Výstup ukázky
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. Pokud chcete volat standardní funkci jazyka C, použijte PInvoke. Další informace naleznete v tématu Příklady vyvolání platformy.