我在StackOverflow和CodeProject.net上阅读了很多关于SEH exceptions
的文章。
在我的C ++程序中实现SEH exceptions
处理后,我受到堆栈溢出异常的影响,我的软件没有捕获它。
经过下一部分研究后我明白,以编程方式检测这种异常是不可能的,因为我们没有可用的堆栈地址空间,因此程序内存已损坏。
我想问你有关处理堆栈溢出异常的经验。它看起来像是一个挑战,如果在非托管代码编程语言中不可能,我真的很感兴趣吗?
下面我将展示我的示例程序(C ++)的一部分,它复制stack overflow exception
。它适用于任何SEH exception
,但不适用于堆栈溢出:
LONG WINAPI SehHandler(PEXCEPTION_POINTERS pExceptionPtrs)
{
cerr << "Handled SEH exception!\n";
cerr << "ContextRecord: " << pExceptionPtrs->ContextRecord << endl;
cerr << "ExceptionRecord: " << pExceptionPtrs->ExceptionRecord << endl;
// Write minidump file
CreateMiniDump(pExceptionPtrs);
// Terminate process
TerminateProcess(GetCurrentProcess(), 1);
return EXCEPTION_EXECUTE_HANDLER;
}
int fib(unsigned int n) {
if(n == 0) return 0;
if(n == 1) return 1;
return fib(n-1)+fib(n-2);
}
int main(){
SetUnhandledExceptionFilter(SehHandler);
cout << fib(1000000);
return 0;
}
答案 0 :(得分:9)
是的,你可以从一个SO崩溃中获得一个minidump,但从来没有你现在这样做的方式。您的SehHandler()函数在触发异常的线程上运行。它处于危险状态,你有大约7080字节的紧急堆栈空间可以做你需要做的事情。如果您使用该程序,则程序将因无法访问的访问冲突异常而失败。
你不能调用MiniDumpWriteDump()并希望能够存活它,该函数需要的堆栈比你可用的多。所以这是一个没有minidump的硬kaboom。
您需要另一个线程才能进行该调用。例如,这可能是您在初始化时创建的线程,并且使用WaitForMultipleObjects()调用进行阻塞。你的SehHandler()可以调用SetEvent()来唤醒它。将PEXCEPTION_POINTERS值写入全局变量后。并无限期地阻塞以允许线程创建minidump并中止该过程。
Fwiw,到目前为止,该线程的最佳位置是另一个进程。这也允许你处理完全破坏过程状态的真正令人讨厌的那些。您在初始化时开始的“保护”过程。使用命名事件来发送信号,例如,使用内存映射文件传递PEXCEPTION_POINTERS。不要在SehHandler()中启动它,进程堆不再可靠,因此CreateProcess()不能再工作了,你必须尽早完成。
答案 1 :(得分:1)
Hans Passant的回答表明有7080字节的紧急堆栈。我不知道该信息来自哪里,他也没有回答@nop,我的调查结果表明该信息不正确。然而,由于某些原因,这个网站不允许我在上面发表评论,所以我只是把它留在这里...
有一个函数可用于查询和设置堆栈处理程序剩余的紧急堆栈:SetThreadStackGuarantee()
。请注意,由于Windows 10肯定(但我认为它也是自Windows 7以来),在大多数情况下此值将为0 。因此,默认情况下,在处理程序中无法执行任何复杂操作。正如Hans所建议的那样,你可能能够发出另一个线程或外部进程的信号,但这就是全部。
但是,如果您不想实现这样一个复杂的解决方案,并且可以在堆栈上留出一些空闲空间,最简单的方法是使用SetThreadStackGuarantee()
将其设置为高值就像任何其他一样,你可以继续处理堆栈溢出异常。请注意,您需要在需要此功能的每个线程上调用此函数,并在发生堆栈溢出之前将其命名为,因此最好在线程初始化时进行。