如何使用pthread来捕获堆栈溢出?

9

我有一个C++应用程序,其中有许多线程,大部分的线程堆栈大小为32k。问题是有时会发生stack overflow,并且我想检测哪个线程导致了这个stack overflow,并将其写入日志文件,但问题是我无法捕获它。

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

是否有人可以向我展示一个小例子,说明如何在线程中发生stack overflow时捕获 SIGSEGV

1个回答

8
对于多线程应用程序,捕获堆栈溢出与单线程应用程序并没有太大区别。唯一可能不同的方式是如果您溢出了很多;对于主线程;在大多数情况下,这仍将使您的堆栈指针无效,并且引发SIGSEGV异常,但对于小线程堆栈,溢出可能会将您的堆栈指针放置在另一个线程的堆栈中间,在这种情况下,非常糟糕的事情将会发生,并且没有前进的希望。如果您使用小堆栈,则应检查的另一个问题是您是否禁用了保护页。使用pthread_attr_setstack(顺便说一下,此函数已过时)不会为您提供保护页,除非您已经自己设置了它们。使用pthread_attr_setstacksize(正确的现代接口)不应干扰保护页分配,但如果您认为溢出超出很多,可以增加保护大小(使用pthread_attr_setguardsize)。
话虽如此,处理堆栈溢出的一般过程是设置SIGSEGV的处理程序,并将其设置为在备用堆栈上运行。这最后一点至关重要!由于在生成信号时堆栈指针无效,因此需要为信号处理程序本身设置备用堆栈。虽然标志是指定是否在备用堆栈上处理给定信号的每个信号属性(由sigaction设置),但实际的备用堆栈是每个线程属性。每个线程都必须使用sigaltstack设置自己的备用堆栈。备用堆栈的空间可以通过mallocmmap分配,但最简单的方法是在线程启动函数中创建一个大小约为2-4k的自动char数组,并将其用作备用堆栈。基本上,这相当于预留了线程堆栈底部的一小段范围,用作堆栈顶部溢出后用作信号处理程序的紧急堆栈空间。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接