如何使用 pthread 捕获堆栈溢出

How to trap stack overflow with pthread?

本文关键字:堆栈 栈溢出 何使用 pthread      更新时间:2023-10-16

我有一个C++应用程序,它有很多线程,其中大多数都有 32k 的堆栈大小。问题是有时我得到一个堆栈溢出,我想检测哪个线程导致了堆栈溢出并将其写入日志文件,问题是我无法捕获它。

我阅读了有关SIGSEGV的信息,并且只能在没有线程的情况下捕获此信号。我也尝试使用pthread_sigmask()和使用libsigsegv,但我也失败了。

谁能给我看一个关于在线程中发生堆栈溢出时捕获SIGSEGV的小例子?

在大多数情况下,多线程应用程序的捕获堆栈溢出与单线程应用程序捕获堆栈溢出没有任何不同。它可能有所不同的主要方式是,如果您溢出了很大的利润;对于主线程;在大多数情况下,这仍然会给你留下一个无效的堆栈指针和SIGSEGV,但对于小线程堆栈,溢出可能会将堆栈指针放在另一个线程堆栈的中间,在这种情况下,会发生非常糟糕的事情,并且没有向前推进的希望。如果您使用的是小堆栈,您应该检查的另一个问题是您没有禁用保护页面。使用pthread_attr_setstack(顺便说一下,此功能已弃用)不会为您提供保护页面,除非您已经自己设置了它们。使用 pthread_attr_setstacksize(正确的现代界面)不应干扰保护页分配,但如果您认为溢出幅度很大,则可能需要增加保护大小(使用 pthread_attr_setguardsize)。

话虽如此,处理堆栈溢出的一般过程是为SIGSEGV设置处理程序并将其设置为在备用堆栈上运行。最后一点至关重要!由于堆栈指针在生成信号时无效,因此需要有一个备用堆栈供信号处理程序本身运行。虽然是否在备用堆栈上处理给定信号的标志是每个信号属性(由 sigaction 设置),但实际的备用堆栈是每个线程属性。每个线程都必须使用 sigaltstack 设置自己的备用堆栈。备用堆栈的空间可以通过 mallocmmap 来分配,但最简单的方法是在线程启动函数中创建一个大小约为 2-4k 的自动char数组,并将其用于备用堆栈。基本上,这相当于在线程堆栈的底部保留一个小范围,以便在堆栈顶部溢出后用作信号处理程序的紧急堆栈空间。