博主的新Blog地址:http://www.brantchen.comlinux
歡迎訪問:)
linux下的測試工具真是少之又少,還很差用,近期試用了memwatch,感受網上的介紹不太好,因此放在這裏跟你們分享 。事實上大部分都是看的幫助,很是多地方翻譯得很差還有錯,請原諒指出最好看原文。假設轉載或引用,請註明個人博客地址,謝謝。安全
MemWatch由 Johan Lindh 編寫,是一個開放源碼 C 語言內存錯誤檢測工具。MemWatch支持 ANSI C,它提供結果日誌紀錄,能檢測雙重釋放(double-free)、錯誤釋放(erroneous free)、內存泄漏(unfreed memory)、溢出(Overflow)、下溢(Underflow)等等。app
MemWatch將所有分配的內存用0xFE填充,因此,假設你看到錯誤的數據是用0xFE填充的,那就是你沒有初始化數據。例外是calloc(),它會直接把分配的內存用0填充。函數
MemWatch將所有已釋放的內存用0xFD填充(zapped with 0xFD).假設你發現你使用的數據是用0xFD填充的,那你就使用的是已釋放的內存。在這樣的狀況,注意MemWatch會立刻把一個"釋放了的塊信息"填在釋放了的數據前。這個塊包含關於內存在哪兒釋放的信息,以可讀的文本形式存放,格式爲"FBI<counter>filename(line)"。如:"FBI<267>test.c(12)".使用FBI會減小free()的速度,因此默認是關閉的。使用mwFreeBufferInfo(1)開啓。工具
爲了幫助跟蹤野指針的寫狀況,MemWatch能提供no-mans-land(NML)內存填充。no-mans-land將使用0xFC填充.當no-mans-land開啓時,MemWatch轉變釋放的內存爲NML填充狀態。學習
通常來講,在程序中使用MemWatch的功能,需要手動加入mwInit()進行初始化,並用相應的mwTerm ()進行結束處理。spa
固然,假設沒有手動調用mwInit(),MemWatch能本身主動初始化.假設是這樣的情形,memwatch會使用atext()註冊mwTerm()用於atexit-queue.對於使用本身主動初始化技術有一個告誡;假設你手動調用atexit()以進行清理工做,memwatch可能在你的程序結束前就終止。爲了安全起見,請顯式使用mwInit()和mwTerm().線程
涉及的函數主要有:翻譯
mwInit() mwTerm() mwAbort()指針
對於通常的操做,MemWatch建立memwatch.log文件。有時,該文件不能被建立;MemWatch會試圖建立memwatNN.log文件,NN在01~99之間。
假設你不能使用日誌,或者不想使用,也沒有問題。僅僅要使用類型爲"void func(int c)"的參數調用mwSetOutFunc(),而後所有的輸出都會按字節定向到該函數.
當ASSERT或者VERIFY失敗時,MemWatch也有Abort/Retry/Ignore處理機制。默認的處理機制沒有I/O操做,但是會本身主動中斷程序。你可以使用不論什麼其它Abort/Retry/Ignore的處理機制,僅僅要以參數"void func(int c)"調用mwSetAriFunc()。後面在1.2使用一節會具體解說。
涉及的函數主要有:
mwTrace() mwPuts() mwSetOutFunc() mwSetAriFunc()
mwSetAriAction() mwAriHandler() mwBreakOut()
可以將MemWatch用於C++,但是不推薦這麼作。請具體閱讀memwatch.h中關於對C++的支持。
Ø
在要使用MemWatch的.c文件裏包括頭文件"memwatch.h"
Ø
使用GCC編譯(注意:不是連接)本身的程序時,增長-DMEMWATCH -DMW_STDIO
如:gcc -DMEMWATCH -DMW_STDIO –o test.o
–c test1.c
1)在程序中常用的MemWatch功能有:
Ø mwTRACE( const char* format_string, ... );
或TRACE( const char* format_string, ... );
Ø mwASSERT( int, const char*, const char*, int )
或ASSERT( int, const char*, const char*, int )
Ø mwVERIFY( int, const char*, const char*, int )
或VERIFY( int, const char*, const char*, int )
Ø mwPuts( const char* text )
Ø ARI機制(mwSetAriFunc(int (*func)(const char *)),
mwSetAriAction(int action),
mwAriHandler( const char* cause ))
Ø mwSetOutFunc(void (*func)(int))
Ø mwIsReadAddr(const void *p, unsigned len )
Ø mwIsSafeAddr(void *p, unsigned len )
Ø mwStatistics( int level )
Ø mwBreakOut( const char* cause)
2)mwTRACE,mwASSERT,mwVERIFY和mwPuts顧名思義,就再也不贅述。僅需要注意的是,Memwatch定義了宏TRACE, ASSERT 和 VERIFY.假設你已使用同名的宏,memwatch2.61及更高版本號的memwatch不會覆蓋你的定義。MemWatch2.61及之後,定義了mwTRACE, mwASSERT和 mwVERIFY宏,這樣,你就能肯定使用的是memwatch的宏定義。2.61版本號前的memwatch會覆蓋已存在的同名的TRACE, ASSERT和 VERIFY定義。
固然,假設你不想使用MemWatch的這幾個宏定義,可以定義MW_NOTRACE, MW_NOASSERT和 MW_NOVERIFY宏,這樣MemWatch的宏定義就不起做用了。所有版本號的memwatch都遵守這個規則。
3)ARI機制即程序設置的「Abort, Retry, Ignore選擇陷阱。
mwSetAriFunc:
設置「Abort, Retry, Ignore」發生時的MemWatch調用的函數.當這樣設置調用的函數地址時,實際的錯誤消息不會打印出來,但會做爲一個參數進行傳遞。
假設參數傳遞NULL,ARI處理函數會被再次關閉。當ARI處理函數關閉後, meewatch會本身主動調用有mwSetAriAction()指定的操做。
正常狀況下,失敗的ASSERT() or VERIFY()會中斷你的程序。但這可以經過mwSetAriFunc()改變,即經過將函數"int myAriFunc(const char *)"傳給它實現。你的程序必須詢問用戶是否中斷,重試或者忽略這個陷阱。返回2用於Abort, 1用於Retry,或者0對於Ignore。注意retry時,會致使表達式又一次求值.
MemWatch有個默認的ARI處理器。默認是關閉的,但你能經過調用mwDefaultAri()開啓。注意這仍然會停止你的程序除非你定義MEMWATCH_STDIO贊成MemWatch使用標準C的I/O流。
同一時候,設置ARI函數也會致使MemWatch不將ARI的錯誤信息寫向標準錯誤輸出,錯誤字符串而是做爲'const char *'參數傳遞到ARI函數.
mwSetAriAction:
假設沒有ARI處理器被指定,設置默認的ARI返回值。默認是MW_ARI_ABORT
mwAriHandler:
這是個標準的ARI處理器,假設你喜歡就雖然用。它將錯誤輸出到標準錯誤輸出,並從標準輸入得到輸入。
mwSetOutFunc:
將輸出轉向調用者給出的函數(參數即函數地址)。參數爲NULL,表示把輸出寫入日誌文件memwatch.log.
mwIsReadAddr:
檢查內存是否有讀取的權限
mwIsSafeAddr:
檢查內存是否有讀、寫的權限
mwStatistics:
設置狀態蒐集器的行爲。相應的參數採用宏定義。
#define MW_STAT_GLOBAL 0 /* 僅蒐集全局狀態信息 */
#define MW_STAT_MODULE 1 /* 蒐集模塊級的狀態信息 */
#define MW_STAT_LINE 2 /* 蒐集代碼行級的狀態信息 */
#define MW_STAT_DEFAULT 0 /* 默認狀態設置 */
mwBreakOut:
當某些狀況MemWatch認爲中斷(break into)編譯器更好時,就調用這個函數.假設你喜歡使用MemWatch,那麼可以在這個函數上設置運行斷點。
其它功能的使用,請參考源碼的說明。
日誌文件memwatch.log中包括的信息主要有下面幾點:
Ø 測試日期
Ø 狀態蒐集器的信息
Ø 使用MemWatch的輸出函數或宏(如TRACE等)的信息。
Ø MemWatch捕獲的錯誤信息
Ø 內存使用的全局信息統計,包含四點:1)分配了多少次內存 2)最大內存使用量3)分配的內存總量 4)爲釋放的內存總數
MemWatch捕獲的錯誤記錄在日誌文件裏的輸出格式例如如下:
message: <sequence-number> filename(linenumber), information
mwInit()和mwTerm()是相應的.因此使用了多少次mwInit(),就需要調用多少次
mwTerm()用於終止MemWatch.
假設在流程中捕獲了程序的異常中斷,那麼需要調用mwAbort()而不是
mwTerm()。即便有顯示的調用mwTerm(),mwAbort()也將終止MemWatch。
MemWatch不能確保是線程安全的。假設你碰巧使用Wind32或者你使用了線程,做爲2.66,是初步支持線程的。定義WIN32或者MW_PTHREADS以明白支持線程。這會致使一個全局相互排斥變量產生,同一時候當訪問全局內存鏈時,MemWatch會鎖定相互排斥變量,但這遠不能證實是線程安全的。
從MemWatch的使用可以得知,沒法用於內核模塊。因爲MemWatch自身就使用了應用層的接口,而不是內核接口。但是,對於普通的應用層程序,我以爲仍是比較實用,並且是開源的,可以本身改動代碼實現;它能方便地查找內存泄漏,特別是提供的接口函數簡單易懂,學習掌握很是easy,相應用層程序的單元測試會較適用。
博主的新Blog地址:http://www.brantchen.com
歡迎訪問:)