2017-10-07 114 views
0

运行程序Valgrind时,它表示在结构的转换指针处存在“大小为8的无效读取”。它与calloc有什么关系?如果按原样读取则为(无)。为什么读取结构指针字段无效?

具有结构(被称为线索),它的用法如下:

#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)); 

这里,当valgrid尝试读取,它说: “尺寸为8的无效读”:

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

从焦炭*翅片相同的消息:

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

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:强烈建议不要隐藏指针类型定义。 – wildplasser

+0

在我做结构的例子之一中,它就像'typedef struct _trie * Trie;'。但是现在我发现这样做不是一个好习惯。 –

回答

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) 

这是说你的代码试图读取无效地址的8字节的值。

该地址位于经由malloccreateTrie中分配的8字节块之后。换句话说,这条线:

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

为什么它认为trie点只有8个字节的内存?因为你分配sizeof (Trie)字节,Trie

typedef struct _trie * Trie; 

或者对换句话说,你的指针分配内存时,你的意思是为整个结构分配足够的内存。

由于这个原因,强烈建议不要在typedefs后面隐藏指针。

建议的修复:

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

Trie *createTrie(int maxNode) { 

    Trie *trie; 

    trie = malloc(sizeof *trie); 

注:

  • 我们使用相同的名称(Trie)两个struct Trie和(裸)Trie因为别的了不必要的混乱。
  • 所有的指针都可视为声明为*
  • 我们不会投出malloc的返回值,因为这可能是另一个潜在的错误来源。
  • 我们使用sizeof *trie来获得trie指向的字节的正确数目,无论如何声明trie
+0

更改为'trie = malloc(sizeof * trie);'仍然为'trie'生成8个字节的大小。这是因为特里是一个指针,对吧? –

+0

@SeanWalsh不,没有。'sizeof * trie'给出了'trie'指向的任何类型的大小。 – melpomene

+0

我明白了,非常感谢。 –