2012-06-26 18 views
2

我在這裏結束了我的工作:我有一個單線程C++程序。這裏有一些經驗數據和背景信息,我試圖強調最重要的關鍵字;單線程C++函數調用中的undebuggable非確定性heisenbug

  • 我說的是整款不沒有任何系統調用,比內存(去)分配調用標準C++庫可以執行其他(std::set s爲參與)。這是一個純粹邏輯的算法。
  • 這個的行爲應該是確定性的,這取決於輸入,我不會改變。
  • 如果該錯誤自身出現,程序就會看起​​來像無限循環似乎開始分配內存超出任何綁定
  • 該錯誤不清單本身不出所料,我可以在命令行運行程序,有時(也許30%-50%)的bug本身表現,否則,一切就順利且正確地運行作爲我可以告訴。
  • 一旦我不是直接從提示中運行程序,而是在gdb或valgrind中,錯誤消失了,程序永遠不會死亡。
  • 現在是最好的部分:我將問題追溯到(模板化的)非虛擬成員函數調用。只需要之前撥打電話,我打印一條信息到std::cout,其中我可以在終端看到第一行裏面的函數還有一條調試消息,這是從來沒有顯示的

我沒有看到任何合理的解釋。也許你可以想出一個想法如何繼續。


編輯:代碼的顯著行,我改變了行號,所以我們可以參考它們並省略無關的部分,所以不能代表一切,似乎讓最好的感覺。

a.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); 

b.cpp

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

輸出的最後一行是:

eval; cd = 0x2e6ebb0, cg = 0x2e6ebc0 

那麼它困在無限循環。

+0

如果你真的確定這不是一個競爭條件(效果看起來完全像你所描述的),我會轉儲我的對象的狀態,以查看哪個狀態導致錯誤狀態。一些錯誤的初始化順序也會導致這種行爲。 –

+7

代碼會有所幫助,否則這是不可能告訴任何事情的。然而,「bug在調試器中奇蹟般地消失了」通常指向一個「if(ptr!= NULL)do_something(); '和一個非初始化變量。如果內存位置偶然爲零,則不會發生該錯誤,否則會發生。調試器對所有**變量進行初始化(即使是你沒有的變量),所以這個bug「神奇地消失了」。 – Damon

+0

您可以嘗試使用['strace'](http://linux.die.net/man/1/strace)跟蹤系統調用(某些可能隱藏在系統庫中)。另外考慮添加** lot **的調試打印,越多越好。 –

回答

5

我敢打賭,第二行打印,當您更改

ConstraintList eval(ArrayContainer const request) 

ConstraintList eval(ArrayContainer const & request) 

如果是這樣,任何一個allSymbols狀態線12和第15行,或者你之間的損壞代碼看起來更像這樣:

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,因爲符號指的是一個alre ady破壞對象。

+0

是的,我失明瞭,對不起。不錯,但是。儘管如此,實際的事情看起來有點複雜。 – bitmask