8

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

我读到了SIGSEGV,我只能在没有线程的情况下捕获这个信号。我也尝试过使用pthread_sigmask()和使用libsigsegv,但我也失败了。

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

4

1 回答 1

8

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

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

于 2013-01-24T18:48:50.930 回答