我正在用C编写一个程序,检查循环符号链接。策略是创建结构文件信息:

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()中没有释放任何内容。我想有一些恶作剧,但我不明白为什么。非常感谢您的帮助!

最佳答案

我注意到代码中有几个奇怪的地方。
首先,openFile的函数签名的返回类型为void,但您可以在此处检查返回值:

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

其次,正如Peter也指出的那样,在调用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()的调用返回一个值,比如0x10000,并且您在代码中的某个已分配内存上调用了func1(),则在0x10000分配的内存现在已移动到其他位置,但在realloc的本地作用域上下文中fileData的值仍然是0x10000。因此,当您有效地调用func1()时(这是您调用free(0x10000)时发生的情况),您将得到一个错误,因为数组的内存不再分配为0x10000。为了释放数组,您要么必须从所有对free(fileData)的递归调用中返回指向指针数组的更新指针,要么通过引用传递func2(),这意味着fileDatafunc2()的函数签名将需要更改为openFile()类型,并且在访问fileInfo***fileData中的func2()时还需要额外的间接层。然后,当您在任何其他地方调用openFile()时,您实际上也在修改realloc的值,因为它也是在fileData中分配的,并且可以在该指针上调用func1()
最后,请记住,如果只释放为free()分配的内存,那么堆上所有已分配的fileData节点都会有很大的内存泄漏,因为fileInfo只是指向节点的指针数组,而不是指向实际节点本身。

关于c - C中奇怪的内存错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7362323/

10-10 21:17