c++ - 隔离堆栈粉碎错误的工具

标签 c++ c debugging memory-leaks

委婉地说,我有一个小的内存问题,并且正在用完工具和想法来找出原因。

我有一个高度多线程 (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 也有陷阱,但只有在堆栈消失后。

问题:还有哪些其他工具或技术有助于缩小违规部分的范围?

非常感谢, --比尔

最佳答案

解决此类问题的几个选项:

您可以尝试在损坏发生之前在堆栈地址上设置硬件断点,并希望调试器在损坏时足够早地中断以提供模糊有用的调试状态。这里棘手的部分是选择正确的堆栈地址;根据违规线程的“选择”的随机性,这可能不切实际。但是从您的一条评论看来,通常是新创建的线程被破坏了,所以这可能是可行的。尝试在线程创建过程中中断,获取线程的堆栈位置,通过一些疯狂的猜测来抵消,设置硬件 BP,然后继续。根据您是否过早、过晚或根本不休息,调整您的偏移量,冲洗并重复。这基本上是高级猜测和检查,如果损坏模式过于随机,可能会受到严重阻碍或完全不切实际,但令人惊讶的是,这经常会导致半清晰的堆栈和成功的调试工作。

另一种选择是开始收集故障转储。尝试在故障转储之间寻找可能有助于您更接近损坏源的模式。也许你会很幸运,其中一个故障转储会“更快”/“更接近源”崩溃。

不幸的是,这两种技术更像是艺术而不是科学。它们是非确定性的,依赖于健康的运气,等等(至少根据我的经验.. 话虽如此,有些人可以用崩溃转储做惊人的事情,但这需要很多时间达到那个水平的技能)。

另外一个注意事项:正如其他人所指出的,未初始化的内存是调试与发布差异的一个非常典型的来源,在这里很容易成为您的问题。但是,另一个需要记住的可能性是时间差异。线程被调度的顺序,以及多长时间,在调试和发布中通常有很大的不同,并且很容易导致同步错误被掩盖在一个而不是另一个中。这些差异可能只是由于执行速度差异造成的,但我认为某些运行时故意在调试环境中扰乱线程调度。

关于c++ - 隔离堆栈粉碎错误的工具,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12712053/

相关文章:

c++ - 找不到句首

c++ - 字符串流到数组

c++ - 如何将数据插入到预先分配的 CSV 文件中?

c++ - 工具链还是 IDE? (调试问题)

php - 如何禁用 PHP 中的通知输出?

C++ static const struct 初始化

c++ - 为什么qt不读取文件

c - 如何在C中读取目录中的所有.txt文件

c++ - WinAPI - 如何将程序和外部 DLL 的所有标准输出重定向到 Win32 标准输出句柄?

iOS:这些地址在 iOS 崩溃日志堆栈跟踪中意味着什么?