调试难以捉摸的段错误
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 MACRO
s 被盲目地扔进去了。
#pragma pack( push, 1 )
#include <set>
int main()
std::set<int> a;
a.insert( 1 );
return 0;
这在我的机器上出现了段错误,而 valgrind 只是抱怨无效读取。我不知道 gdb 是否有任何方法知道这是由字节对齐引起的。
【问题讨论】:
你用 gdb 试过什么?与瓦尔格林?我还没有看到这些工具中至少有一个(通常是两个)无法解决的段错误。 for segfaultgdb
将是最好的工具....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 可能能够捕捉到段错误。以上是关于调试难以捉摸的段错误的主要内容,如果未能解决你的问题,请参考以下文章