memwatch的使用

博主的新Blog地址:http://www.brantchen.comlinux

歡迎訪問:)


       linux下的測試工具真是少之又少,還很差用,近期試用了memwatch,感受網上的介紹不太好,因此放在這裏跟你們分享 。事實上大部分都是看的幫助,很是多地方翻譯得很差還有錯,請原諒指出最好看原文。假設轉載或引用,請註明個人博客地址,謝謝。安全

       

1介紹

MemWatch Johan Lindh 編寫,是一個開放源碼 C 語言內存錯誤檢測工具。MemWatch支持 ANSI C,它提供結果日誌紀錄,能檢測雙重釋放(double-free)、錯誤釋放(erroneous free)、內存泄漏(unfreed memory)、溢出(Overflow)、下溢(Underflow)等等。app

 

1.1 MemWatch的內存處理

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-landNML)內存填充。no-mans-land將使用0xFC填充.no-mans-land開啓時,MemWatch轉變釋放的內存爲NML填充狀態。學習

 

1.2初始化和結束處理

通常來講,在程序中使用MemWatch的功能,需要手動加入mwInit()進行初始化,並用相應的mwTerm ()進行結束處理。spa

固然,假設沒有手動調用mwInit()MemWatch能本身主動初始化.假設是這樣的情形,memwatch會使用atext()註冊mwTerm()用於atexit-queue.對於使用本身主動初始化技術有一個告誡;假設你手動調用atexit()以進行清理工做,memwatch可能在你的程序結束前就終止。爲了安全起見,請顯式使用mwInit()mwTerm().線程

涉及的函數主要有:翻譯

mwInit()   mwTerm()    mwAbort()指針

 

1.3 MemWatchI/O操做

對於通常的操做,MemWatch建立memwatch.log文件。有時,該文件不能被建立;MemWatch會試圖建立memwatNN.log文件,NN01~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()

 

1.4 MemWatchC++的支持

   可以將MemWatch用於C++,但是不推薦這麼作。請具體閱讀memwatch.h中關於對C++的支持。

 

2使用

2.1爲本身的程序提供MemWatch功能

Ø       在要使用MemWatch.c文件裏包括頭文件"memwatch.h"

Ø       使用GCC編譯(注意:不是連接)本身的程序時,增長-DMEMWATCH -DMW_STDIO
如:gcc -DMEMWATCH -DMW_STDIO –o test.o
–c test1.c

 

2.2使用MemWatch提供的功能

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)

 

2mwTRACEmwASSERTmwVERIFYmwPuts顧名思義,就再也不贅述。僅需要注意的是,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都遵守這個規則。

3ARI機制即程序設置的「Abort, Retry, Ignore選擇陷阱。

mwSetAriFunc

設置「Abort, Retry, Ignore」發生時的MemWatch調用的函數.當這樣設置調用的函數地址時,實際的錯誤消息不會打印出來,但會做爲一個參數進行傳遞。

假設參數傳遞NULLARI處理函數會被再次關閉。當ARI處理函數關閉後, meewatch會本身主動調用有mwSetAriAction()指定的操做。

正常狀況下,失敗的ASSERT() or VERIFY()會中斷你的程序。但這可以經過mwSetAriFunc()改變,即經過將函數"int myAriFunc(const char *)"傳給它實現。你的程序必須詢問用戶是否中斷,重試或者忽略這個陷阱。返回2用於Abort 1用於Retry,或者0對於Ignore。注意retry時,會致使表達式又一次求值.

 MemWatch有個默認的ARI處理器。默認是關閉的,但你能經過調用mwDefaultAri()開啓。注意這仍然會停止你的程序除非你定義MEMWATCH_STDIO贊成MemWatch使用標準CI/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,那麼可以在這個函數上設置運行斷點。

其它功能的使用,請參考源碼的說明。

 

2.3分析日誌文件

日誌文件memwatch.log中包括的信息主要有下面幾點:

Ø        測試日期

Ø        狀態蒐集器的信息

Ø        使用MemWatch的輸出函數或宏(如TRACE等)的信息。

Ø        MemWatch捕獲的錯誤信息

Ø        內存使用的全局信息統計,包含四點:1)分配了多少次內存 2)最大內存使用量3)分配的內存總量 4)爲釋放的內存總數

MemWatch捕獲的錯誤記錄在日誌文件裏的輸出格式例如如下:

message: <sequence-number> filename(linenumber), information

 

2.4注意事項

mwInit()mwTerm()是相應的.因此使用了多少次mwInit(),就需要調用多少次

mwTerm()用於終止MemWatch.

 

假設在流程中捕獲了程序的異常中斷,那麼需要調用mwAbort()而不是

mwTerm()。即便有顯示的調用mwTerm()mwAbort()也將終止MemWatch

 

MemWatch不能確保是線程安全的。假設你碰巧使用Wind32或者你使用了線程,做爲2.66,是初步支持線程的。定義WIN32或者MW_PTHREADS以明白支持線程。這會致使一個全局相互排斥變量產生,同一時候當訪問全局內存鏈時,MemWatch會鎖定相互排斥變量,但這遠不能證實是線程安全的。

 

3結論

    MemWatch的使用可以得知,沒法用於內核模塊。因爲MemWatch自身就使用了應用層的接口,而不是內核接口。但是,對於普通的應用層程序,我以爲仍是比較實用,並且是開源的,可以本身改動代碼實現;它能方便地查找內存泄漏,特別是提供的接口函數簡單易懂,學習掌握很是easy,相應用層程序的單元測試會較適用。

 

 

博主的新Blog地址:http://www.brantchen.com

歡迎訪問:)
相關文章
相關標籤/搜索