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
病态代码测试--valgrind测试报告
最新推荐文章于 2024-05-03 21:43:42 发布