调试难以捉摸的段错误

Posted

技术标签:

【中文标题】调试难以捉摸的段错误【英文标题】:Debugging an elusive segfault 【发布时间】:2014-04-14 21:09:23 【问题描述】:

当尝试以下方法无济于事时,调试 c++ 段错误的最佳方法是什么:

隔离似乎导致问题的代码 在 gdb 下运行 使用各种工具和选项在 valgrind 下运行 注释掉 segfaulting 行以查看 segfault 是否仍然发生

编辑:

我找到了我的段错误的来源。假设#pragma pack( push, 1 ) 行深埋在包含的标头中,并且没有匹配的#pragma push( pop ),可能是因为#if[n]def MACROs 被盲目地扔进去了。

#pragma pack( push, 1 )

#include <set>

int main()

    std::set<int> a;
    a.insert( 1 );
    return 0;

这在我的机器上出现了段错误,而 valgrind 只是抱怨无效读取。我不知道 gdb 是否有任何方法知道这是由字节对齐引起的。

【问题讨论】:

你用 gdb 试过什么?与瓦尔格林?我还没有看到这些工具中至少有一个(通常是两个)无法解决的段错误。 for segfault gdb 将是最好的工具....valgrind 用于检查内存不足 用 valgrind 我试过 --tool=memcheck --track-origins=yes。它只报告conditional jump or move depends on unitialised values,但未初始化的值是在堆栈上创建并通过引用传递给函数的std::set。在正常情况下它不会被统一化。 使用 gdb,我已经进入了出现段错误的函数,并注意到我通过引用传递的集合中的变量指向不可访问的内存。在这一点上,我只需要弄清楚为什么 std::set 内的指针被破坏了。 要捕捉难以捉摸的段错误,您必须戴上忍者面具,在夜色中躺好几个小时,等待发现。如果你有耐心,你的罢工机会就会到来。 【参考方案1】:

调试段错误程序的另一种方法(希望您使用的是版本控制系统)是回滚您的提交,直到您的程序不再出现段错误。从那时起,您就知道下一次提交是引入了段错误的提交。

就我而言,段错误是由不匹配的#pragma pack( push, 1 )#pragma pack( pop ) 引起的。这可能会导致没有任何意义的错误,例如 std::set.insert 在新分配的 std::set 上调用时会导致段错误。

【讨论】:

并不总是有效;例如如果段错误基于未初始化的变量,则可能只是特定的提交与问题无关,但恰好改变了未初始化变量的值。 @MattMcNabb 如果是这样的话,gdb/valgrind 可能能够捕捉到段错误。

以上是关于调试难以捉摸的段错误的主要内容,如果未能解决你的问题,请参考以下文章

Linux环境下段错误的产生原因及调试方法小结

glGenFramebuffers 中的段错误

调用 glDrawElements 时的段错误

PayPal 难以捉摸的 IPN 历史在哪里?

getaddrinfo() 上的段错误

Windows:处理所有线程中的段错误