|
撰/ahliu
甚麼是dmalloc?我們一般都使用dmalloc於gcc的程式庫模組(libdmalloc),它的運作原理比mtrace稍為複雜,它會重新定義大部份與記憶體有關的函數,包括malloc、free、memset、memcpy、strcat、strcpy等,還會在程式的結束點(exit point)將剩餘未釋放的動態記憶體(注:著者的意思為heap memory)釋放,然後將結果寫進記錄檔。 安裝dmalloc本文所描述之測試只適用於4.8.1及5.1.0至5.3.0版本,如果你已安裝了dmalloc,便可跳過這一章 請瀏覽http://dmalloc.com獲得最新的dmalloc版本及說明,下載及解壓後,請使用以下設定指令: ./configure --prefix=/usr/local/dmalloc --libdir=/usr/lib --enable-threads --enable-shlib
(設定指令可因應自己需要而更改) 然後輸入: make
make install
make installinfo
make installdocs
若果標頭檔案(i.e. dmalloc.h)和程式庫及程式模組(libdmalloc)並非在系統預設的位置裡(/usr/lib及/usr/include),請把檔案複製至該位置。 如何在程式中使用dmalloc?首先,你必需在你的程式碼加入標頭檔案dmalloc.h,而dmalloc是一個程式庫,在編繹程式時需加上-ldmalloc。在絕大部份情況下dmalloc會根據環境變數「DMALLOC_OPTIONS」來決定偵錯選項,重要選項包括: - debug bitmask:決定dmalloc記錄哪些資料,資料記錄選項是一組十六進制代碼,於debug_tok.h裡定義,選項名稱均以「log-xxx」命名,一般情況下我們都想dmalloc將動態記憶體分配和釋放的操作總結記錄下來,詳情可參看http://dmalloc.com/docs/5.3.0/online/dmalloc_31.html#SEC31
- logfile name:dmalloc寫入記錄的檔案名稱,有時候你想其檔案名稱更有彈性,可使用格式標識符,例如%p是你所寫的程式的process ID,%t是程式完結的時間,詳情可參看http://dmalloc.com/docs/5.3.0/online/dmalloc_29.html#SEC29
當然,dmalloc的設置選項不止這麼簡單,但礙於本文篇幅有限,而且詳細參考文件已在http://www.dmalloc.com上找到,所以以下所介紹的,都是實際應用而非功能介紹。因為DMALLOC_OPTIONS是一個環境變數,你可以用setenv/export(因應不同shell而定)指令直接設值,例如在bash中: export DMALLOC_OPTIONS=log=logfilename,debug=0x8400000
這代表「不要使用剛釋放的記憶體位址,遇上錯誤便立刻終止程式,把記錄寫進與你程式同一個目錄,名叫logfilename的檔案」,「debug」是剛才所提到的debug bitmask,是一個十六進制代碼,部份選項之代碼如下:
none(0x0):關去dmalloc所有功能(不能與其他選項共用)
log-stats(0x1):記錄基本記憶體運作的總結資料
log-non-free(0x2):記錄未被釋放的記憶體
log-known(0x4):只記錄有程式指針參考的未釋放記憶體(不能與0x2共用)
log-trans(0x8):記錄記憶體分配及釋放的事件
log-admin(0x20):記錄分配及釋放記憶體請求的資料
log-blocks(0x40):記錄記憶體區塊的運作
...
詳細說明可往http://www.linuxjournal.com/article.php?sid=6059。 常用的debug選項為log-stats和log-non-free,其debug十六進制代碼為0x3,因此你可以輸入以下指令設定dmalloc的環境變數: export DMALLOC_OPTIONS=log=logfile,debug=0x3 (in Bash)
setenv DMALLOC_OPTIONS debug=0x3,log=logfile (in Csh)
另外,使用被分配記憶體區塊以外的位址(fencepost problem)也是常見的錯誤,可加入 check-fence(0x400)偵測。 dmalloc的輸出結果假如環境變數DMALLOC_OPTIONS中有「log=your_logfile」設定的話,所有dmalloc的輸出結果都會寫進名為「your_logfile」的檔案,我們再次使用上一篇(mtrace)裡有溢出問題的程式碼,輸出結果如下:
1088190657: 1: Dmalloc version '5.3.0' from 'http://dmalloc.com/'
1088190657: 1: flags = 0x3, logfile 'logfile'
1088190657: 1: interval = 0, addr = 0, seen # = 0, limit = 0
1088190657: 1: starting time = 1088190657
1088190657: 1: process pid = 8692
1088190657: 1: Dumping Chunk Statistics:
1088190657: 1: basic-block 4096 bytes, alignment 8 bytes, heap grows up
1088190657: 1: heap address range: 0x804a000 to 0x8053000, 36864 bytes
1088190657: 1: user blocks: 1 blocks, 4081 bytes (11%)
1088190657: 1: admin blocks: 8 blocks, 32768 bytes (89%)
1088190657: 1: external blocks: 0 blocks, 0 bytes (0%)
1088190657: 1: total blocks: 9 blocks, 36864 bytes
1088190657: 1: heap checked 0
1088190657: 1: alloc calls: malloc 1, calloc 0, realloc 0, free 0
1088190657: 1: alloc calls: recalloc 0, memalign 0, valloc 0
1088190657: 1: alloc calls: new 0, delete 0
1088190657: 1: current memory in use: 1 bytes (1 pnts)
1088190657: 1: total memory allocated: 1 bytes (1 pnts)
1088190657: 1: max in use at one time: 1 bytes (1 pnts)
1088190657: 1: max alloced with 1 call: 1 bytes
1088190657: 1: max unused memory space: 15 bytes (93%)
1088190657: 1: top 10 allocations:
1088190657: 1: total-size count in-use-size count source
1088190657: 1: 1 1 1 1 test.c:9
1088190657: 1: 1 1 1 1 Total of 1
1088190657: 1: Dumping Not-Freed Pointers Changed Since Start:
1088190657: 1: not freed: '0x804aff0|s1' (1 bytes) from 'test.c:9'
1088190657: 1: total-size count source
1088190657: 1: 1 1 test.c:9
1088190657: 1: 1 1 Total of 1
1088190657: 1: ending time = 1088190657, elapsed since start = 0:00:00
從這個記錄檔可知,有一指針(0x804aff0)所指著的記憶體並未釋放,該段記憶體的大小為1 byte,而該記憶體是在test.c的第9行程式碼中被分配的。所有未被釋放的記憶體,包括其大小、記憶體位址、何時被分配等等都有詳細列出,相信這也是你所需要的資料。各位可嘗試加入其他debug選項,以獲得更詳細的資料(但記錄檔的大小及程式執行時間亦相對增加)。 其他dmalloc的選項應用當你編繹完dmalloc後,在bin目錄中會發現dmalloc這個執行檔,這個程式本身是為了方便使用者設置dmalloc環境變數所用的,可省卻計算十六進制代碼的麻煩,而且還列出dmalloc的其他執行選項(請輸入dmalloc --usage列出所有選項)。例如「-i」是用來設定相隔多少記憶體分配/釋放次數才記錄檢查溢出: dmalloc -i 1 -p log-stats -p log-non-free -l logfile
那麼這個程式就會為了設置你的環境變數(注:若你的shell因某種原因令dmalloc無法更改環境變數,請自行鍵入dmalloc所輸出的變數值)。另外,dmalloc還有一更好的方法來省卻設置debug選項的麻煩,當你輸入dmalloc -t後會有以下輸出(以下為ver 5.3.0的輸出): Tags available by default:
none
runtime
run
low
med
medium
high
all
以上是dmalloc的偵錯程度debug level,輸入dmalloc [tags]即代表debug level為tags,例如「all」即代表偵測所有動態記憶體的運作,而「high」比「medium」的偵測資料多,如此類推,例如: dmalloc all
將會記錄所有動態記憶體的運作。 dmalloc使用總結下載及安裝:(本例子只適用於Red Hat Linux 9 (Shrike) gcc-3.2.2 dmalloc 5.3.0 bash,讀者可自行修改)
wget http://download.sourceforge.net/dmalloc/dmalloc-5.3.0.tgz
gtar zxvf dmalloc-5.3.0.tgz
cd dmalloc-5.3.0
./configure --prefix=/usr/local/dmalloc --libdir=/usr/lib --enable-threads --enable-shlib
make
make install
make installinfo
make installdocs 設定dmalloc環境
cp bin/dmalloc/ /usr/bin (optional)
cp include/dmalloc.h /usr/include (optional)
cp lib/* /usr/lib (optional)
dmalloc -i 1 -p log-stats -p log-non-free -l log%p
export DMALLOC_OPTIONS=debug=0x3,inter=1,log=log%p (optional) 加入dmalloc.h至程式碼及編繹
...
#include <dmalloc.h>
int main( ) {
...
return 0;
}
gcc xxx.c -ldmalloc -o xxx
相關連結:
- dmalloc 下載
- 記錄選項參考
- 記錄檔案名稱設定參考
- debug選項一覽
發表日期:2004-06-26
|