一)MALLOC_CHECK_GNU的標準庫(glibc)可以通過內建的調試特性對動態記憶體進行調試,它就是MALLOC_CHECK_環境變數,它在預設情況下是不設定的,在老的版本預設這個值為0,新的版本預設值為2,但有一個矛盾,如果設定為空白,它將會列印出長長的跟蹤資訊,這比設為2更詳細.MALLOC_CHECK_有三種設定,即:MALLOC_CHECK_=0 ----- 關閉所有檢查.MALLOC_CHECK_=1 ----- 當有錯誤被探測到時,在標準錯誤輸出(stderr)上列印錯誤資訊.MALLOC_CHECK_=2 ----- 當有錯誤被探測到時,不顯示錯誤資訊,直接進行中斷.我們用下面的小程式做一下測試,來源程式如下:#include <stdio.h>#include <stdlib.h>int main (int argc,char *argv[]){ int i; char* p = (char *)malloc(10); char* pt = p; for (i = 0;i < 10;i++) { p[i] = 'z'; } free (p); free(pt); return 0;}gcc double-free.c -o double-free注:這個程式會釋放兩次指標.echo $MALLOC_CHECK_我們在MALLOC_CHECK_預設設定的情況下,執行test程式,輸出如下的資訊: ./test *** glibc detected *** ./test: double free or corruption (fasttop): 0x0890f008 ***======= Backtrace: =========/lib/libc.so.6[0x175f7d]/lib/libc.so.6(cfree+0x90)[0x1795d0]./test[0x80483dc]/lib/libc.so.6(__libc_start_main+0xdc)[0x125dec]./test[0x8048301]======= Memory map: ========00110000-00247000 r-xp 00000000 08:01 3704502 /lib/libc-2.5.so00247000-00249000 r-xp 00137000 08:01 3704502 /lib/libc-2.5.so00249000-0024a000 rwxp 00139000 08:01 3704502 /lib/libc-2.5.so0024a000-0024d000 rwxp 0024a000 00:00 0 00b51000-00b6a000 r-xp 00000000 08:01 3704501 /lib/ld-2.5.so00b6a000-00b6b000 r-xp 00018000 08:01 3704501 /lib/ld-2.5.so00b6b000-00b6c000 rwxp 00019000 08:01 3704501 /lib/ld-2.5.so00bf3000-00bf4000 r-xp 00bf3000 00:00 0 [vdso]00dab000-00db6000 r-xp 00000000 08:01 3704511 /lib/libgcc_s-4.1.1-20070105.so.100db6000-00db7000 rwxp 0000a000 08:01 3704511 /lib/libgcc_s-4.1.1-20070105.so.108048000-08049000 r-xp 00000000 08:01 327681 /root/test08049000-0804a000 rw-p 00000000 08:01 327681 /root/test0890f000-08930000 rw-p 0890f000 00:00 0 b7e00000-b7e21000 rw-p b7e00000 00:00 0 b7e21000-b7f00000 ---p b7e21000 00:00 0 b7f26000-b7f27000 rw-p b7f26000 00:00 0 b7f3b000-b7f3c000 rw-p b7f3b000 00:00 0 bfdcf000-bfde4000 rw-p bfdcf000 00:00 0 [stack]Aborted這裡我們調整MALLOC_CHECK_為0,再次運行程式,如下:export MALLOC_CHECK_=0./test 注:我們看到程式沒有任何輸出.我們將MALLOC_CHECK_調整為1,再次運行程式,如下:export MALLOC_CHECK_=1./test malloc: using debugging hooks*** glibc detected *** ./test: free(): invalid pointer: 0x0811e008 ***注:我們看到每次運行程式都會有malloc: using debugging hooks的輸出,同時程式檢測到free()兩次釋放的問題.我們將MALLOC_CHECK_調整為2,再次運行程式,如下:export MALLOC_CHECK_=2./test Aborted注:我們看到程式只輸出了Aborted,並中斷了程式的運行.二)用mtrace尋找記憶體泄露mtrace是由glibc提供的一個工具,在Redhat中將它打包在glibc-utils包中.我們安裝此包,如下:rpm -ivh /mnt/Server/glibc-utils-2.5-12.i386.rpmmtrace的主要作用是尋找記憶體泄露,為了應用mtrace程式,必須在代碼中使用glibc提供的函數mtrace和muntrace.另外,必須設定一個檔案的名字給環境變數MALLOC_TRACE,因為glibc利用它為mtrace程式儲存資料.當執行完代碼後,資料將會存在這個確認的檔案中,每執行一次程式,這個檔案的內容都會被重寫.我們用下面的代碼進行測試,如下:#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <mcheck.h>int main (int argc,char *argv[]){ setenv("MALLOC_TRACE","output",1); mtrace(); int i; char* p = (char *)malloc(10); char* pt = p; for (i = 0;i < 10;i++) { p[i] = 'z'; } return 0;}編譯:gcc test.c -o test注:程式用setenv函數設定環境變數MALLOC_TRACE運行程式:./test 這時在目前的目錄下產生了一個名為output的檔案,如下:cat output = Start@ ./test:[0x80483f2] + 0x82ba438 0xa@ /lib/libc.so.6:(clearenv+0x7c)[0xb9910c] - 0x82ba008@ /lib/libc.so.6:(tdestroy+0x47)[0xc39b77] - 0x82ba090@ /lib/libc.so.6:(tdestroy+0x4f)[0xc39b7f] - 0x82ba0b0用mtrace尋找記憶體泄露,它告訴我們memory not freedmtrace output - 0x082ba008 Free 3 was never alloc'd 0xb9910c- 0x082ba090 Free 4 was never alloc'd 0xc39b77- 0x082ba0b0 Free 5 was never alloc'd 0xc39b7fMemory not freed:----------------- Address Size Caller0x082ba438 0xa at 0x80483f2三)使用memusage收集記憶體統計資料memusage不需要在代碼中做出任何指示.這個工具也來自由glibc-utils包.它以柱形顯示程式佔用了多少記憶體.它預設輸出到標準輸出中,用ASCII文本顯示一個繪成圖畫似的柱形.如下:memusage awk 'BEGIN{print "hello world"}'hello worldMemory usage summary: heap total: 7487, heap peak: 6891, stack peak: 8624 total calls total memory failed calls malloc| 58 7487 0realloc| 0 0 0 (nomove:0, dec:0, free:0) calloc| 0 0 0 free| 15 797Histogram for block sizes: 0-15 27 46% ================================================== 16-31 7 12% ============ 32-47 2 3% === 48-63 6 10% =========== 64-79 1 1% = 80-95 1 1% = 96-111 1 1% = 112-127 4 6% ======= 160-175 1 1% = 176-191 2 3% === 192-207 1 1% = 208-223 2 3% === 384-399 1 1% = 480-495 1 1% = 4000-4015 1 1% = 四)使用Electric Fence檢測記憶體流失Electric Fence用一些巧妙的技術來檢測程式在堆記憶體區上的溢出,不需要用Electric Fence來修改代碼,相反,它提供一個動態庫,這個庫有多個動態分配函數.一個名為ef的指令碼被用來處理環境變數LD_PRELOAD的設定,我們可以用ef命令來調用程式.下面是安裝Electric Fence,如下:rpm -ivh /mnt/Server/ElectricFence-2.2.2-20.2.2.i386.rpm我們下面用一個小程式做測試,原始碼如下:#include <string.h>intmain (int argc, char *argv[]){ int *ptr = new int; memset(ptr, 0, sizeof(int) + 1); delete ptr;}編譯:g++ new-corrupt.cpp -o new-corrupt注:這個小程式會導致邊界溢出.執行程式:./new-corrupt注:程式沒有任何指示.我們用ef執行這個程式,如下:ef ./new-corrupt Electric Fence 2.2.0 Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com>/usr/bin/ef: line 20: 4148 Segmentation fault ( export LD_PRELOAD=libefence.so.0.0; exec $* )注:此時有輸出資訊,它告訴我們出現了Segmentation {敏感詞}t,並且指明在哪行出現的問題.我們也可以將electric fence和gdb聯用,如下:編譯器,同時指定-g選項g++ -g new-corrupt.cpp -o new-corrupt 用gdb開啟程式,如下:gdb ./new-corruptGNU gdb Red Hat Linux (6.5-16.el5rh)Copyright (C) 2006 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB. Type "show warranty" for details.This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".(gdb) set environment LD_PRELOAD libefence.so.0.0 /*設定環境變數LD_PRELOAD為libefence.so.0.0*/(gdb) run /*運行程式*/Starting program: /root/new-corrupt Electric Fence 2.2.0 Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com> Electric Fence 2.2.0 Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com>Program received signal SIGSEGV, Segmentation fault.0x0804849d in main () at new-corrupt.cpp:7 /*檢查出在調用memset函數時導致越界*/7 memset(ptr, 0, sizeof(int) + 1);(gdb) quit下面我們在gdb中不指定環境變數,我們看到gdb沒有列印出相關的錯誤資訊.gdb ./new-corruptGNU gdb Red Hat Linux (6.5-16.el5rh)Copyright (C) 2006 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB. Type "show warranty" for details.This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".(gdb) runStarting program: /root/new-corrupt Program exited normally.
一)MALLOC_CHECK_GNU的標準庫(glibc)可以通過內建的調試特性對動態記憶體進行調試,它就是MALLOC_CHECK_環境變數,它在預設情況下是不設定的,在老的版本預設這個值為0,新的版本預設值為2,但有一個矛盾,如果設定為空白,它將會列印出長長的跟蹤資訊,這比設為2更詳細.MALLOC_CHECK_有三種設定,即:MALLOC_CHECK_=0 ----- 關閉所有檢查.MALLOC_CHECK_=1 ----- 當有錯誤被探測到時,在標準錯誤輸出(stderr)上列印錯誤資訊.MALLOC_CHECK_=2 ----- 當有錯誤被探測到時,不顯示錯誤資訊,直接進行中斷.我們用下面的小程式做一下測試,來源程式如下:#include <stdio.h>#include <stdlib.h>int main (int argc,char *argv[]){ int i; char* p = (char *)malloc(10); char* pt = p; for (i = 0;i < 10;i++) { p[i] = 'z'; } free (p); free(pt); return 0;}gcc double-free.c -o double-free注:這個程式會釋放兩次指標.echo $MALLOC_CHECK_我們在MALLOC_CHECK_預設設定的情況下,執行test程式,輸出如下的資訊: ./test *** glibc detected *** ./test: double free or corruption (fasttop): 0x0890f008 ***======= Backtrace: =========/lib/libc.so.6[0x175f7d]/lib/libc.so.6(cfree+0x90)[0x1795d0]./test[0x80483dc]/lib/libc.so.6(__libc_start_main+0xdc)[0x125dec]./test[0x8048301]======= Memory map: ========00110000-00247000 r-xp 00000000 08:01 3704502 /lib/libc-2.5.so00247000-00249000 r-xp 00137000 08:01 3704502 /lib/libc-2.5.so00249000-0024a000 rwxp 00139000 08:01 3704502 /lib/libc-2.5.so0024a000-0024d000 rwxp 0024a000 00:00 0 00b51000-00b6a000 r-xp 00000000 08:01 3704501 /lib/ld-2.5.so00b6a000-00b6b000 r-xp 00018000 08:01 3704501 /lib/ld-2.5.so00b6b000-00b6c000 rwxp 00019000 08:01 3704501 /lib/ld-2.5.so00bf3000-00bf4000 r-xp 00bf3000 00:00 0 [vdso]00dab000-00db6000 r-xp 00000000 08:01 3704511 /lib/libgcc_s-4.1.1-20070105.so.100db6000-00db7000 rwxp 0000a000 08:01 3704511 /lib/libgcc_s-4.1.1-20070105.so.108048000-08049000 r-xp 00000000 08:01 327681 /root/test08049000-0804a000 rw-p 00000000 08:01 327681 /root/test0890f000-08930000 rw-p 0890f000 00:00 0 b7e00000-b7e21000 rw-p b7e00000 00:00 0 b7e21000-b7f00000 ---p b7e21000 00:00 0 b7f26000-b7f27000 rw-p b7f26000 00:00 0 b7f3b000-b7f3c000 rw-p b7f3b000 00:00 0 bfdcf000-bfde4000 rw-p bfdcf000 00:00 0 [stack]Aborted這裡我們調整MALLOC_CHECK_為0,再次運行程式,如下:export MALLOC_CHECK_=0./test 注:我們看到程式沒有任何輸出.我們將MALLOC_CHECK_調整為1,再次運行程式,如下:export MALLOC_CHECK_=1./test malloc: using debugging hooks*** glibc detected *** ./test: free(): invalid pointer: 0x0811e008 ***注:我們看到每次運行程式都會有malloc: using debugging hooks的輸出,同時程式檢測到free()兩次釋放的問題.我們將MALLOC_CHECK_調整為2,再次運行程式,如下:export MALLOC_CHECK_=2./test Aborted注:我們看到程式只輸出了Aborted,並中斷了程式的運行.二)用mtrace尋找記憶體泄露mtrace是由glibc提供的一個工具,在Redhat中將它打包在glibc-utils包中.我們安裝此包,如下:rpm -ivh /mnt/Server/glibc-utils-2.5-12.i386.rpmmtrace的主要作用是尋找記憶體泄露,為了應用mtrace程式,必須在代碼中使用glibc提供的函數mtrace和muntrace.另外,必須設定一個檔案的名字給環境變數MALLOC_TRACE,因為glibc利用它為mtrace程式儲存資料.當執行完代碼後,資料將會存在這個確認的檔案中,每執行一次程式,這個檔案的內容都會被重寫.我們用下面的代碼進行測試,如下:#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <mcheck.h>int main (int argc,char *argv[]){ setenv("MALLOC_TRACE","output",1); mtrace(); int i; char* p = (char *)malloc(10); char* pt = p; for (i = 0;i < 10;i++) { p[i] = 'z'; } return 0;}編譯:gcc test.c -o test注:程式用setenv函數設定環境變數MALLOC_TRACE運行程式:./test 這時在目前的目錄下產生了一個名為output的檔案,如下:cat output = Start@ ./test:[0x80483f2] + 0x82ba438 0xa@ /lib/libc.so.6:(clearenv+0x7c)[0xb9910c] - 0x82ba008@ /lib/libc.so.6:(tdestroy+0x47)[0xc39b77] - 0x82ba090@ /lib/libc.so.6:(tdestroy+0x4f)[0xc39b7f] - 0x82ba0b0用mtrace尋找記憶體泄露,它告訴我們memory not freedmtrace output - 0x082ba008 Free 3 was never alloc'd 0xb9910c- 0x082ba090 Free 4 was never alloc'd 0xc39b77- 0x082ba0b0 Free 5 was never alloc'd 0xc39b7fMemory not freed:----------------- Address Size Caller0x082ba438 0xa at 0x80483f2三)使用memusage收集記憶體統計資料memusage不需要在代碼中做出任何指示.這個工具也來自由glibc-utils包.它以柱形顯示程式佔用了多少記憶體.它預設輸出到標準輸出中,用ASCII文本顯示一個繪成圖畫似的柱形.如下:memusage awk 'BEGIN{print "hello world"}'hello worldMemory usage summary: heap total: 7487, heap peak: 6891, stack peak: 8624 total calls total memory failed calls malloc| 58 7487 0realloc| 0 0 0 (nomove:0, dec:0, free:0) calloc| 0 0 0 free| 15 797Histogram for block sizes: 0-15 27 46% ================================================== 16-31 7 12% ============ 32-47 2 3% === 48-63 6 10% =========== 64-79 1 1% = 80-95 1 1% = 96-111 1 1% = 112-127 4 6% ======= 160-175 1 1% = 176-191 2 3% === 192-207 1 1% = 208-223 2 3% === 384-399 1 1% = 480-495 1 1% = 4000-4015 1 1% = 四)使用Electric Fence檢測記憶體流失Electric Fence用一些巧妙的技術來檢測程式在堆記憶體區上的溢出,不需要用Electric Fence來修改代碼,相反,它提供一個動態庫,這個庫有多個動態分配函數.一個名為ef的指令碼被用來處理環境變數LD_PRELOAD的設定,我們可以用ef命令來調用程式.下面是安裝Electric Fence,如下:rpm -ivh /mnt/Server/ElectricFence-2.2.2-20.2.2.i386.rpm我們下面用一個小程式做測試,原始碼如下:#include <string.h>intmain (int argc, char *argv[]){ int *ptr = new int; memset(ptr, 0, sizeof(int) + 1); delete ptr;}編譯:g++ new-corrupt.cpp -o new-corrupt注:這個小程式會導致邊界溢出.執行程式:./new-corrupt注:程式沒有任何指示.我們用ef執行這個程式,如下:ef ./new-corrupt Electric Fence 2.2.0 Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com>/usr/bin/ef: line 20: 4148 Segmentation fault ( export LD_PRELOAD=libefence.so.0.0; exec $* )注:此時有輸出資訊,它告訴我們出現了Segmentation {敏感詞}t,並且指明在哪行出現的問題.我們也可以將electric fence和gdb聯用,如下:編譯器,同時指定-g選項g++ -g new-corrupt.cpp -o new-corrupt 用gdb開啟程式,如下:gdb ./new-corruptGNU gdb Red Hat Linux (6.5-16.el5rh)Copyright (C) 2006 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB. Type "show warranty" for details.This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".(gdb) set environment LD_PRELOAD libefence.so.0.0 /*設定環境變數LD_PRELOAD為libefence.so.0.0*/(gdb) run /*運行程式*/Starting program: /root/new-corrupt Electric Fence 2.2.0 Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com> Electric Fence 2.2.0 Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com>Program received signal SIGSEGV, Segmentation fault.0x0804849d in main () at new-corrupt.cpp:7 /*檢查出在調用memset函數時導致越界*/7 memset(ptr, 0, sizeof(int) + 1);(gdb) quit下面我們在gdb中不指定環境變數,我們看到gdb沒有列印出相關的錯誤資訊.gdb ./new-corruptGNU gdb Red Hat Linux (6.5-16.el5rh)Copyright (C) 2006 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB. Type "show warranty" for details.This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".(gdb) runStarting program: /root/new-corrupt Program exited normally.