• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            曠野的呼聲

            路漫漫其修遠兮 吾將上下而求索

            常用鏈接

            統(tǒng)計

            最新評論

            【轉(zhuǎn)帖】Rational Purify 使用及分析實例

            Rational Purify 使用及分析實例

            developerWorks

            級別: 初級

            蔡 林, IBM 中國軟件開發(fā)中心軟件工程師

            2006 年 2 月 23 日

            本文介紹了 IBM Rational Purify的基本概念和在不同操作系統(tǒng)中使用Purify對C/C++源程序中存在的內(nèi)存問題進行勘察和分析,并且提供了有關(guān)的實例以便讀者在實際操作中作為參考。

            簡介

            本文介紹了IBM Rational Purify的基本概念和在不同操作系統(tǒng)中使用Purify對C/C++源程序中存在的內(nèi)存問題進行勘察和分析,并且提供了有關(guān)的實例以便讀者在實際操作中作為參考。






            1.內(nèi)存問題的原因及分類

            在C/C++程序中,有關(guān)內(nèi)存使用的問題是最難發(fā)現(xiàn)和解決的。這些問題可能導致程序莫名其妙地停止、崩潰,或者不斷消耗內(nèi)存直至資源耗盡。由于C/C++語言本身的特質(zhì)和歷史原因,程序員使用內(nèi)存需要注意的事項較多,而且語言本身也不提供類似Java的垃圾清理機制。編程人員使用一定的工具來查找和調(diào)試內(nèi)存相關(guān)問題是十分必要的。

            總的說來,與內(nèi)存有關(guān)的問題可以分成兩類:內(nèi)存訪問錯誤和內(nèi)存使用錯誤。內(nèi)存訪問錯誤包括錯誤地讀取內(nèi)存和錯誤地寫內(nèi)存。錯誤地讀取內(nèi)存可能讓你的模塊返回意想不到的結(jié)果,從而導致后續(xù)的模塊運行異常。錯誤地寫內(nèi)存可能導致系統(tǒng)崩潰。內(nèi)存使用方面的錯誤主要是指申請的內(nèi)存沒有正確釋放,從而使程序運行逐漸減慢,直至停止。這方面的錯誤由于表現(xiàn)比較慢很難被人工察覺。程序也許運行了很久才會耗凈資源,發(fā)生問題。

            1.1 內(nèi)存解剖

            一個典型的C++內(nèi)存布局如下圖所示:



            自底向上,內(nèi)存中依次存放著只讀的程序代碼和數(shù)據(jù),全局變量和靜態(tài)變量,堆中的動態(tài)申請變量和堆棧中的自動變量。自動變量就是在函數(shù)內(nèi)聲明的局部變量。當函數(shù)被調(diào)用時,它們被壓入棧;當函數(shù)返回時,它們就要被彈出堆棧。堆棧的使用基本上由系統(tǒng)控制,用戶一般不會直接對其進行控制,所以堆棧的使用還是相對安全的。動態(tài)內(nèi)存是一柄雙刃劍:它可以提供程序員更靈活的內(nèi)存使用方法,而且有些算法沒有動態(tài)內(nèi)存會很難實現(xiàn);但是動態(tài)內(nèi)存往往是內(nèi)存問題存在的沃土。

            1.2 內(nèi)存訪問錯誤

            相對用戶使用的語言,動態(tài)內(nèi)存的申請一般由malloc/new來完成,釋放由free/delete完成。基本的原則可以總結(jié)為:一對一,不混用。也就是說一個malloc必須對應(yīng)一且唯一的free;new對應(yīng)一且唯一的delete; malloc不能和delete, new不能和free對應(yīng)。另外在C++中要注意delete和delete[]的區(qū)別。delete用來釋放單元變量,delete[]用來釋放數(shù)組等集聚變量。有關(guān)這方面的詳細信息可以參考[C++Adv]。

            我們可以將內(nèi)存訪問錯誤大致分成以下幾類:數(shù)組越界讀或?qū)憽⒃L問未初始化內(nèi)存、訪問已經(jīng)釋放的內(nèi)存和重復釋放內(nèi)存或釋放非法內(nèi)存。

            下面的代碼集中顯示了上述問題的典型例子:


            1   #include <iostream>
                                    2   using namespace std;
                                    3   int main(){
                                    4      char* str1="four";
                                    5      char* str2=new char[4];	//not enough space
                                    6      char* str3=str2;
                                    7      cout<<str2<<endl;	//UMR
                                    8      strcpy(str2,str1);	//ABW
                                    9      cout<<str2<<endl;  //ABR
                                    10     delete str2;
                                    11     str2[0]+=2;	//FMR and FMW
                                    12     delete str3;	//FFM
                                    13   }
                                    

            由以上的程序,我們可以看到:在第5行分配內(nèi)存時,忽略了字符串終止符"\0"所占空間導致了第8行的數(shù)組越界寫(Array Bounds Write)和第9行的數(shù)組越界讀(Array Bounds Read); 在第7行,打印尚未賦值的str2將產(chǎn)生訪問未初始化內(nèi)存錯誤(Uninitialized Memory Read);在第11行使用已經(jīng)釋放的變量將導致釋放內(nèi)存讀和寫錯誤(Freed Memory Read and Freed Memory Write);最后由于str3和str2所指的是同一片內(nèi)存,第12行又一次釋放了已經(jīng)被釋放的空間 (Free Freed Memory)。

            這個包含許多錯誤的程序可以編譯連接,而且可以在很多平臺上運行。但是這些錯誤就像定時炸彈,會在特殊配置下觸發(fā),造成不可預見的錯誤。這就是內(nèi)存錯誤難以發(fā)現(xiàn)的一個主要原因。

            1.3 內(nèi)存使用錯誤

            內(nèi)存使用錯誤主要是指內(nèi)存泄漏,也就是指申請的動態(tài)內(nèi)存沒有被正確地釋放,或者是沒有指針可以訪問這些內(nèi)存。這些小的被人遺忘的內(nèi)存塊占據(jù)了一定的地址空間。當系統(tǒng)壓力增大時,這些越來越多的小塊將最終導致系統(tǒng)內(nèi)存耗盡。內(nèi)存使用錯誤比內(nèi)存訪問錯誤更加難以發(fā)現(xiàn)。這主要有兩點原因:第一,內(nèi)存使用錯誤是"慢性病",它的癥狀可能不會在少數(shù)、短時間的運行中體現(xiàn);第二,內(nèi)存使用錯誤是因為"不做為"(忘記釋放內(nèi)存)而不是"做錯"造成的。這樣由于忽略造成的錯誤在檢查局部代碼時很難發(fā)現(xiàn),尤其是當系統(tǒng)相當復雜的時候。






            2.Purify的原理及使用

            IBM Rational PurifyPlus是一組程序運行時的分析軟件。她包括了程序性能瓶頸分析軟件Quantify, 程序覆蓋面分析軟件PureCoverage,和本文的主角:程序運行錯誤分析軟件Purify。Purify可以發(fā)現(xiàn)程序運行時的內(nèi)存訪問,內(nèi)存泄漏和其他難以發(fā)現(xiàn)的問題。

            同時她也是市場上唯一支持多種平臺的類似工具,并且可以和很多主流開發(fā)工具集成。Purify可以檢查應(yīng)用的每一個模塊,甚至可以查出復雜的多線程或進程應(yīng)用中的錯誤。另外她不僅可以檢查C/C++,還可以對Java或.NET中的內(nèi)存泄漏問題給出報告。

            2.1 Purify的原理

            程序運行時的分析可以采用多種方法。Purify使用了具有專利的目標代碼插入技術(shù)(OCI:Object Code Insertion)。她在程序的目標代碼中插入了特殊的指令用來檢查內(nèi)存的狀態(tài)和使用情況。這樣做的好處是不需要修改源代碼,只需要重新編譯就可以對程序進行分析。

            對于所有程序中使用的動態(tài)內(nèi)存,Purify將它們按照狀態(tài)進行歸類。這可以由下圖來說明(來自[DEV205]):



            參見本文中以上給出的代碼,在程序第5行執(zhí)行后,str2處于黃色狀態(tài)。當在第7行進行讀的時候,系統(tǒng)就會報告一個訪問未初始化內(nèi)存錯誤(Uninitialized Memory Read)。因為只有在綠色狀態(tài)下,內(nèi)存才可以被合法訪問。

            為了檢查數(shù)據(jù)越界錯誤(ABR,ABW),Purify還在每個分配的內(nèi)存前后插入了紅色區(qū)域。這樣一來,超過邊界的訪問指令必定落在非法區(qū)域,從而觸發(fā)ABR或者ABW錯誤報告。這里需要指出一點。訪問未初始化內(nèi)存錯誤UMR在某些情況下其實是合法的操作,例如內(nèi)存拷貝。所以在分析報告時可以把UMR放到最后,或者干脆從結(jié)果中濾除。

            2.2 Purify的使用

            這里簡單介紹一下Purify在Windows和UNIX環(huán)境下的使用。

            在Windows中,只要運行Purify,填入需要分析的程序及參數(shù)就可。Purify會自動插入檢測代碼并顯示報告。報告的格式如下(來自[DEV205]):



            藍色的圖標代表一些運行的信息,比如開始和結(jié)束等。黃色是Purify給出的警告。通常UMR會作為警告列出。紅色則代表嚴重的錯誤。每一種相同的錯誤,尤其是在循環(huán)中的,會被集中在一起顯示,并且標明發(fā)生的次數(shù)。由每個錯誤的詳細信息,用戶可以知道相應(yīng)的內(nèi)存地址和源代碼的位置,并直接修改。另外用戶還可以設(shè)置不同的濾過器,用來隱藏暫時不關(guān)心的消息。

            在UNIX系統(tǒng)中,使用Purify需要重新編譯程序。通常的做法是修改Makefile中的編譯器變量。下面是用來編譯本文中程序的Makefile:


                    CC=purify gcc
                                    all: pplusdemo
                                    pplusdemo: pplusdemo.o
                                    $(CC) -o pplusdemo pplusdemo.o -lstdc++
                                    pplusdemo.o: pplusdemo.cpp
                                    $(CC) -g -c -w pplusdemo.cpp
                                    clean:
                                    -rm pplusdemo pplusdemo.o
                                    

            首先運行Purify安裝目錄下的purifyplus_setup.sh來設(shè)置環(huán)境變量,然后運行make重新編譯程序。需要指出的是,程序必須編譯成調(diào)試版本。在gcc中,也就是必須使用"-g"選項。在重新編譯的程序運行結(jié)束后,Purify會打印出一個分析報告。它的格式和含義與Windows平臺大同小異。

            下面是本文中的程序在Linux上Purify運行的結(jié)果:


                ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    UMR: Uninitialized memory read:
                                    * This is occurring while in:
                                    strlen         [rtlib.o]
                                    std::basic_ostream< char,std::char_traits< char>> & std::operator
                                    <<<std::char_traits< char>>(std::basic_ostream< char,std::char_traits<
                                    char>> &, char const *) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:7]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * Reading 1 byte from 0x80b45e0 in the heap.
                                    * Address 0x80b45e0 is at the beginning of a malloc'd block of 4 bytes.
                                    * This block was allocated from:
                                    malloc         [rtlib.o]
                                    operator new( unsigned) [libstdc++.so.5]
                                    operator new []( unsigned) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:5]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    ABW: Array bounds write:
                                    * This is occurring while in:
                                    strcpy         [rtlib.o]
                                    main           [pplusdemo.cpp:8]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * Writing 5 bytes to 0x80b45e0 in the heap (1 byte at 0x80b45e4 illegal).
                                    * Address 0x80b45e0 is at the beginning of a malloc'd block of 4 bytes.
                                    * This block was allocated from:
                                    malloc         [rtlib.o]
                                    operator new( unsigned) [libstdc++.so.5]
                                    operator new []( unsigned) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:5]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    ABR: Array bounds read:
                                    * This is occurring while in:
                                    strlen         [rtlib.o]
                                    std::basic_ostream< char,std::char_traits< char>> & std::operator
                                    <<<std::char_traits< char>>(std::basic_ostream< char,std::char_traits<
                                    char>> &, char const *) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:9]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * Reading 5 bytes from 0x80b45e0 in the heap (1 byte at 0x80b45e4 illegal).
                                    * Address 0x80b45e0 is at the beginning of a malloc'd block of 4 bytes.
                                    * This block was allocated from:
                                    malloc         [rtlib.o]
                                    operator new( unsigned) [libstdc++.so.5]
                                    operator new []( unsigned) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:5]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    FMM: Freeing mismatched memory:
                                    * This is occurring while in:
                                    operator delete( void *) [rtlib.o]
                                    main           [pplusdemo.cpp:10]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * Attempting to free block at 0x80b45e0 in the heap.
                                    * Address 0x80b45e0 is at the beginning of a malloc'd block of 4 bytes.
                                    * This block was allocated from:
                                    malloc         [rtlib.o]
                                    operator new( unsigned) [libstdc++.so.5]
                                    operator new []( unsigned) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:5]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * This block of memory was obtained using an allocation routine which is
                                    not compatible with the routine by which it is being freed.
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    FMR: Free memory read:
                                    * This is occurring while in:
                                    main           [pplusdemo.cpp:11]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * Reading 1 byte from 0x80b45e0 in the heap.
                                    * Address 0x80b45e0 is at the beginning of a freed block of 4 bytes.
                                    * This block was allocated from:
                                    malloc         [rtlib.o]
                                    operator new( unsigned) [libstdc++.so.5]
                                    operator new []( unsigned) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:5]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * There have been 0 frees since this block was freed from:
                                    free           [rtlib.o]
                                    _ZdLpV         [libstdc++.so.5]
                                    main           [pplusdemo.cpp:10]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    FMW: Free memory write:
                                    * This is occurring while in:
                                    main           [pplusdemo.cpp:11]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * Writing 1 byte to 0x80b45e0 in the heap.
                                    * Address 0x80b45e0 is at the beginning of a freed block of 4 bytes.
                                    * This block was allocated from:
                                    malloc         [rtlib.o]
                                    operator new( unsigned) [libstdc++.so.5]
                                    operator new []( unsigned) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:5]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * There have been 0 frees since this block was freed from:
                                    free           [rtlib.o]
                                    _ZdLpV         [libstdc++.so.5]
                                    main           [pplusdemo.cpp:10]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    FUM: Freeing unallocated memory:
                                    * This is occurring while in:
                                    free           [rtlib.o]
                                    _ZdLpV         [libstdc++.so.5]
                                    main           [pplusdemo.cpp:12]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * Attempting to free block at 0x80b45e0 already freed.
                                    * This block was allocated from:
                                    malloc         [rtlib.o]
                                    operator new( unsigned) [libstdc++.so.5]
                                    operator new []( unsigned) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:5]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * There have been 1 frees since this block was freed from:
                                    free           [rtlib.o]
                                    _ZdLpV         [libstdc++.so.5]
                                    main           [pplusdemo.cpp:10]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    Current file descriptors in use: 5
                                    FIU: file descriptor 0: <stdin>
                                    FIU: file descriptor 1: <stdout>
                                    FIU: file descriptor 2: <stderr>
                                    FIU: file descriptor 26: <reserved for Purify internal use>
                                    FIU: file descriptor 27: <reserved for Purify internal use>
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    Purify: Searching for all memory leaks...
                                    Memory leaked: 0 bytes (0%); potentially leaked: 0 bytes (0%)
                                    Purify Heap Analysis (combining suppressed and unsuppressed blocks)
                                    Blocks        Bytes
                                    Leaked          0            0
                                    Potentially Leaked          0            0
                                    In-Use          0            0
                                    ----------------------------------------
                                    Total Allocated          0            0
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    * Program exited with status code 0.
                                    * 7 access errors, 7 total occurrences.
                                    * 0 bytes leaked.
                                    * 0 bytes potentially leaked.
                                    * Basic memory usage (including Purify overhead):
                                    290012 code
                                    152928 data/bss
                                    6816 heap (peak use)
                                    7800 stack
                                    

            我們對照程序可以發(fā)現(xiàn)Purify查出了程序中所有的錯誤。對于每個錯誤,她不但給出了源代碼的位置還指出這些內(nèi)存最初分配的源代碼位置。這對于查找問題提供了很大幫助。對于程序12行的解釋,Purify將其認為是不匹配的內(nèi)存釋放(FMM: Freeing mismatched memory),因為她認為這樣的釋放方式不符合嚴格的規(guī)定。

            Purify在其報告和文檔中使用了很多的縮寫,在此一并列出,以便讀者在使用時參考(來自[Purify]):



            2.3 Purify的一些特性

            這里簡單介紹一下Purify提供的幾個特性。有關(guān)這些特性的詳細信息,請查閱文檔[Purify]。

            • 觀察點(Watchpoint):通過在程序或者調(diào)試器中調(diào)用Purify 提供的觀察點函數(shù),Purify可以報告有關(guān)被觀察對象的讀寫或其他操作。
            • 與Rational其他產(chǎn)品的集成:在Puify的用戶界面中可以方便地進入ClearCase和ClearQuest。Purify還可以和PureCoverage同時使用,對程序進行分析。
            • Purify的定制:無論是Purify報告中的消息,還是界面中的元素,都可以進行一定程度的定制。另外通過修改配置文件和調(diào)用Purify API,用戶還可以自動記錄運行日志,發(fā)送電子郵件等。
            • Purify提供的API:為了更好地把Purify融合到自動化測試的體系中,Purify提供了一系列的公開函數(shù)。用戶完全可以通過腳本的方式自動運行,記錄,和分析Purify。





            3.總結(jié)

            當使用C/C++進行開發(fā)時,采用良好的一致的編程規(guī)范是防止內(nèi)存問題第一道也是最重要的措施。在此前提下,IBM Rational Purify作為一種運行時分析軟件可以很好地幫助您發(fā)現(xiàn)忽略的內(nèi)存問題,或成為軟件自動測試中的一個重要組成部分。






            4.參考資料

            [C++Adv]
            [DEV205] Essentials of Rational PurifyPlus
            [Purify] IBM Rational PurifyPlus for Linux and UNIX Documentation



            關(guān)于作者

             

            蔡林,IBM 中國軟件開發(fā)中心軟件工程師,2004年獲得美國Baylor University計算機系碩士學位,同年加入IBM 中國軟件開發(fā)中心,從事Rational ClearQuest G11N的開發(fā)工作。

            posted on 2009-05-25 23:36 董波 閱讀(981) 評論(0)  編輯 收藏 引用

            久久久久亚洲AV成人网人人网站 | 国产精品久久久久jk制服| 7777精品伊人久久久大香线蕉| 久久久黄色大片| 国产美女亚洲精品久久久综合| 亚洲伊人久久大香线蕉综合图片 | 久久综合丝袜日本网| 色综合合久久天天给综看| 久久久久女人精品毛片| 久久久久国产精品麻豆AR影院| 久久久久精品国产亚洲AV无码| 日本久久久久久中文字幕| 久久久久久久综合狠狠综合| 亚洲国产成人久久精品动漫| 亚洲va久久久久| 国产日韩久久久精品影院首页| 久久国产色av免费看| 久久精品国产一区二区电影| 久久狠狠高潮亚洲精品| 区亚洲欧美一级久久精品亚洲精品成人网久久久久 | 久久99精品久久久久久久久久| 日本亚洲色大成网站WWW久久| 久久精品水蜜桃av综合天堂 | 国产午夜精品久久久久九九| 中文字幕人妻色偷偷久久 | 免费无码国产欧美久久18| 99久久精品久久久久久清纯| 久久精品无码午夜福利理论片| 久久天天躁夜夜躁狠狠躁2022| 久久国产成人午夜AV影院| 国产精品久久99| 久久午夜无码鲁丝片| 欧美牲交A欧牲交aⅴ久久| 久久久久久国产精品美女| 一级做a爰片久久毛片看看| 午夜不卡888久久| 国产亚洲成人久久| 久久久久无码中| 久久亚洲sm情趣捆绑调教| 亚洲精品综合久久| 久久久久99这里有精品10 |