1

我正在用 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恶作剧,但我不明白为什么。帮助将不胜感激!

4

3 回答 3

2

我注意到代码中有几个奇怪的地方。

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

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

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

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

在第一次迭代中(*fileDataLen) == 0,在增加 之后,您现在*fileDataLen只有分配数组的大小)。因此,下次您在另一个递归调用期间调用时,您将复制into的值,但尚未分配该内存。此外,下次调用时,它可能不再在同一位置重新分配内存,因此将指向完全不同的位置,仅复制第一个数组条目。1fileDatafileData[(*fileDataLen)] = currFile;currFilefileData[1]reallocfileData

第三,您不能调用free(fileData)func1()因为您通过在函数realloc内部调用func2()已经更改了内存指向的值,并且您没有通过fileData引用您的func2()函数来传递原始变量的实际内存地址。换句话说,如果对malloc()in的调用func1()返回了一个值,比如说 0x10000,并且您realloc在代码中的其他位置调用了分配的内存,那么在 0x10000 分配的内存现在已经移动到其他位置,但是fileData在上下文中的值的本地范围func1()仍然是 0x10000。因此,当你有效地打电话时free(0x10000),这就是你打电话时发生的事情free(fileData),你会得到一个错误,因为数组的内存不再分配在 0x10000。为了释放数组,您要么必须从对 的所有递归调用中返回指向指针数组的更新指针func2(),要么通过fileData引用传递,这意味着func2()and的函数签名openFile()将需要更改为fileInfo***类型,并且您' 还需要一个额外的间接层,无论何时访问fileData和. 然后,当您在其他任何地方调用时,您实际上也在修改分配的值,并且可以调用该指针。func2()openFile()reallocfileDatafunc1()free()

最后,请记住,如果您只释放为 分配的内存,那么堆上fileData所有分配的节点都会有很大的内存泄漏,因为只是指向节点的指针数组,而不是实际节点本身。fileInfofileData

于 2011-09-09T14:05:54.863 回答
1

您的问题是您没有为以下内容分配足够的内存fileData

fileInfo * fileData = malloc(sizeof(struct fileInfo ));

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

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

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

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

您应该始终保持此不变性,将数组重新分配为 size fileDataLen + 1

fileData = realloc(fileData, (*fileDataLen + 1) * sizeof(struct fileInfo*));
于 2011-09-09T13:32:59.063 回答
0

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

于 2011-09-09T17:39:09.207 回答