【发布时间】:2012-09-24 14:11:18
【问题描述】:
委婉地说,我有一个小的内存问题,并且正在用完工具和想法来找出原因。
我有一个高度多线程 (pthreads) 的 C/C++ 程序,它在 4.4.4 之后和 4.7.1 之前的 GCC 优化编译下开发了堆栈粉碎问题。
症状是在创建其中一个线程期间,我得到了一个完整的堆栈粉碎,不仅仅是 %RIP,而且所有父帧和大多数寄存器都是 0x00 或其他无意义的地址。 哪个线程导致问题似乎是随机的,但是从日志消息来看,它似乎与同一块代码隔离,并且似乎在创建新线程时出现了半可重复的点。
这使得捕获和隔离有问题的代码变得非常困难,而不是一个可能有数千行的编译单元,因为到目前为止,在有问题的文件中的 print() 在试图缩小范围时被证明是不可靠的活动部分。
导致最终破坏堆栈的线程的线程创建是:
extern "C"
{
static ThreadReturnVal ThreadAPI WriterThread(void *act)
{
Recorder *rec = reinterpret_cast (act);
xuint64 writebytes;
LoggerHandle m_logger = XXGetLogger("WriterThread");
if (SetThreadAffinity(rec->m_cpu_mask))
{ ... }
SetThreadPrio((xint32)rec->m_thread_priority);
while (true)
{
... poll a ring buffer ... Hard Spin 100% use on a single core, this is that sort of crazy code.
}
}
我尝试了调试版本,但症状仅出现在优化版本中,-O2 或更好。 我已经尝试过 Valgrind/memcheck 和 DRD,但在堆栈被吹走之前都没有发现任何问题(大约需要 12 小时才能达到故障)
使用 -O2 -Wstack-protector 编译没有任何问题, 但是,带有 -fstack-protector-all 的构建确实可以保护我免受错误的影响,但不会发出任何错误。
Electric-Fence 也有陷阱,但只有在堆栈消失后。
问题:还有哪些其他工具或技术有助于缩小违规部分的范围?
非常感谢, --比尔
【问题讨论】:
-
如果它是创建线程的堆栈,一些代码可能会很好 - 你将什么作为参数传递给新线程?
-
为了清楚起见,您是说它在 g++ 4.4.2 和 4.8 上运行良好,还是这些版本尚未经过测试?
-
Mark B:在 GCC 4.4.2 上运行良好,4.7.x 以上版本与一些依赖库冲突,因此未经测试。
-
在gdb中,崩溃后
x/<some big number>xw $rsp的输出?是一切都归零,还是那里有可识别的东西? -
未初始化的堆栈变量可能会导致优化代码中的多线程错误,因为编译器会在调试代码中初始化它们,而在优化代码中,堆栈将不同,从而导致内存中的值与未优化的发布代码不同。
标签: c++ c debugging memory-leaks