C中奇怪的内存错误

时间:2011-09-09 13:26:23

标签: c memory-leaks realloc

我正在用C编写一个程序来检查循环符号链接。策略是创建一个struct fileInfo:

typedef struct fileInfo fileInfo;

struct fileInfo {
    ino_t inode;
    dev_t devID;
};

将存储文件的inode和devID。我们创建这些结构的数组,并在打开新文件之前每次检查文件是否已存在。如果是这样,那么它就是一个循环链接。

void func1(...)
{

    fileInfo **fileData = malloc(sizeof(struct fileInfo*));
    int fileDataLen = 0;
    char* path = "path of file";
    /* some flags */

    func2(path, fileData, &fileDataLen);

    for (int i = 0; i < fileDataLen; i++)
        free(fileData[i]);
    free(fileData);
}

void func2(char* path, fileInfo ** fileData, int * fileDataLen)
{
    //try to open file
     struct stat buf;
     if (openFile(file, &buf, followSymLinks) == -1)
         exit(1);

     fileData = checkForLoops(fileData, fileDataLen, &buf, file);

     if (S_ISDIR(buf.st_mode)) 
     {
         char* newPath = /* modify path */
         func2(newPath,fileData, fileDataLen);
     }

    /* other stuff */

}

int openFile(char* file, struct stat * buf, fileInfo ** fileData, int * fileDataLen)
{

     if (lstat(path, buf) < 0) 
        {
            fprintf(stderr, "lstat(%s) failed\n", path);
            return -1;
        }
     return 0;
}

fileInfo** checkForLoops(fileInfo **fileData, int * fileDataLen,struct stat *buf, 
                    char* path)
{
    for (int i = 0; i < (*fileDataLen); i++)
    {
        if (fileData[i]->inode == buf->st_ino && 
            fileData[i]->devID == buf->st_dev)
            fprintf(stderr, "circular symbolic link at %s\n", path);
    }


    fileInfo *currFile = malloc(sizeof(struct fileInfo));
    memcpy(&currFile->inode, &buf->st_ino, sizeof(buf->st_ino));
    memcpy(&currFile->devID, &buf->st_dev, sizeof(buf->st_dev));

    fileData[(*fileDataLen)] = currFile;
    (*fileDataLen)++;
    fileData = realloc(fileData, ((*fileDataLen)+1) * sizeof(struct fileInfo*));

    return fileData;
}
但是,我注意到,在对func2()进行了几次调用之后,存在内存泄漏并且fileData指向任何内容。我只是不确定泄漏的来源,因为我没有在func2()中释放任何东西。我假设有一些realloc恶作剧,但我不明白为什么。非常感谢帮助!

3 个答案:

答案 0 :(得分:2)

我注意到代码中有几个奇怪的东西。

首先,openFile的函数签名的返回类型为void,但您在此处检查返回值:

if (openFile(file, &buf, fileData, fileDataLen) < 0)

其次,正如彼得所指出的那样,在调用realloc时你没有分配足够的空间:

fileData = realloc(fileData, (*fileDataLen) * sizeof(struct fileInfo*));

在第一次迭代,(*fileDataLen) == 0,在递增*fileDataLen后,您现在只有1的值,这意味着您没有重新分配任何内容(即,您'简单地传回fileData已经指向的内存,因为它没有改变分配的数组的大小)。因此,下次在另一次递归调用期间调用fileData[(*fileDataLen)] = currFile;时,您将把currFile的值复制到fileData[1],但该内存尚未分配。此外,下一次调用realloc时,它可能不再在同一位置重新分配内存,因此fileData将指向一个完全不同的位置,只复制第一个数组条目。

第三,您无法在free(fileData)中致电func1(),因为您通过调用realloc函数内的func2()更改了内存所指向的值,并且您没有通过引用fileData函数传递原始func2()变量的实际内存地址。换句话说,如果malloc()func1()的调用返回值为0x10000,并且您在代码中的其他位置分配了内存上的realloc,那么分配的内存就是0x10000现在已移动到其他位置,但fileData的本地范围上下文中的func1()值仍为0x10000。因此,当您有效地调用free(0x10000)时,即调用free(fileData)时发生的情况,您将收到错误,因为阵列的内存不再分配在0x10000。为了释放数组,您要么必须从func2()的所有递归调用返回指针数组的更新指针,要么通过引用传递fileData,这意味着{的函数签名{1}}和func2()需要更改为openFile()类型,每当访问fileInfo***中的fileData和{{{}时,您还需要额外的间接层1}}。然后,当您在其他任何地方调用func2()时,您实际上正在修改openFile()的值,因为它在realloc中也已分配,并且可以在该指针上调用fileData。 / p>

最后,请记住,如果只释放为func1()分配的内存,那么堆上的所有已分配free()节点的内存泄漏都会很大,因为{{1} }只是一个指向节点的指针数组,而不是实际的节点本身。

答案 1 :(得分:1)

你的问题是你没有为fileData分配足够的内存:

<击>     fileInfo * fileData = malloc(sizeof(struct fileInfo ));

在这里,您只为 fileInfo单指针分配内存,而不是您似乎正在使用的fileInfo实例数组。

抱歉,我的第一个想法是错误的...但你的问题似乎仍然是你没有为fileData分配足够的内存 - 只是在另一个地方:

fileData[(*fileDataLen)] = currFile; // 1
(*fileDataLen)++;
fileData = realloc(fileData, (*fileDataLen) * sizeof(struct fileInfo*)); // 2

这里你分配一个少于所需的元素。您从fileDataLen为0开始,fileData包含1个元素。打开第一个文件后,将fileDataLen增加到1,然后重新分配数组以包含1个元素而不是2个!因此,当打开第二个文件时,缓冲区在// 1以上被覆盖,并且某些内存被覆盖。

您应始终保持此不变量,将数组重新分配为fileDataLen + 1大小:

fileData = realloc(fileData, (*fileDataLen + 1) * sizeof(struct fileInfo*));

答案 2 :(得分:0)

我不知道你在func2中对路径变量执行了什么样的处理,但是你可能试图修改一个静态字符串,这会导致另一个内存问题,因为这些字符串存储在一个操作系统保留的私有内存区域。