我有一个C ++应用程序,它有很多线程,大多数都是32k的堆栈大小。问题是,有时我得到一个stackoverflow,我想检测哪个线程导致了stackoverflow并将其写入日志文件,问题是我无法捕获它。
我读到了SIGSEGV
,我只能在没有线程的情况下捕获此信号。我也尝试使用pthread_sigmask()
并使用libsigsegv,但我也失败了。
任何人都可以向我展示一个关于在线程中发生堆栈溢出时捕获SIGSEGV
的小例子吗?
答案 0 :(得分:8)
多线程应用程序的陷阱堆栈溢出在很大程度上与单线程应用程序没有任何不同。它可能有所不同的主要方式是你是否有大幅度的溢出;为主线程;在大多数情况下,这仍会留下无效的堆栈指针和SIGSEGV
,但是对于小的线程堆栈,溢出可能会将堆栈指针放在另一个线程堆栈的中间,在这种情况下会发生非常糟糕的事情,前进的进展没有希望。如果你使用小堆栈,你应该检查的另一个问题是你没有禁用防护页面。使用pthread_attr_setstack
(顺便推荐使用此功能)除非您已自行设置,否则不会为您提供保护页面。使用pthread_attr_setstacksize
(正确的现代界面)不应该干扰保护页面分配,但是如果您认为溢出很大,则可能需要增加保护大小(pthread_attr_setguardsize
)。
话虽如此,处理堆栈溢出的一般过程是为SIGSEGV
设置处理程序并将其设置为在备用堆栈上运行。最后一点非常关键!由于堆栈指针在生成信号时无效,因此需要有一个备用堆栈,供信号处理程序自身运行。虽然用于是否在备用堆栈上处理给定信号的标志是每信号属性(由sigaction
设置),但实际备用堆栈是每线程属性。 每个线程必须使用sigaltstack
设置自己的备用堆栈。备用堆栈的空间可以通过malloc
或mmap
分配,但最简单的方法是在线程启动时创建一个大小约为2-4k的自动char
数组功能,并将其用于备用堆栈。基本上,这相当于在线程堆栈的 bottom 保留一个小范围,以便在堆栈顶部溢出后用作信号处理程序的紧急堆栈空间。