在過去的幾個月中,我一直在忙着調試在一個非常大的專有C++圖像處理庫中的某處發生的罕見崩潰,該庫使用針對ARM Cortex-A9 Linux目標的GCC 4.7.2進行編譯。由於一個常見的症狀是glibc抱怨堆腐敗,第一步是使用堆腐敗檢查器來捕獲oob內存寫入。我使用https://stackoverflow.com/a/17850402/3779334中描述的技術將所有調用free/malloc轉移到我自己的函數中,使用一定數量的已知數據填充每個已分配的內存塊來捕獲越界寫入 - 但是什麼都沒找到,即使使用as在每個分配的塊之前和之後大約爲1 KB(由於大量使用STL容器,因此分配了數十萬個塊,因此我無法進一步擴大填充範圍,再加上我認爲任何寫入超出1KB的塊都會超出範圍無論如何最終會觸發段錯誤)。這個界限檢查器在過去發現了其他問題,所以我不懷疑它的功能。什麼可能會導致互斥錯誤?
(有人說「Valgrind的」之前,是的,我已經試過太沒有結果無論是。)
現在,我的內存邊界檢查還有一個特點,它預先考慮與數據結構每一個分配的塊。這些結構都鏈接在一個長鏈表中,以便我偶爾遍歷所有分配和測試內存完整性。由於某些原因,即使此列表的所有操作都受到互斥鎖保護,列表也會被破壞。在調查這個問題時,似乎互斥體本身偶爾無法完成其工作。這裏是僞代碼:
pthread_mutex_t alloc_mutex;
static bool boolmutex; // set to false during init. volatile has no effect.
void malloc_wrapper() {
// ...
pthread_mutex_lock(&alloc_mutex);
if (boolmutex) {
printf("mutex misbehaving\n");
__THROW_ERROR__; // this happens!
}
boolmutex = true;
// manipulate linked list here
boolmutex = false;
pthread_mutex_unlock(&alloc_mutex);
// ...
}
代碼評論「發生這種情況!」偶爾會達到,儘管這似乎是不可能的。我的第一個理論是互斥數據結構被覆蓋。我把互斥體放在一個結構體中,在它之前和之後有大的數組,但是當這個問題發生時,數組沒有任何變化,所以似乎沒有任何東西被覆蓋。
那麼..什麼樣的腐敗可能會導致這種情況發生,我如何找到並解決問題的原因?
還有一些筆記。測試程序使用3-4個線程進行處理。使用較少的線程運行似乎使腐敗不那麼常見,但不會消失。測試每次運行約20秒,並在絕大多數情況下成功完成(我可以有10個單元重複測試,第一次故障發生在5分鐘到幾個小時後)。當問題發生時,測試時間很晚(比如15秒),所以這不是一個不好的初始化問題。內存邊界檢查器從來沒有捕獲到實際的越界寫入,但glibc仍然偶爾會因損壞的堆錯誤而失敗(這種錯誤是否可以由oob寫入以外的其他情況引起?)。每次失敗都會生成一個包含大量跟蹤信息的核心轉儲;在這些轉儲中我沒有看到任何模式,沒有顯示比其他代碼更多的特定代碼段。這個問題似乎非常特定於一個特定的算法家族,並且在其他算法中不會發生,所以我很確定這不是一個零星的硬件或內存錯誤。我已經做了很多更多的測試來檢查oob堆的訪問,我不想列出這些文件來阻止這篇文章再次發佈。
在此先感謝您的幫助!
似乎極不可能我們可以幫你在這裏。在這種情況下,你似乎完成了你應該做的大部分工作,除了把它縮小到一個更小的程序。而且,是的,我知道在這種情況下這很困難且耗時。但是,不,這不會讓它變得更不重要。祝你好運! –
可能想使用此代碼嘗試Vagrind,並查看它是否顯示任何相關的內容 –
您可以在平臺上使用gcc 4.8並嘗試使用AddressSanitizer(https://code.google.com/p/address-sanitizer/wiki/AddressSanitizer)嗎?閱讀https://en.wikipedia.org/wiki/AddressSanitizer。 –