病態代碼測試--valgrind測試報告

0。前提準備:
   
    (1)將sal/unxlngi6.pro/lib/libsalalloc_malloc.so拷入/usr/lib目錄下。
    (2)在將要啓動valgrind的終端下執行如下操作:
            export LD_PRELOAD=libsalalloc_malloc.so
    (3)在第(2)步設定好的終端下啓動valgrind開始測試。
    以上操作只在m46版本之前有效,以上設定強迫openoffice使用系統(操作系統)標準的堆使用方法,即a malloc-based memory allocator,因爲valgrind主要偵測程序代碼中對malloc/free的標準的系統調用,所以如果openoffice使用了基於其它內存管理分配方式的allocator,則會影響valgrind偵測到一些錯誤類型。所以我們要強迫openoffice使用系統標準的 malloc/free方式來使用內存,而不是使用自定義的。

1。使用了未初始化的內存
   
    (1a)例子
         (1)代碼:
        {
            int i[5];
            if( i[0] == 0 )
                        i[1] = 1;
            return 0;
         }
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window* pWindow )
        {
            ...
            //add code here .
        }
        (3)代碼分析:
        很顯然int i[5]沒有初始化,此處爲:未初始化內存讀(UMR)
        (4)工具檢測出否:
        檢測出
        (5)工具所報錯誤:
        conditional jump or move depends on uninitialised value(s)
        (6)工具所報錯誤正確否:
        正確,使用了一個未初始化的變量作爲跳轉依據。
        (7)工具設定了哪些特定參數:
        valgrind --tool=memcheck --leak-check=full --db-attach=yes ./soffice.bin

    (1b)例子
        (1)代碼:
       
         char  strForUMR[4];
         printf("%s /n",strForUMR); //對未初始化內存讀。UMR
        (2)代碼位置:           
                    sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
       


        (3)代碼分析:
            上面代碼讀了一塊未初始化的數組。

       (4)工具檢測出否:可以檢測出
       (5)工具所報錯誤:
             error1:conditional jump or move depends on uninitialised value(s)(SlideSorterViewShell.cxx:622)
            error2:use of uninitialised value of size 4(SlideSorterViewShell.cxx:622)
            error3:invalid read of size 1(SlideSorterViewShell.cxx:622)
        (6)工具所報錯誤正確否:正確
        (7)工具設定了哪些特定參數:valgrind ./soffice.bin即可


    (1c)例子

        (1)代碼:
         char* strForUMR = new char[4];       
         printf("%s /n",strForUMR); //對未初始化內存讀。UMR

        (2)代碼位置:
                                                    sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }

        (3)代碼分析:
            讀堆上未初始化內存。
        (4)工具檢測出否:
            如果在測試前做了“前提準備”的話,則valgrind可以準確檢測出此錯誤。
        (5)工具所報錯誤:
             error1:Conditional jump or move depends on uninitialised                 value(s)at(SlideSorterViewShell.cxx:673)
           
        (6)工具所報錯誤正確否:
            工具所報錯誤完全正確。
        (7)工具設定了哪些特定參數:
            valgrind ./soffice.bin
           

    (1d)例子

        (1)代碼:
                {
                int num1, num2;
                num1 = num2;//UMC
                }
        (2)代碼位置:
                                                                    sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
            num2是一個未初始化的變量。
        (4)工具檢測出否:
            不能檢測出來
        (5)工具所報錯誤:
        (6)工具所報錯誤正確否:
        (7)工具設定了哪些特定參數:

    (1e)例子
        (1)代碼:

                int num1, num2;
                num1 = num2;//UMC
                if( num1 == 2 ) num1 = 0;
        (2)代碼位置:

            sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
        (1e)只比(1d)多一條if語句,依據未初始化變量跳轉。
        (4)工具檢測出否:
        valgrind 可以檢測出來,看來valgrind也可以檢測(1d)那樣的代碼,但是(1d)那樣的代碼並沒有對程序的運行產生什麼可預測的危害,故valgrind 出於檢測速度考慮沒有必要報告之,但對於(1e)情況就不同了,未初始化的變量很顯然對程序的運行產生了不良影響,故valgrind檢測並報告這段代碼中有未初始化的變量,且被用於if判斷。對於未初始化資源,在其還沒有要做惡的表象時(即未被使用之時),valgrind不是判其有罪,如果 valgrind發現其要做惡,比如if判斷中使用了未初始化資源時,則valgrind必報告之,因爲if的無效跳轉是程序不穩定,甚至崩潰的主要根源之一!
        (5)工具所報錯誤:
        error1: condicontional jump or move depends on uninitialised value(s)
        (6)工具所報錯誤正確否:
        正確
        (7)工具設定了哪些特定參數:valgrind ./soffice.bin

2.內存泄露

    (2a)例子

        (1)代碼:
            {
                char *p1;
                char *p2;

                p1 = (char *) malloc(512);
                p2 = (char *) malloc(512);

                p1 = p2;
               
                free(p1);
                free(p2);//二次釋放。
            }
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
        從上面代碼可知,p1的指向被改變了,並且無法找回,最終導致512個字節無法釋    放,上面代碼存在的另一個問題是:“內存二次釋放”,因爲 p1,p2指向同一塊        內    存空間,導致同一塊內存空間被釋放二次,這會導致程序不穩定,或崩潰!
        (4)工具檢測出否:
            檢測出二次釋放,若加下--leak-check=full則可以明確報出p1所指的512字節泄露了,不加此參數則只報有內存泄露,但具體位置不報。
        (5)工具所報錯誤:
            error1:invlid free() in SlideSorterViewShell.cxx:625
            error2:2,048 bytes in 4 blocks are definitely lost in loss record 166 of 199(SlideSorterViewShell.cxx:619)
        (6)工具所報錯誤正確否:
            工具報錯正確。
        (7)工具設定了哪些特定參數:
            valgrind --leak-check=full ./soffice.bin


    (2b)例子
        (1)代碼:
            {
                int* pi = new int[10];
               
                if(1) return;

                if(pi != NULL )delete[] pi;
            }
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
            由於不合理的跳轉而導致delete語句沒有被執行到,最終資源泄露。
        (4)工具檢測出否:
            沒有檢測出來,看來此來問題由程序員自己來控制比較好,由於代碼邏輯設計的不合理,導致大量的跳轉,最終造成泄露,工具不是萬能的,工具並不能完全理解代碼的邏輯。
        (5)工具所報錯誤:
        (6)工具所報錯誤正確否:
        (7)工具設定了哪些特定參數:

    (2c)例子
        (1)代碼:
           
            {
                try
                {
                    int* pi = new int[10];
                    if(1) throw 99;
                    if( pi != NULL ) delete pi;
                }catch( int I ){}
            }
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
            由於拋出異常而導致delete語句沒有被執行到,最終資源泄露。
        (4)工具檢測出否:
            沒有檢測出來,看來此來問題由程序員自己來控制比較好,由於拋出異常而導致的跳轉,最終造成泄露,工具不是萬能的,工具並不能完全覆蓋代碼的所有執行路徑,包括異常路徑。
        (5)工具所報錯誤:
        (6)工具所報錯誤正確否:
        (7)工具設定了哪些特定參數:valgrind --leak-check=full ./soffice.bin

    (2d)例子
        (1)代碼:
            {
                    FILE* fp;
                    int key;
           
                    fp = fopen( filename, “r”);
                    fscanf( fp, “%d”, &key );
                    return key;
            }
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
            系統中資源不僅只有內存一家,還有很多,如:文件句柄,socket等。
        (4)工具檢測出否:
            沒有檢測出來,看來此來問題由程序員自己來控制比較好,valgrind的專長不在於此。
        (5)工具所報錯誤:
        (6)工具所報錯誤正確否:
        (7)工具設定了哪些特定參數:

3.非法讀/寫

    (    3a)例子
        (1)代碼:
            {
                int i;
                int iw[10], ir[10];
               
                for( i =0; i<11; i++ )
                                iw = i;
                for( i = 0; i<11; i++ )
                                ir = iw;

            }
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
            數組訪問越界。
        (4)工具檢測出否:
            沒有檢測出來,valgrind對於在棧和靜態存儲區上分配的內存塊檢測能力有限,其主要是對堆上分配的內存塊進行檢測,這是它的強項。但是當把循環次數從11增至110時valgrind與gdb 皆報出崩潰錯誤。
        (5)工具所報錯誤:
        valgrind: jump to the invalid address stated on the next line.
        Gdb :program received signal SIGSEGV,segmentation fault.
        (6)工具所報錯誤正確否:
            沒有報出具體位置,所以需要自已追蹤之。
        (7)工具設定了哪些特定參數:valgrind --leak-check=full ./soffice.bin

    (3b)例子
        (1)代碼:
            {
                char p[5];
                strcpy(p, “Hello, world.”);//數組p容不下這很多的字符,越界了。
                puts(p);
            }
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
            p太小,不足矣容納”Hello, world.”故對數組p[5]寫越界。
        (4)工具檢測出否:
            valgrind及gdb皆報錯,但錯誤來自Paint的上一級調用,報調用Paint函數時出現段錯誤。
        (5)工具所報錯誤:
            gdb: program received signal SIGSEGV , segmentaion fault
        at /sd/source/ui/view/sdwindow.cxx:321
        valgrind: invalid  read of size 4 at sd::Window::Paint( Rectangle const & )(sdwindow.cxx:321)
        (6)工具所報錯誤正確否:
            所報錯是相關性的,由上例代碼引發的,雖未直接標定例子中的代碼。
        (7)工具設定了哪些特定參數:

    (3c)例子
        (1)代碼:
            {
              int i;
            int* iw = (int*) malloc(sizeof(int) * 10 );
            int* ir = (int*) malloc(sizeof(int) * 10 );
 
            for( i = 0; i < 110; i++ ) iw = i;
            for( i = 0; i < 110; i++ ) ir = iw;
             }
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
            在堆上分配一個數組,使用中出現訪問越界。
        (4)工具檢測出否:
            valgrind可以明確地檢測出來,並準確定到源碼位置。看來valgrind對於堆上出現的問題的檢測能力是相當強的。
        (5)工具所報錯誤:
        invalid write of size 4 at(SlideSorterViewShell.cxx:619)
        (6)工具所報錯誤正確否:
        valgrind報錯準確。
        (7)工具設定了哪些特定參數:valgrind ./soffice.bin


    (3d)例子
        (1)代碼:
            {
                const char *name = "Beijing RedOffice 2000 Software Co., Ltd";
                char * charForABWABR  = (char*) malloc(10);
                strncpy(charForABWABR, name, 10);
                charForABWABR[11] = '/0'; //數組越寫。

                printf("%s /n",charForABWABR);//數組越界讀。
            }
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
            堆上分配的數組,使用中出現訪問越界(讀寫越界)。
        (4)工具檢測出否:
            工具可以準確地檢測出錯誤,並準確地定位出問題在源碼中的位置。
        (5)工具所報錯誤:
            error1:invalid write of size 1 at (SlideSorterViewShell.cxx:618)
            error2:invalid read of size 1 at(SlideSorterViewShell.cxx:619)
        (6)工具所報錯誤正確否:
            工具所報錯誤非常準確。
        (7)工具設定了哪些特定參數:valgrind ./soffice.bin

    (3e)例子
        (1)代碼:
            void genIPR()//無效指針讀寫。
             {
                    int *ipr = (int *) malloc(4 * sizeof(int));
                     int i, j;
                    i = *(ipr - 1000); j = *(ipr + 1000); /* Expect IPR */
                   free(ipr);
              }

            void genIPW()
            {
                    int *ipw = (int *) malloc(5 * sizeof(int));
                     *(ipw - 1000) = 0; *(ipw + 1000) = 0; /* Expect IPW */
                  free(ipw);
            }
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
            很顯然代碼中給指針加入一個偏移值,使其指向了一個非法的內存位置 ,最終造成了對非法內存位置的讀寫。
        (4)工具檢測出否:
        工具可以準確地檢測並定位出錯誤及對應的源碼位置 。
       
        (5)工具所報錯誤:
            error1:invalid read of size 4 at(SlideSorterViewShell.cxx:618)
            error2:invalid read of size 4 at(SlideSorterViewShell.cxx:619)
            error3:invalid write of size 4 at(SlideSorterViewShell.cxx:623)
            error4:invalid write of size 4 at(SlideSorterViewShell.cxx:624)
        (6)工具所報錯誤正確否:
            工具報錯誤準確。
        (7)工具設定了哪些特定參數:
            valgrind ./soffice.bin

4.讀寫已經釋放的內存(使用無效指針)
    注意:讀寫已釋放的內存塊,是隨機性崩潰的根源之一!如果你釋放的內存塊沒有立即被系統收回重用時,讀寫此塊內存一般不會導致程序崩潰,甚至程序沒有任何不良表現。但如果你釋放的內存塊立即被系統收回重用時,此時再讀寫之則多數會導致程序崩潰!
    (4a)例子
        (1)代碼:
            struct X{ int q;} *xp;

            xp = (struct X *) malloc( sizeof( struct X ) );
            xp->q = 13;
            free(xp);
            /*此後xp所指的內存塊自由了,可能已被重新分配了*/
            xp->q = 15;//寫已釋放的內存,可能立即崩潰。也可能破壞其它程序的數據。
            return xp->q;//讀已釋放的內存。           
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
            代碼中已註釋明確。
        (4)工具檢測出否:
            valgrind可以準確檢測錯誤並給出準確位置。
        (5)工具所報錯誤:
            invalid write of size 4 at(SlideSorterViewShell.cxx:621)
        (6)工具所報錯誤正確否:
            報錯準確。
        (7)工具設定了哪些特定參數:valgrind ./soffice.bin

    (4b)例子
        (1)代碼:   
                char* str2 = new char[4];
                delete [] str2;
                str2[0]+=2;    //FMR and FMW
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
            很明顯代碼讀寫了已釋放的內存。       
        (4)工具檢測出否:   
                如果在檢測之前做了“前提準備”,則valgrind可以準確地檢測出錯誤。   
        (5)工具所報錯誤:
            error1:invalid read of size 1 at(SlideSorterViewShell.cxx:694)
            error2:invalid write of size 1 at(SlideSorterViewShell.cxx:694)
        (6)工具所報錯誤正確否:
            valgrind報錯完全定確。
        (7)工具設定了哪些特定參數:
            valgrind ./soffice.bin

    (4c)例子
        (1)代碼:           
            #include <iostream>
            class A
            {
                private:
                int i;
                double f;
            public:
                A(int ii, double ff ): i(ii) , f(ff){};
                ~A(){printf(“i am dead/n”);}
                void printfA()
                {
                    std::cout << "i="  << i << "f=" << f << std::endl;
                }
            };
            int main()
            {
                 A* p;   
            if(true)
            {
                 A obj(1, 1.1);
                 p = &obj;
                 if(p) p->printfA();
            }
            if(p) p->printfA();

            return 0;
        }       
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
            指針所指的對象在離開作用域時析構了,可是指針仍指向它,並調用其中           的函數。這會導致程序不穩定。           
        (4)工具檢測出否:
            工具沒能檢測出來,不知爲什麼,對象明明已經析構,也許是指針離對象析構的對象太近了,也許在其它模塊中使用指針引用對象時更容易出現問題。           
        (5)工具所報錯誤:
        (6)工具所報錯誤正確否:
        (7)工具設定了哪些特定參數:
            valgrind ./soffice.bin

   
5。c++環境中錯誤地使用malloc/new 與free/delete的配對
    (5a)例子
        (1)代碼:
            {
                int* pi = new int[5];
                delete pi;
            }
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
            很明顯代碼中應用delete [] 纔對。
        (4)工具檢測出否:
            在openoffice中重現了該病態代碼之後,用valgrind檢測之,沒有檢測出來,
        但是自已編寫一個小程序重現病態代碼,用g++編譯之,則valgrind可以檢測出錯        誤。
        (5)工具所報錯誤:
        (6)工具所報錯誤正確否:
        (7)工具設定了哪些特定參數:valgrind --leak-check=full ./soffice.bin



6。未初始化的指針
    (6a)例子
        (1)代碼:
        void f( int datum )
        {
            int *p2;

            *p2 = datum;//指針p2沒有初始化。
        }
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
            上面的代碼很直觀,所以不用多說,對野指針的寫通常會導致程序崩潰,        對野指針的讀通常會得到無效的數據,導致程序運行不穩定,所以在寫程序        時,務    必始終保持指針有明確有效的指向。
        (4)工具檢測出否:
            可以明確檢測出來。
        (5)工具所報錯誤:
            error1:use of uninitialised value of size 4at(SlideSorterViewShell.cxx:617)
            error2:invalid write of size 4 at(SlideSorterViewShell.cxx:617)
        (6)工具所報錯誤正確否:
            工具檢測錯完全正確
        (7)工具設定了哪些特定參數:
            valgrind --leak-check=full ./soffice.bin

7.空指針讀寫
    (7a)例子
        (1)代碼:   
        typedef struct node
        {
               struct node* next;
                int          val;
        } Node;

        void genNPRandZPR()
        {
                int i = findLastNodeValue(NULL);
        }
        int findLastNodeValue(Node* head)
        {
            while (head->next != NULL)
        {
                    head = head->next;    /* Expect NPR */
                }
            return head->val;     /* Expect ZPR */
        }       
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:   
            代碼示例中的指針是一個類型明確,但指向爲null的指針去讀取指        針類型        中的成員變量,這顯然是不可以的,用指針可以去讀寫具體的內存對        象,而        不是抽象的類型。       
        (4)工具檢測出否:
            可以準確地檢測出。           
        (5)工具所報錯誤:
            invalid read of size 4 at(SlideSorterViewShell.cxx:620)
        (6)工具所報錯誤正確否:
            工具所報錯誤完全正確。
        (7)工具設定了哪些特定參數:
            valgrind --leak-check=full ./soffice.bin

    (7b)例子
        (1)代碼:   
        struct StrtForNPR
        {
            int num01, num02;
        };

        struct StrtForNPR *pForNPR = (struct StrtForNPR*)0;
        pForNPR->num02 = pForNPR->num01;        //NPR
        (2)代碼位置:
        sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx:615後
        void SlideSorterViewShell::Paint( const Rectangle& rBBox, sd::Window*         pWindow )
        {   
                ...
            //add code here .
        }
        (3)代碼分析:
                代碼示例中的指針是一個類型明確,但指向爲null的指針去讀取指針類型        中的成員變量,這顯然是不可以的,用指針可以去讀寫具體的內存對象,而    不是抽        象的類型。       
        (4)工具檢測出否:   
            工具可以準確地檢測出來       
        (5)工具所報錯誤:
            invalid read of size 4 at(SlideSorterViewShell.cxx:642)
        (6)工具所報錯誤正確否:
            完全正確。
        (7)工具設定了哪些特定參數:
            valgrind ./soffice.bin

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章