【Linux】學會 core dump 事後除錯 快速定位段錯誤
環境: centos 6.5
core dump是什麼
其實就是作業系統在程序收到某些訊號而終止執行時,將此時程序地址空間的內容以及有關程序狀態的其他資訊寫出的一個磁碟檔案。最常見的就是段錯誤,然後程式直接掛掉。當程式出現段錯誤時,不要一臉矇蔽,有一種簡單而有效的方式快速定位錯誤。
常見 core dump 錯誤
總結自前輩的經驗:
一、無效指標
- 對空指標進行了操作
- 對未初始化的指標進行了操作
- 使用一個已經釋放記憶體過的指標再次delete 重複釋放,(所以說釋放後要置空,置空就不會報錯)
- 多執行緒訪問全域性變數,導致記憶體值異常而程式核心轉存。
二、指標越界
- 檢查賦值語句,檢查定位到錯誤上下變數的值,可以結合註釋來定位
- 記憶體變數值異常,檢查定位行,程式碼走讀排查函式呼叫是使用否有問題,重點關注函式:
sprintf, strcpy,memmove, memcpy,stcmp,strcasecmp
等容易出現錯誤的函式。
三、作業系統特殊性
- 位元組對齊方式引起的程式核心轉儲
- 引用模組與自身模組所定義的結構體的位元組對齊方式不同
- 在程式碼中, 把引用到的別的模組的標頭檔案包含到自身檔案中的位元組對齊方式語法宣告的中間了, 結果導致位元組對齊方式出現了變化
如何生成 core dump
以下幾步:
- 在gcc 加上-g選項,生成除錯資訊
- 使用
ulimit -a
檢視你係統對生成core檔案大小的限制,一般都限制為0,為了避免產生過過多冗餘資訊,也為了保證資料的安全,因為記憶體中可能有很多隱私資訊,此時需要修改core 檔案的資訊(下面有具體的案例)。 - 生成 core 檔案後(各個平臺生成的檔案定定義格式可能不同,我使用的系統預設生成在當前目錄下,檔名是core.**,*號是程序ID)然後使用
gdb execute core.*
除錯你的程式。 execute 是你 掛掉的程式名字, 後面跟著的是生成的 core檔案。
記錄一下除錯過程
在寫一個小型http 伺服器的時候,瀏覽器訪問靜態頁面沒有問題,一旦訪問可執行指令碼(用 c 寫的cgi 介面程式 )就GG,由於可執行指令碼是 父程序 fork 出子程序然後exec 程式替換,將可執行指令碼替換進來,然後就直接掛掉。
初步懷疑是錯誤發生在執行指令碼的函式裡,然後一開始寫的時候沒有寫巨集測試程式碼,直接開幹。也不想用printf 輸出除錯,發現這是一個段錯誤,然後就想到了之前看到過的 事後除錯。
下面是除錯過程:
1、 檢視系統是否有對 core 檔案的限制
果然。。有。。(廢話啊)。
然後我們可以有兩種方式可以修改:
[bob @ host httpd]$ulimit -c 1024
-c 後面跟你要限制的大小,然後這有時候沒什麼用。因為你也不知道它會 dump 多大的資料,如果一直無法產生core檔案,可以用下面這個命令
[bob @ host httpd]$ulimit -c unlimited # 表示大小無限制
由於當時沒有儲存截圖。。我想情景再現,發現我已經想不起來是哪裡的錯誤,記得是一個很比較低階但是不容易發現的錯誤,就是越界問題。下面我寫個小例子來演示一下:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p;
*p = 10;
return 0;
}
你說這會不會掛?當然。。會啊,解引用未知地址。
然後檢視修改系統對core 的限制並在gcc 上加-g 選項,再次執行程式:
注意如果出現報錯的問題,請切換成root 使用者,我的機子上普通使用者 無法修改為 ulimited。
然後再次執行程式:
又掛了,但是當前目錄下多了一個core.* 的檔案。
現在使用gdb 除錯該程式。
看關鍵部分!!,直接就到定位到了 12 行,然後在推斷定位行上下,就發現指標未初始化的問題。當然如果程式較大,還需要仔細分析,結合core 檔案的輔助,快速定位錯誤。