1

我读过很多关于SEH exceptionsStackOverflow 和 CodeProject.net 的文章。

在我的 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;
}
4

2 回答 2

9

是的,您可以从 SO 崩溃中获得一个小型转储,但绝不是您现在这样做的方式。您的 SehHandler() 函数在触发异常的线程上运行。而且它处于危险状态,您还有大约 7080 字节的紧急堆栈空间来做您需要做的事情。如果您使用它,那么程序将因无法捕获的访问冲突异常而失败。

您不能调用 MiniDumpWriteDump() 并希望在它中生存,该函数需要比您可用的更多的堆栈。因此,这是一个没有小型转储的硬 kaboom。

您需要另一个线程来进行该调用。例如,这可能是您在初始化时创建并使用 WaitForMultipleObjects() 调用阻塞的线程。你的 SehHandler() 可以调用 SetEvent() 来唤醒它。将 PEXCEPTION_POINTERS 值写入全局变量后。并无限期地阻止以允许线程创建小型转储并中止进程。

Fwiw,到目前为止,该线程的最佳位置是在另一个进程中。这也允许您处理完全破坏进程状态的真正令人讨厌的问题。您在初始化时开始的“守卫”过程。用一个命名事件来发出信号,比如说,一个内存映射文件来传递 PEXCEPTION_POINTERS。不要在 SehHandler() 中启动它,进程堆不再可靠所以 CreateProcess() 不能再工作了,你必须尽早做。

于 2014-02-11T13:38:37.230 回答
1

Hans Passant 的回答表明有 7080 字节的紧急堆栈。我不知道该信息来自哪里,他也没有在上面回答@nop,我的发现表明该信息不正确。但是,由于某种原因,该网站不允许我在上面发表评论,所以我将把它留在这里......

有一个函数可用于查询和设置堆栈处理程序剩余多少紧急堆栈:SetThreadStackGuarantee(). 请注意,从 Windows 10 开始(但我认为也是从 Windows 7 开始),在大多数情况下,该值将是 0。因此,默认情况下,无法在处理程序中执行任何复杂的操作。正如 Hans 所建议的,您可能能够向另一个线程或外部进程发出信号,但仅此而已。

但是,如果您不想实现如此复杂的解决方案,并且可以在堆栈上腾出一些松弛空间,则最简单的方法是将SetThreadStackGuarantee()设置为足够高的值,以便您可以像处理任何其他异常一样继续处理堆栈溢出异常其他。请注意,您需要在每个需要此功能的线程上调用此函数,并在堆栈溢出发生之前调用它,因此最好在线程初始化时调用。

于 2017-01-04T08:57:05.920 回答