病态代码测试--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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值