web-dev-qa-db-fra.com

Valgrind: lecture invalide de taille 4 -> sigsegv, fonctionne très bien sans valgrind et dans visual studio

J'ai implémenté un algorithme de compression (utilisant le codage huffman) qui utilise une file d'attente prioritaire de nœuds (une structure i définie). Maintenant, quand je lance le code sous Linux ou Visual Studio, tout fonctionne bien. Lorsque je vérifie les fuites de mémoire dans Visual Studio, aucune n'est indiquée.

Le problème est maintenant que lorsque j'utilise valgrind pour analyser mon programme, il se termine avec le signal 11 (sigsegv). La première erreur rencontrée est une "lecture invalide de taille 4" dans la méthode delete min. D'autres erreurs après cela sont: L'adresse est de 0 octet dans un bloc de taille 453 libéré, une écriture invalide de taille 4, une libération non valide, une suppression ou une réallocation.

Quelqu'un peut-il me donner des conseils sur le type d'erreur que j'aurais pu commettre? Je recherche sur Internet depuis des heures, mais je ne trouve pas ce que je fais mal (surtout parce que cela ne fonctionne que lorsque vous n'utilisez pas valgrind). Ou des conseils pour déboguer et découvrir la cause de l'erreur de lecture.

Merci beaucoup!

Voici le code au cas où quelqu'un voudrait le revoir, mais je suppose que ce n'est pas si facile de plonger dans ce code spécifique.

Je suppose que cela a quelque chose à voir avec la file d'attente prioritaire du code:

La partie où je fais la partie huffman -> à chaque fois, supprimez les 2 nœuds minimaux et ajoutez la somme des deux en un seul nœud.

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;
}

Voici les méthodes delete_min et insert_node pour la file d'attente prioritaire:

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;
}

EDIT: Ajout de la sortie 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)

La ligne 331 est la ligne dans delete_min de: node * min = queue [0];

ÉDITER:

Le problème est maintenant résolu. Dans la réponse acceptée, la raison est expliquée. L'affectation correcte de la valeur réallouée, dans delete_min a résolu tous les problèmes.

//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

Je vais vous expliquer la première erreur.

==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)

À la ligne 331, vous lisez probablement un entier (non signé), dans une partie de la mémoire que vous n'avez pas allouée à votre propre programme.

==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==

Cette partie donne plus d'informations sur la partie de la mémoire que vous avez essayé de lire. Il indique que vous avez déjà utilisé la mémoire, mais reallox l'a libérée. Cela signifie que vous lisez d'un ancien pointeur vers une partie de la mémoire que vous avez réallouée.

Vous devez vous assurer que vous utilisez les retours de réallocation du pointeur, et non l'ancien.

La raison pour laquelle cela ne plante pas lors de l'exécution en dehors de valgrind est que la plupart du temps, la même partie de la mémoire sera allouée par realloc. Le pointeur reste donc le même, et en tant que tel, votre code fonctionnera. Cependant, parfois, realloc décidera de déplacer la partie de la mémoire, puis votre code se bloquera. Valgrind essaie de vous avertir pour cela.

Le reste des erreurs sera probablement résolu lorsque vous utilisez le pointeur renvoyé.

24
Noctua

Sur la base de vos erreurs Valgrind, vous accédez probablement puis libérez des nœuds que vous avez déjà supprimés. Vous devriez envisager de publier les erreurs Valgrind avec les numéros de ligne correspondants (compiler avec -g dans gcc) pour nous aider plus facilement.

Edit: L'erreur la plus flagrante, le segfault, est l'endroit où vous devez commencer le débogage. Cette ligne échoue:

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

probablement parce que queue est NULL. Pourquoi est-ce NULL? Probablement parce que realloc n'a rien alloué. Pourquoi n'a-t-il rien alloué? Soit parce que vous avez manqué de mémoire (peu probable), soit parce que vous avez essayé d'allouer quelque chose de taille 0. (Voir http://www.cplusplus.com/reference/cstdlib/realloc/ pour plus de détails sur realloc ). Comment pouvez-vous demander la taille 0? Si p_queue->size-1 est 0.

3
1''