簡體   English   中英

用於隔離堆棧粉碎bug的工具

[英]Tools for Isolating a Stack smashing bug

說得客氣一點,我有一個小內存問題,並且沒有工具和想法來隔離原因。

我有一個高度多線程(pthreads)的C / C ++程序,在4.4.4之后和4.7.1之前的GCC優化編譯下開發了堆棧粉碎問題。

症狀是在創建其中一個線程期間,我獲得了完整的堆棧粉碎,而不僅僅是%RIP,但是所有父幀和大多數寄存器都是0x00或其他非感知地址。 哪個線程導致問題似乎是隨機的,但是通過日志消息判斷它似乎被隔離到相同的Hunk代碼,並且似乎在創建新線程時處於半可重復的點。

這使得很難將有問題的代碼捕獲和隔離到比可能數千行的單個編譯單元更為狹窄,因為到目前為止,打印()在違規文件中被證明在嘗試縮小活動部分時是不可靠的。

導致最終破壞堆棧的線程的線程創建是:

 
extern "C"
{
static ThreadReturnVal ThreadAPI WriterThread(void *act)
{
   Recorder       *rec = reinterpret_cast  (act);
   xuint64        writebytes;
   LoggerHandle m_logger = XXGetLogger("WriterThread");

   if (SetThreadAffinity(rec->m_cpu_mask))
   { ... }
   SetThreadPrio((xint32)rec->m_thread_priority);

   while (true)
   {
     ... poll a ring buffer ... Hard Spin 100% use on a single core, this is that sort of crazy code. 
   }
}

我嘗試過調試版本,但症狀只存在於優化版本中,-O2或更好。 我已經嘗試過Valgrind / memcheck和DRD但是在堆棧被吹走之前都沒有找到任何問題(並且需要大約12小時來達到失敗)

使用-O2 -Wstack-protector進行編譯時沒有看到任何錯誤,但使用-fstack-protector-all進行構建確實可以保護我免受錯誤的影響,但不會發出任何錯誤。

電圍欄也陷阱,但只有在堆棧消失后才會陷阱。

問題:還有哪些其他工具或技術可用於縮小違規部分?

非常感謝, - 比爾

解決此類問題的幾種選擇:

您可以嘗試在發生損壞之前在堆棧地址上設置硬件斷點,並希望調試器在損壞中提前破壞,以提供模糊的有用調試狀態。 這里棘手的部分是選擇正確的堆棧地址; 根據違規線程的“選擇”的隨機性,這可能不實用。 但是從你的一條評論中,聽起來通常是新創建的線程被粉碎,所以這可能是可行的。 嘗試在創建線程期間中斷,獲取線程的堆棧位置,通過一些瘋狂的猜測進行偏移,設置硬件BP,然后繼續。 根據您是否過早,太晚或根本不打破,調整偏移,沖洗和重復。 這基本上是高級猜測和檢查,如果損壞模式太隨機,可能會嚴重阻礙或完全不實用,但令人驚訝的是,這通常會導致半清晰的堆棧和成功的調試工作。

另一種選擇是開始收集崩潰轉儲。 嘗試在崩潰轉儲之間查找可能有助於使您更接近損壞源的模式。 也許你會很幸運,其中一個崩潰轉儲會“更快”/“接近來源”崩潰。

不幸的是,這兩種技術都是科學的藝術; 他們是非確定性的,依賴健康的運氣等等(至少根據我的經驗......據說,有人可以用崩潰轉儲做出驚人的事情,但需要花費很多時間達到那種技能水平)。

還有一個注意事項:正如其他人所指出的那樣,未初始化的內存是調試與發布差異的典型來源,在這里很容易成為您的問題。 但是,要記住的另一種可能性是時間差異。 線程調度的順序以及調試與發布之間的順序通常有很大不同,並且很容易導致同步錯誤被屏蔽在一個而不是另一個屏蔽。 這些差異可能只是由於執行速度的差異,但我認為一些運行時故意在調試環境中混亂線程調度。

您可以使用靜態分析工具檢查一些sutble錯誤,可能找到的錯誤之一可能是您的錯誤的原因。 您可以在此處找到有關這些工具的一些信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM