web-dev-qa-db-ja.com

Valgrind:サイズ4の無効な読み取り-> sigsegv、valgrindがなくてもVisual Studioで正常に機能する

ノードの優先キュー(構造体i定義)を使用する圧縮アルゴリズム(ハフマンコーディングを使用)を実装しました。さて、LinuxまたはVisual Studioでコードを実行すると、すべてが正常に動作します。 Visual Studioでメモリリークをチェックすると、何も表示されません。

ここで問題は、valgrindを使用してプログラムを分析すると、シグナル11(sigsegv)で終了することです。最初に発生したエラーは、メソッドminの「サイズ4の無効な読み取り」です。その後のその他のエラーは次のとおりです。アドレスは解放されたサイズ453のブロック内の0バイト、無効なサイズ4の書き込み、無効な解放、削除、または再割り当てです。

誰がどんなエラーを起こした可能性があるかについて誰かにアドバイスをいただけますか?私は何時間もインターネットを検索してきましたが、私が間違っていることを見つけることができません(特に、valgrindを使用しない場合にのみ機能するため)。または、読み取りエラーの原因をデバッグして調べる方法のヒント。

どうもありがとう!

誰かがそれを確認したい場合のためのコードは次のとおりですが、この特定のコードに飛び込むのは簡単ではないと思います。

私はそれがコードの優先キューと関係があると思います:

ハフマン部分を行う部分->毎回2つの最小ノードを削除し、両方の合計を1つのノードとして追加します。

while(queue->size > 1){
    node* n1 = delete_min(queue);
    node* n2 = delete_min(queue); // all the errors are encountered in this call
    node* temp = (node*) calloc(sizeof(node),1);
    temp->amount = n1->amount + n2->amount;
    insert_node(queue,temp);
    n1->parent = temp;
    n2->parent = temp;
    temp->left = n1;
    temp->right = n2;
}

優先度キューのdelete_minメソッドとinsert_nodeメソッドを次に示します。

void insert_node(priority_queue* p_queue, node* x){
    int i = p_queue->size;
    if(i == 0){
        p_queue->queue = (node**) malloc(sizeof(node*));
    }
    else{
        p_queue->queue = (node**) realloc(p_queue->queue,sizeof(node*)*(p_queue->size+1));
    }
    p_queue->queue[p_queue->size] = x;

    while(i>=0 && p_queue->queue[i]->amount < p_queue->queue[(i-1)/2]->amount){
        node* temp = p_queue->queue[i];
        p_queue->queue[i] = p_queue->queue[(i-1)/2];
        p_queue->queue[(i-1)/2] = temp;
        i = (i-1)/2;
    }
    p_queue->size++;
}

node* delete_min(priority_queue* p_queue){
    node** queue = p_queue->queue;
    node* min = queue[0];

    if(p_queue->size>1){
        int r = 0;
        int current = 1; //left child of root

        queue[0] = queue[p_queue->size-1];
        queue = (node**) realloc(queue,sizeof(node*)*(--p_queue->size));
        while(current < p_queue->size){
            //in case of 2 children, check if current needs to be right or left child
            if(current < p_queue->size-1 && queue[current] > queue[current+1]){
                current++;
            } 
            if(queue[current] < queue[r]){
                node* temp = queue[r];
                queue[r] = queue[current];
                queue[current] = temp;

                r = current;
                current = 2 * current;
            }
            else{
                break;
            }
            current++;
        }
    }
    else{
        free(queue);
        p_queue->size--;
    }
    return min;
}

編集:valgrind出力を追加しました:

Invalid read of size 4
==1893==    at 0x80498E0: delete_min (huffman.c:331)
==1893==    by 0x80492DA: huffman_encode (huffman.c:196)
==1893==    by 0x8049DDE: encode_file (main.c:94)
==1893==    by 0x8049BBE: main (main.c:32)
==1893==  Address 0x441d9a8 is 0 bytes inside a block of size 452 free'd
==1893==    at 0x402BC70: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==1893==    by 0x8049922: delete_min (huffman.c:335)
==1893==    by 0x80492CC: huffman_encode (huffman.c:195)
==1893==    by 0x8049DDE: encode_file (main.c:94)
==1893==    by 0x8049BBE: main (main.c:32)
==1893== 
==1893== Invalid read of size 4
==1893==    at 0x8049901: delete_min (huffman.c:333)
==1893==    by 0x80492DA: huffman_encode (huffman.c:196)
==1893==    by 0x8049DDE: encode_file (main.c:94)
==1893==    by 0x8049BBE: main (main.c:32)
==1893==  Address 0x441db64 is 444 bytes inside a block of size 452 free'd
==1893==    at 0x402BC70: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==1893==    by 0x8049922: delete_min (huffman.c:335)
==1893==    by 0x80492CC: huffman_encode (huffman.c:195)
==1893==    by 0x8049DDE: encode_file (main.c:94)
==1893==    by 0x8049BBE: main (main.c:32)
==1893== 
==1893== Invalid write of size 4
==1893==    at 0x8049906: delete_min (huffman.c:333)
==1893==    by 0x80492DA: huffman_encode (huffman.c:196)
==1893==    by 0x8049DDE: encode_file (main.c:94)
==1893==    by 0x8049BBE: main (main.c:32)
==1893==  Address 0x441d9a8 is 0 bytes inside a block of size 452 free'd
==1893==    at 0x402BC70: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==1893==    by 0x8049922: delete_min (huffman.c:335)
==1893==    by 0x80492CC: huffman_encode (huffman.c:195)
==1893==    by 0x8049DDE: encode_file (main.c:94)
==1893==    by 0x8049BBE: main (main.c:32)
==1893== 
==1893== Invalid free() / delete / delete[] / realloc()
==1893==    at 0x402BC70: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==1893==    by 0x8049922: delete_min (huffman.c:335)
==1893==    by 0x80492DA: huffman_encode (huffman.c:196)
==1893==    by 0x8049DDE: encode_file (main.c:94)
==1893==    by 0x8049BBE: main (main.c:32)
==1893==  Address 0x441d9a8 is 0 bytes inside a block of size 452 free'd
==1893==    at 0x402BC70: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==1893==    by 0x8049922: delete_min (huffman.c:335)
==1893==    by 0x80492CC: huffman_encode (huffman.c:195)
==1893==    by 0x8049DDE: encode_file (main.c:94)
==1893==    by 0x8049BBE: main (main.c:32)
==1893== 
==1893== Invalid read of size 4
==1893==    at 0x8049A0E: delete_min (huffman.c:337)
==1893==    by 0x80492DA: huffman_encode (huffman.c:196)
==1893==    by 0x8049DDE: encode_file (main.c:94)
==1893==    by 0x8049BBE: main (main.c:32)
==1893==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==1893== 
==1893== 
==1893== Process terminating with default action of signal 11 (SIGSEGV)
==1893==  Access not within mapped region at address 0x0
==1893==    at 0x8049A0E: delete_min (huffman.c:337)
==1893==    by 0x80492DA: huffman_encode (huffman.c:196)
==1893==    by 0x8049DDE: encode_file (main.c:94)
==1893==    by 0x8049BBE: main (main.c:32)

行331は、delete_minの次の行です:node * min = queue [0];

編集:

これで問題は解決しました。認められた回答には、その理由が説明されています。再割り当てされた値を正しく割り当てるだけで、delete_minですべての問題が解決しました。

//realloc queue and assign new value to local queue var
p_queue->queue = (node**) realloc(queue,sizeof(node*)*(--p_queue->grootte));
queue = p_queue->queue;
17
HaS

最初のエラーについて説明します。

==1893== Invalid read of size 4
==1893==    at 0x80498E0: delete_min (huffman.c:331)
==1893==    by 0x80492DA: huffman_encode (huffman.c:196)
==1893==    by 0x8049DDE: encode_file (main.c:94)
==1893==    by 0x8049BBE: main (main.c:32)

331行目では、自分のプログラムに割り当てていないメモリの一部で、おそらく(符号なし)intを読み取っています。

==1893==  Address 0x441d9a8 is 0 bytes inside a block of size 452 free'd
==1893==    at 0x402BC70: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==1893==    by 0x8049922: delete_min (huffman.c:335)
==1893==    by 0x80492CC: huffman_encode (huffman.c:195)
==1893==    by 0x8049DDE: encode_file (main.c:94)
==1893==    by 0x8049BBE: main (main.c:32)
==1893==

この部分は、読み取ろうとしたメモリの部分に関する詳細情報を提供します。すでにメモリを使用していると表示されていますが、realloxが解放しました。つまり、古いポインタから、再割り当てしたメモリの一部を読み取っているということです。

古いポインターではなく、reallocポインターの戻り値を使用するようにしてください。

これがvalgrindの外で実行しているときにクラッシュしない理由は、ほとんどの場合、メモリの同じ部分がreallocによって割り当てられるためです。したがって、ポインタは同じままであり、コードは機能します。ただし、場合によっては、reallocがメモリの一部を移動することを決定し、コードがクラッシュします。 Valgrindはこれについて警告しようとしています。

残りのエラーは、返されたポインターを使用しているときにおそらく解決されます。

24
Noctua

Valgrindエラーに基づいて、おそらくすでに削除したノードにアクセスしてから解放しています。 Valgrindエラーを対応する行番号(gccで-gを付けてコンパイル)に投稿して、私たちが支援しやすくすることを検討してください。

編集:最も明白なエラーであるsegfaultは、デバッグを開始する場所です。この行は失敗します:

while((2*i)+2 < p_queue->grootte-1 && (queue[i]->amount > queue[(2*i)+1]->amount || queue[i]->amount > queue[(2*i)+2]->amount)){

おそらくqueueがNULLであるためです。なぜそれがNULLなのですか?おそらくreallocは何も割り当てなかったためです。なぜ何も割り当てなかったのですか?メモリが不足しているため(可能性は低い)、またはサイズ0の何かを割り当てようとしたためです(reallocの詳細については http://www.cplusplus.com/reference/cstdlib/realloc/ を参照してください) )。どのようにしてサイズ0を要求できますか? p_queue->size-1は0です。

3
1''