深奧又愚蠢的問題

前陣子有同仁發現我們的系統中有一支driver會造成系統當機,因為這支driver目前的負責人換我接手了,所以問題就轉到我手上,直到最近把手上幾個比較重要的項目告一段落後才抽空來看這個問題。

一開始先只看一下source,程式看起來不複雜,可能有問題的點都是很簡單易懂的標準程式寫法,看起來沒什麼破綻,看不出問題來。這支driver主要的程式註冊了一個event callback,在這個event callback裡面又會觸發另一個event,而這個event又會讓別支driver註冊的event callback執行,然後啟動一個service。看起來好像很複雜,其實並不複雜,就把它當成只連續call了幾次function就行。

我把driver打開執行看看,果然在我的環境也會發生系統當機的問題,是可以複製的問題,所以不是環境平台不同的問題。再把這支driver關閉,果然就沒有系統當機的問題,所以應該很有可能是這支driver造成的問題。接著我試著調整這支driver的執行次序看看,結果發現如果我讓它提早一些執行,結果就不會當機了。是那邊的記憶體有問題嗎?因為發現問題的同仁也說過,我們release的程式裡面,有幾個版本不會造成當機,但有的版本又會當機。現在我調整次序後又不會當機了?看來應該和記憶體有關係,是這支driver前面的driver造成的嗎?我又去看看前面的driver,看起來也是很簡單的程式,完全看不出來有什麼點是有可能會發生問題的。

光是作了以上幾個測試就花了我不少時間,因為我們的系統每次修改程式到重新編譯程式準備好環境作測試就會花不少時間。debug的方式主要是丟除錯訊息,因為這是最便捷的方法,當然也能支援source level debug,只是因為設定太麻煩以致於平常都習慣靠除錯訊息除錯。最後實在不行了,既然已經花了那麼多時間測試了,不如再多花點時間把source level debugger架起來吧。

source level debugger架起來後,我當然直接在driver的event callback裡面下一個breakpoint,然後執行看看。結果發生詭異的事情!第一次執行,程式並沒有中斷,這就奇怪了,我斷點是下在程式必經之路,怎麼不會斷呢?第二次程式是中斷了,但是居然斷在另外一支driver的callback裡面!我比對了我下斷點的function的位址和實際中斷的function的位址,還真的是一樣的位址。這種事情怎麼會發生呢!?這一定是記憶體的問題。

很快的我就找到問題真正發生點並把它修好:原來會造成系統當機的這支driver在註冊event callback到系統後,後面的初始化動作有問題,對系統報告錯誤後被系統unload掉了。但在driver被系統unload之前並沒有把先前註冊的event callback作反向的unregister動作,所以在系統裡面的記錄就指向一的不明位址。這就是造成當掉的原因,也是有時會當有時不會當的原因。因為這是memory的問題,現象會根據當是系統狀態而有不同。

這個問題初看好像很深奧,其實很愚蠢,這讓我又得到二個教訓。


  1. 那些看起來顯而易見沒有問題的程式有時候真的是問題的所在!
  2. 可以的話還是儘快打開你的source level debugger吧,source debug還是最強大的debug方法!


留言

這個網誌中的熱門文章

以lex/yacc實作算式計算機

猜數字遊戲 (電腦猜人)

KillSudoku 4顆星精彩數獨詳解 - 鍊技巧