0

Valgrindが無効な書き込みを誤って報告することに問題がある人はいますか?私はこのループを持つCプログラムを持っています:

void myfunc4(int *myData, ...) 
{
 int *variable1, *variable2, ii, ss, bb, jj;
 ...
 bb = 0;
 for (ii=0; ii<ss; ii++) {  
   for (jj=0; jj<(variable2[ii]-variable1[ii]+1); jj++) {
       myData[bb] = variable1[ii] + jj; /* valgrind reports error is on this line */
       bb = bb+1;
   }
   printf("ss = %d, ii = %d, bb = %d \n", ss, ii, bb);
 }
}

私はValgrindを使用して実行します。

valgrind --log-file=./logfile --leak-check=full ./myProgram

そして、それがリストする最初で唯一の「無効な」エラーは次のとおりです。

==6135== Invalid write of size 4
==6135==    at 0x4090AA: myfunc4 (myfunc4.c:170)
==6135==    by 0x408527: myfunc3 (myfunc3.c:168)
==6135==    by 0x406CA1: myfunc2 (myfunc2.c:84)
==6135==    by 0x410163: myfunc1 (myfunc1.c:133)
==6135==    by 0x413726: main (myProgram.c:511)
==6135==  Address 0x1077c250 is 209,712 bytes inside a block of size 209,715 alloc'd
==6135==    at 0x4A05FDE: malloc (vg_replace_malloc.c:236)
==6135==    by 0x408248: myfunc3 (myfunc3.c:119)
==6135==    by 0x406CA1: myfunc2 (myfunc2.c:84)
==6135==    by 0x410163: myfunc1 (myfunc1.c:133)
==6135==    by 0x413726: main (myProgram.c:511)
==6135== 
==6135== More than 10000000 total errors detected.  I'm not reporting any more.
==6135== Final error counts will be inaccurate.  Go fix your program!

Valgrindは、エラーがコード行で発生すると述べています。

myData[bb] = variable1[ii] + jj;

その時点でgdbを使用してプログラムをステップ実行すると、正常に実行されます。ループが完了する前に表示される最後のprintfは次のとおりです。

ss = 687, ii = 686, bb = 2690

Valgrind以外では何の問題も見られないようです。Valgrindは一貫してこのエラーを出しますが、gdbは一貫して問題を示しません。

割り当てられたメモリmyDataは、Valgrindが正しく報告しているように、209712バイトであり、これは209712/4 = 52428整数用のスペースです(Linux 64ビットマシンを使用しています)。ステートメントから、printf必要に応じてbb=2690でforループが終了することがわかります。したがって、配列に使用される最大のインデックスmyData[bb](Valgrindが文句を言う場所)はmyData[2689]です。

誰かが私が次に見ることができる場所に光を当てることができますか?私はこれを一日中見つめてきました。私はValgrindをあまり使用していません。これを嘘つきとは言いたくないのですが、ここで何か間違ったことをしているのでしょうか。どんなアドバイスも大歓迎です。

更新1

myfunc4()内部への呼び出しmyfunc3()は次のとおりです。

int *myData, lengthA; 
...
myData = malloc( sizeof(int) * lengthA / 10); 
myfunc4(myData);

更新2

ステートメントを含めるようにループを変更するとif (bb>10000)、gdbはtrueをテストしませんが、Valgrindはテストします。コンパイルされたプログラムは同じです。誰かが何が起こっているのか洞察を持っていますか?

void myfunc4(int *myData, ...) 
{
 int *variable1, *variable2, ii, ss, bb, jj;
 ...
 bb = 0;
 for (ii=0; ii<ss; ii++) {  
   for (jj=0; jj<(variable2[ii]-variable1[ii]+1); jj++) {
       myData[bb] = variable1[ii] + jj; 
       bb = bb+1;
       if (bb>10000) {
          printf("bb=%d \n", bb); /* valgrind executes this line but gdb does not */
          exit(1);
       }
   }
   printf("ss = %d, ii = %d, bb = %d \n", ss, ii, bb);
 }
}
4

2 に答える 2

2

やっとバグがわかった。もちろん、malloc はゼロに初期化されず、ifいくつかの配列値を設定するステートメント (上記には示されていません) がありましたがelse、他のパスをキャッチして同じ配列値を設定するステートメントはありませんでした。 path が初期化された値を使用していたため、動作が悪くなりました。

このデバッグ作業では、gdb は Valgrind と比較して、(malloc を介して) 配列をゼロに初期化するのに優れた仕事をしました。それに頼るべきではありませんが、少なくともここでは gdb と Valgrind で得られた結果の違いのようです。

于 2012-11-29T10:02:08.627 に答える
0

データに割り当てられた実際のバイト数を取得し、それを関数に渡します。

size_t szData = sizeof(int) * lengthA / 10; 
myData = malloc(szData);
myfunc4(myData, szData);

アクセスを確認してvalgrindを確認します。

/* .... */
assert((bb +1) * sizeof(int) < szData);
myData[bb] = variable1[ii] + jj;
于 2012-11-29T06:20:26.360 に答える