程序分析實例 - 無雙大蛇(Orochi)

下面以對KOEI的無雙大蛇的一個bug的研究爲例,介紹程序分析的基本方法。

無雙大蛇是KOEI公司推出的一款動作類遊戲,3.20日發佈了日文PC版。
在遊戲過程中發現,進入某些戰鬥的時候程序會陷入死循環,具體表現是在菜單中選擇戰鬥場景之後,畫面變黑,但是一直不出現戰前配置的界面。Alt+F4關閉主窗口之後,還可以在任務管理器中找到它的進程。
因爲是進入戰鬥場景時發生的問題,猜測可能是讀取或者解析場景數據的時候發生了錯誤。因爲無雙系列的數據量較大,通常場景數據不會保存在內存中,而是直接從文件讀取,所以先用SysInternals中的procmon工具對文件讀寫進行監控,以便定位場景數據。
監控之後發現程序在使用ReadFile一次性讀取大量數據(>35M)的時候失敗(procmon中給出的錯誤信息是insufficient resource),然後程序一直在重試,從而導致了死循環。
使用關鍵字“ReadFile "insufficient resource"”Google了一下,沒有發現太有價值的線索。
我自己寫了個測試程序讀取相同位置相同數量的數據,沒有任何問題。因此暫時無法準確定位讀取失敗的原因。

正好要對大蛇的主程序進行分析,所以也順便研究一下這個bug。
首先,因爲自己的測試程序可以成功讀取,所以懷疑是讀取參數的原因導致ReadFile失敗。因爲ReadFile本身通常不會帶參數(雖然最後一個參數是用於指定overlap的,但是通常很少用到),所以先研究CreateFile調用時傳遞的參數。
很快定位到程序中打開數據文件的代碼,發現它在CreateFile的時候傳遞了FILE_FLAG_NO_BUFFERING參數。MSDN了一下,裏面只提到使用該參數需要注意一些對齊的問題。
修改了我自己的測試程序,加入了FILE_FLAG_NO_BUFFERING參數。這次終於重現了bug,查看GetLastError的返回值,發現確實是ERROR_NO_SYSTEM_RESOURCES。
再次使用Google,加入新獲得了兩個關鍵字FILE_FLAG_NO_BUFFERING和ERROR_NO_SYSTEM_RESOURCES,可以找到更多相關的鏈接。瀏覽之後,基本可以肯定是一次性讀入過多的數據導致的問題。
http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.kernel/2005-02/0489.html

因爲問題實際上並不是FILE_FLAG_NO_BUFFERING參數導致的,所以我們去掉這個關鍵字。另外我覺得很多人應該會把該行爲當成bug(因爲MSDN上並沒有提及),所以在關鍵字中加入bug,以期望進一步驗證我的判斷。然後重新搜索,得到了一個非常有價值的鏈接:
http://svn.icculus.org/physfs/trunk/lzma/C/Archive/7z/7zMain.c?view=markup&sortdir=down&pathrev=923
裏面明確提到了這個問題
/*
   ReadFile and WriteFile functions in Windows have BUG:
   If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
   from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
   (Insufficient system resources exist to complete the requested service).
*/

這說明,當碰到了bug,並且你已經掌握了較爲詳盡的出錯相關信息的時候,可以直接通過Google的codesearch,或者koders網站在開源軟件的代碼中進行搜索,以充分利用前人的分析結果。(其實MFC的源代碼註釋中也有很多類似的信息)

當然最後修復這個bug就很簡單了,自己寫一個以4M爲單位讀取文件的代碼,然後做個內存補丁即可。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章