環境: 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 文件的輔助,快速定位錯誤。