单线程C ++函数调用中的undebuggable非确定性heisenbug

时间:2012-06-26 10:10:09

标签: c++ debugging non-deterministic heisenbug

我在这里结束了:我有一个单线程的C ++程序。这是一些经验数据和背景信息,我试图突出最重要的关键词;

  • 我正在讨论的整个部分没有任何系统调用,除了内存(de-)分配调用标准C ++库可能会执行({{ 1}}涉及)。这是一个纯粹的逻辑算法。
  • 的行为应该是确定性的,具体取决于输入,我不会改变。
  • 如果错误表现出来,程序只会落入看似无限循环的地方,似乎开始分配内存超出任何约束
  • 错误显示自己可预测,我可以从命令行运行程序,有时(可能是30%-50%)错误表现出来,否则就我所知,一切都顺利而正确地进行。
  • 一旦我不直接从提示符运行程序,但在 gdb或valgrind中,错误消失,程序永远不会死。
  • 现在是最好的部分:我将问题追溯到(模板化的)非虚拟成员函数调用。只需通话,我就会在std::set打印一条消息,在终端中我可以看到。函数内的第一行也有一条调试消息,从未显示

我再也看不到任何合理的解释了。也许你可以想出如何继续下去。


编辑:重要的代码行,我更改了行号,以便我们可以引用它们并省略不相关的部分,所以并非一切似乎都是最有意义的。

a.cpp

std::cout

b.cpp

 10     std::set<Array const*>* symbols;
 11     std::set<Array const*> allSymbols;
 12     symbols = &allSymbols;
 //  ... allSymbols are populated with std::inserter
 15     std::cout << "eval; cd = " << &cd << ", cg = " << &cd.cg << std::endl;
 16     senderConstraints = cd.cg.eval(*symbols);

输出的最后一行是:

 31     template <typename ArrayContainer>
 32     ConstraintList eval(ArrayContainer const request) {
 33       std::cout << "inside eval ... going to update graph now" << std::endl;

然后它被困在无限循环中。

1 个答案:

答案 0 :(得分:5)

我打赌,当你改变

时,会打印第二行
ConstraintList eval(ArrayContainer const request)

ConstraintList eval(ArrayContainer const & request)

如果是这样,第{12}行和第15行之间allSymbols的状态都已损坏,或者您的代码看起来更像是这样:

std::set<Array const*>* symbols;
{
    std::set<Array const*> allSymbols;
    symbols = &allSymbols;
    //  ... allSymbols are populated with std::inserter
}
std::cout << "eval; cd = " << &cd << ", cg = " << &cd.cg << std::endl;
senderConstraints = cd.cg.eval(*symbols);

这是UB,因为符号指的是已经被破坏的对象。