2017-10-07 25 views
0

Exécution du programme en Valgrind, il est dit qu'il existe une "lecture non valide de taille 8" au pointeur de transition de la structure. Cela a quelque chose à voir avec le calloc? C'est (nul) s'il est lu tel quel.Pourquoi la lecture d'un champ de pointeur struct est-elle invalide?

Ayant un struct (appelé Trie), il est utilisé comme suit:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <limits.h> 

const int MAX_SIZE = 20; 

struct _trie { 
    int maxNode; 
    int nextNode; 
    int** transition; 
    char* fin; 
}; 

typedef struct _trie * Trie; 

Trie createTrie (int maxNode){ 

    Trie trie; 

    trie = (Trie) malloc(sizeof(Trie)); 

    printf("size of trie: %lu, size of the struct: %lu, size of _trie: %lu\n",sizeof(trie),sizeof(Trie), sizeof(struct _trie)); 

    trie->maxNode = maxNode; 

    printf("maxNode = %d, size of maxNode: %lu\n",trie->maxNode,sizeof(trie->maxNode)); 
    printf("size of nextNode : %lu, size of transition: %lu, size of fin: %lu\n", 
      sizeof(trie->nextNode),sizeof(trie->transition),sizeof(trie->fin)); 

Ici, quand valgrid essaie de lire, il est dit "lecture incorrecte de la taille 8":

//invalid read 
    printf("transitions points to: %p, address: %p\n",trie->transition,&trie->transition); 

même message de la fin char *:

//invalid read 
    printf("fin points to: %p, address: %p\n",trie->fin,&trie->fin); 

    getchar(); 

    trie->transition = (int**)calloc(maxNode,sizeof(int*)); 

    printf("trie->transition done.\n"); 
    printf("transitions points to: %p, address: %p\n",trie->transition,&trie->transition); 

    if(trie->transition == NULL){ 
     printf("null for trie->transition\n"); 
     exit(0); 
    } 

    printf("Size of transition: %lu, size of int:%lu, pointer: %p\n\n",sizeof(trie->transition),sizeof(int),trie->transition); 

    for(int counter = 0; counter < maxNode; ++counter){ 

     trie->transition[counter] = calloc(UCHAR_MAX,sizeof(int)); 

     if(trie->transition[counter] == NULL){ 
      printf("null for trie->transition[%d]\n",counter); 
      exit(0); 
     } 

     //printf("size of transition[%d]: %lu\n",counter,sizeof(trie->transition[counter])); 

    } 


    printf("\nFilling up trie->transition\n"); 


    for(int counter = 0; counter < maxNode; ++counter){ 


     for(int counter2 = 0; counter2 < UCHAR_MAX; ++counter2){ 

      trie->transition[counter][counter2] = -1; 

      //printf("size of transition[%d][%d]: %lu, value: %d\n",counter,counter2,sizeof(trie->transition[counter]),trie->transition[counter][counter2]); 

     } 

     //getchar(); 
    } 

    return (trie); 
} 

void free_all(Trie trie){ 

    for(int counter = 0; counter < trie->maxNode; ++counter){ 

     free(trie->transition[counter]); 

    } 

    free(trie->transition); 
    free(trie); 
} 

int main(int argc, char *argv[]){ 

    Trie trie = createTrie(MAX_SIZE); 

    free_all(trie); 
    return (0); 
} 

sortie Valgrind:

==3079== Memcheck, a memory error detector 
==3079== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. 
==3079== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info 
==3079== Command: ./debug_test 
==3079== 
size of trie: 8, size of the struct: 8, size of _trie: 24 
maxNode = 20, size of maxNode: 4 
size of nextNode : 4, size of transition: 8, size of fin: 8 
==3079== Invalid read of size 8 
==3079== at 0x1088AD: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd 
==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==3079== by 0x108835: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== 
transitions points to: (nil), address: 0x5201048 
==3079== Invalid read of size 8 
==3079== at 0x1088D1: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== Address 0x5201050 is 8 bytes after a block of size 8 alloc'd 
==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==3079== by 0x108835: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== 
fin points to: (nil), address: 0x5201050 

==3079== Invalid write of size 8 
==3079== at 0x108907: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd 
==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==3079== by 0x108835: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== 
trie->transition done. 
==3079== Invalid read of size 8 
==3079== at 0x108923: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd 
==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==3079== by 0x108835: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== 
transitions points to: 0x5201910, address: 0x5201048 
==3079== Invalid read of size 8 
==3079== at 0x10893F: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd 
==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==3079== by 0x108835: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== 
==3079== Invalid read of size 8 
==3079== at 0x108962: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd 
==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==3079== by 0x108835: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== 
Size of transition: 8, size of int:4, pointer: 0x5201910 

==3079== Invalid read of size 8 
==3079== at 0x108991: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd 
==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==3079== by 0x108835: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== 
==3079== Invalid read of size 8 
==3079== at 0x1089B9: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd 
==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==3079== by 0x108835: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== 

Filling up trie->transition 
==3079== Invalid read of size 8 
==3079== at 0x108A20: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd 
==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==3079== by 0x108835: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== 
==3079== Invalid read of size 8 
==3079== at 0x108A84: free_all (in /projects/trie/debug_test) 
==3079== by 0x108AF8: main (in /projects/trie/debug_test) 
==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd 
==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==3079== by 0x108835: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== 
==3079== Invalid read of size 8 
==3079== at 0x108AB3: free_all (in /projects/trie/debug_test) 
==3079== by 0x108AF8: main (in /projects/trie/debug_test) 
==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd 
==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==3079== by 0x108835: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== 
==3079== 
==3079== HEAP SUMMARY: 
==3079==  in use at exit: 0 bytes in 0 blocks 
==3079== total heap usage: 24 allocs, 24 frees, 22,616 bytes allocated 
==3079== 
==3079== All heap blocks were freed -- no leaks are possible 
==3079== 
==3079== For counts of detected and suppressed errors, rerun with: -v 
==3079== ERROR SUMMARY: 5167 errors from 11 contexts (suppressed: 0 from 0) 
+4

'= Trie (Trie) malloc (sizeof (Trie));' -> '= Trie (Trie) malloc (sizeof (* Trie));' – BLUEPIXY

+2

Plus: un solide conseil de ne pas cacher derrière des pointeurs typedefs. – wildplasser

+0

Dans l'un des exemples que j'ai eu pour faire des structures, c'était comme 'typedef struct _trie * Trie; Mais maintenant je vois que ce n'est pas une bonne pratique de le faire. –

Répondre

0
==3079== Invalid read of size 8 
==3079== at 0x1088AD: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 
==3079== Address 0x5201048 is 0 bytes after a block of size 8 alloc'd 
==3079== at 0x4C2DB2F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==3079== by 0x108835: createTrie (in /projects/trie/debug_test) 
==3079== by 0x108AE8: main (in /projects/trie/debug_test) 

Ce code dit tente de lire une valeur de 8 octets à partir d'une adresse non valide.

Cette adresse est juste après un bloc de 8 octets alloué via malloc dans createTrie. En d'autres termes, cette ligne:

trie = (Trie) malloc(sizeof(Trie)); 

Pourquoi faut-il penser trie points seulement 8 octets de mémoire? Parce que vous avez alloué sizeof (Trie) octets, et Trie est

typedef struct _trie * Trie; 

Ou sur d'autres mots, vous avez alloué la mémoire pour un pointeur lorsque vous vouliez dire allouer suffisamment de mémoire pour une struct entière.

Il est fortement recommandé de ne pas masquer les pointeurs derrière typedefs, exactement pour cette raison.

Correction proposée:

typedef struct Trie Trie; 
struct Trie { 
    int maxNode; 
    int nextNode; 
    int** transition; 
    char* fin; 
}; 

Trie *createTrie(int maxNode) { 

    Trie *trie; 

    trie = malloc(sizeof *trie); 

Notes:

  • Nous utilisons pour les struct Trie et (nu) Trie du même nom (Trie) parce que tout le reste est une confusion inutile.
  • Tous les pointeurs sont visiblement déclarés comme des pointeurs, avec *.
  • La valeur de retour de malloc n'est pas utilisée, car il s'agit d'une autre source potentielle d'erreurs.
  • Nous utilisons sizeof *trie pour obtenir le bon nombre d'octets dans le type trie pointe vers, peu importe comment trie est déclaré.
+0

Passer à 'trie = malloc (sizeof * trie);' produit toujours 8 octets de taille pour 'trie'. C'est parce que Trie est un pointeur, non? –

+0

@SeanWalsh Non, et non.'sizeof * trie' vous donne la taille de tout type de' trie'. – melpomene

+0

Je vois, merci beaucoup. –