_resetstkoflw
从堆栈溢出还原。
重要
此 API 不能在运行时的窗口执行的应用程序。有关更多信息,请参见 CRT 函数不支持与 /ZW。
int _resetstkoflw ( void );
返回值
非零,如果函数成功,零;如果失败。
备注
_resetstkoflw 函数可以将系统从堆栈溢出的情况恢复为正常,从而使程序得以继续运行,而不会由于出现异常错误而失败。 如果 _resetstkoflw 函数中调用,不显示保护页在上一个异常后。 当下次发生堆栈溢出时,根本不会显示异常,进程将在没有任何警告的情况下终止。
如果应用程序中的线程导致 EXCEPTION_STACK_OVERFLOW 异常,线程在一个损坏的状态将其堆栈保留。 与其他异常是例如 EXCEPTION_ACCESS_VIOLATION 或 EXCEPTION_INT_DIVIDE_BY_ZERO,这是,不损坏堆栈。 当程序首先加载时,堆栈设置为一个随机小的值。 堆栈然后增大在需要时调整线程的需要。 这是通过放置一 PAGE_GUARD 访问的页实现在当前堆栈的末尾。 有关更多信息,请参见 创建显示保护页。
当代码导致堆栈指针指向本页中的一个地址,则会发生异常,并且该系统进行以下三个操作:
移除在显示保护页的 PAGE_GUARD 保护,以便线程可以读取和写入数据到内存中。
分配定位在最后一个下的页的新显示保护页。
重新运行引发异常的命令。
这样,系统会为线程自动增加堆栈大小。 进程中的每个线程都具有最大堆栈大小。 堆栈大小设置在生成时 /STACK(堆栈分配),或者跟在 .def 文件中 STACKSIZE 语句该项的。
当此最大堆栈大小超过时,系统将进行以下三个操作:
移除在显示保护页的 PAGE_GUARD 保护,如。
尝试在最后一个下分配新显示保护页。 但是,在中,因为最大堆栈大小超过了,则失败。
引发异常,以便线程可以处理它在异常块。
请注意,此时,堆栈没有显示保护页。 下次程序始终增大堆栈的末尾,应具有显示保护页、程序编写在堆栈尾以外的和导致访问冲突。
调用 _resetstkoflw 还原显示保护页,只要以堆栈溢出异常后完成。 此功能可从 __except 的主体内调用块或 __except 块的外部。 但是,时,应使用时,有一些限制在它。 不应调用**_resetstkoflw** 从:
筛选器表达式。
筛选功能。
从筛选器函数调用的函数。
Catch 块。
__finally 块。
在这些点,堆栈完全不会展开。
堆栈溢出异常生成,因为结构化异常,而不是 C++ 异常,因此,_resetstkoflw 没有用在普通的 Catch 块,因为它将不捕获溢出异常。 但是,因此,如果 _set_se_translator 用于实现 C++ 引发一个异常的结构化异常转换器 (在第二个示例中所示),堆栈溢出异常会导致可以由 c. c++ catch 处理块的 c. c++ 异常。
调用从结构化异常转换器函数引发的异常达到 c. c++ 捕获的 _resetstkoflw 块是不安全的。 在这种情况下,堆栈空间不会释放,并且堆栈指针没有在执行 catch 块外将重置,直到块,因此,即使析构函数为所有可损坏的对象调用,在 catch 块之前。 不应调用此函数,直到堆栈空间被释放,并重置堆栈指针。 因此,应在退出 catch 之后调用它将阻止。 为可能的 ACE 堆栈空间应使用 catch 块,因为在自身发生尝试从前面的堆栈溢出还原 catch 的堆栈溢出块不可退回的,并且可能导致程序停止响应,在执行 catch 块中的溢出块触发器本身由同一 catch 处理块的异常。
具有 _resetstkoflw 在正确的位置可能失败的情况,即使使用,如中 __except 块。 如果为,则在展开堆栈后,仍不留下的足够的堆栈空间执行 _resetstkoflw 不写入堆栈的最后一页,_resetstkoflw 无法重新设置堆栈的最后一页,因为显示保护页并返回 0,指示失败。 因此,此功能安全的用法应包括检查返回值而不是假定,堆栈是安全漏洞。
结构化异常处理将不捕获 STATUS_STACK_OVERFLOW 异常,则应用程序编译 /clr 或 /clr:pure (请参见 /clr(公共语言运行时编译))。
要求
实例 |
必需的标头 |
---|---|
_resetstkoflw |
<malloc.h> |
有关更多兼容性信息,请参见中介绍的 兼容性。
库:CRT库功能的所有版本。
示例
下面的示例演示 _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;
}
示例输出
没有过程参数:
loop #1
程序停止响应,而无需执行进一步迭代。
过程参数:
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
描述
下面的示例在结构化异常转换为 C++ 异常的程序显示给 _resetstkoflw 的建议使用。
代码
// 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.
.NET Framework 等效项
不适用。若要调用标准 C 函数,请使用 PInvoke。有关更多信息,请参见 平台调用示例。