使用 free() 时大小为 4 的无效读取

invalid read of size 4 when using free()

我是 C 和 valgrind 的新手,正在尝试学习它们。 当我使用以下功能时:

void die(const char *message,struct Connection *conn){
    if (conn){
        free(conn->file);
        free(conn->db);
        free(conn);
    }
    if (errno){
        perror(message);
    }else{
        printf("ERROR:$s\n",message);
    }
    exit(1);
}

打印错误并从结构中释放内存(这是它们的声明):

struct Address{
    int id;
    int set;
    char name[MAX_DATA];
    char email[MAX_DATA];
};

struct Database{
    struct Address rows[MAX_ROWS];
};

struct Connection{
    FILE *file;
    struct Database *db;
};

我从 valgrind 得到了这样的错误:

==15471== 2 errors in context 61 of 62
==15471== Invalid read of size 4
==15471==     at 0x4EA5889: _IO_default_setbuf (genops.c:567)
==15471==     by 0x4EA4928: _IO_file_setbuf@@GLIBC_2.2.5 (fileops.c:454)
==15471==     by 0x4EA6C32: _IO_unbuffer_write (genops.c:979)
==15471==     by 0x4EA6C32: _IO_cleanup (genops.c:1019)
==15471==     by 0x4E67F14: exit (exit.c:100)
==15471==     by 0x40097F: die (ex17.c:33)
==15471==     by 0x400DF4: Database_get (ex17.c:105)
==15471==     by 0x40102F: main (ex17.c:139)
==15471== Addres 0x51d53f0 is 0 bytes inside a block of size 568 free'd
==15471==     at 0x4C2845A: free (vg_replace_malloc.c:473)
==15471==     by 0x40091D: die (ex17.c:25)
==15471==     by 0x400DF4: Database_get (ex17.c:105)
==15471==    by 0x40102F: main (ex17.c:139)

但是在没有 valgrind 的情况下执行时,我没有内存错误。 会不会是把NULL传给free()造成的?这真的是一个错误吗,因为有人说 free(NULL) 什么都不做?

抱歉英语不好。

您没有 free 一个 FILE * 指针,因为您也没有 malloc 它。您将 FILE * 指针传递给 fclose() ,这将为您销毁它(并且释放内存,如果这样的内存确实存在 - 因为它没有定义 FILE * 指针指向内存已由 malloc 分配,只有在这种情况下调用 free 才是合法的。

你也没有说明你是如何分配所有内存的。当您仅使用 malloc() 分配 conn 而未显式分配 conn->db 或将其设置为 NULL 时,其值未定义(malloc returns 基本上是用 "random bytes") 填充的内存,所以在 malloc 之后 conn->db 的值可能是 NULL (如果你幸运的话,因为内存经常被零填充)或者它可能是别的东西。如果你想确保所有分配的内存都归零(因此所有布尔值都是假的,所有整数值都是 0 并且所有指针都是 NULL),你总是需要使用 calloc 进行分配。

如果您不是 libc,我不知道在什么情况下 freeing 一个 FILE 指针是合法的,而您不是。无论您打算 free(conn->file); 表达什么意思,这绝对不是正确的做法。

发生的情况是,您释放了一些不属于您的内存,并且在退出时 libc 会自行清理打开的文件,并且崩溃,因为它触及了您已经毁掉的内存。

如果非要我猜的话,你可能指的是 fclose

第一件事:在我看来这是一个非常经典的问题。也许您或应用程序试图访问之前已释放的内存地址。这可能会导致崩溃。

但对于您的具体情况: 不应释放文件指针。相反,您应该使用适当的 Ansi C 函数关闭文件并再次将指针设置为 NULL。

问题:您的应用程序是多线程的吗?

因为在您释放指针(另一个线程)后,有人可能会尝试访问它。