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測試報告
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.