c - C中奇怪的内存错误

标签 c memory-leaks realloc

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

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

最佳答案

我注意到代码中有一些奇怪之处。

首先,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 将指向一个完全不同的位置,只有复制过来的第一个数组条目。

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

最后,请记住,如果您只释放为 fileData 分配的内存,那么对于堆,因为 fileData 只是指向节点的指针数组,而不是实际节点本身。

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

相关文章:

c - 防止相关函数中的内存泄漏

c++ - 在 C++/windows 中检测内存泄漏

c++ - 使用 malloc 和 realloc 的最佳方式

c++ - 将指针传递给结构在两个程序中的行为不同

c - 开始使用支持 UNICODE 的 WINAPI 编程

c - 收割丧尸? [C]

arrays - 是否可以使用 SIMD 对 C 中的非平凡循环进行矢量化? (复用一个输入的多长度 5 double 点积)

objective-c - 如何正确释放 UITabController

c - socket C 的动态内存分配

c、从头开始shrink分配的空间