【问题标题】:Why does Facebook's Infer tool warn about a resource leak in this code?为什么 Facebook 的 Infer 工具会警告此代码中的资源泄漏?
【发布时间】:2020-11-27 21:33:25
【问题描述】:

在以下代码上运行时,Facebook 的 Infer 工具会给出以下输出:

Analysis finished in 397mss

Found 1 issue

test.c:18: error: RESOURCE_LEAK
  resource of type `_IO_FILE` acquired by call to `fopen()` at line 13, column 13 is not released after line 18, column 2.
  16.           return 1;
  17.       }
  18. >     fp = check_file_size_and_reopen(fp);
  19.   
  20.       fclose(fp);


Summary of the reports

  RESOURCE_LEAK: 1

代码如下:

#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

#define FILE_MAX_SIZE   256000
#define FILE_NAME       "dump.log"
#define LAST_FILE_NAME  "dump.log2"

FILE* check_file_size_and_reopen(FILE* fp);

int main(void) {

    FILE *fp = fopen(FILE_NAME, "a+");

    if (!fp) {
        return 1;
    }
    fp = check_file_size_and_reopen(fp);

    fclose(fp);

    return 0;
}

FILE* check_file_size_and_reopen(FILE* fp) {
    struct stat info;

    fstat(fileno(fp), &info);

    if (info.st_size > FILE_MAX_SIZE) {
        fclose(fp);
        rename(FILE_NAME, LAST_FILE_NAME);
        fp = fopen(FILE_NAME,"a+");
    }

    return fp;  
}

如果文件指针作为FILE** fp 传入并被修改,则会给出相同的警告,但如果对check_file_size_and_reopen() 的调用被替换为相同的内联代码,则不会。

这是因为 Infer 无法确定 fp 在传递给另一个函数时调用 fclose() 之前没有被修改,还是这里实际上存在潜在的资源泄漏?

更新

有趣的是,似乎是对fstat() 的调用让我们感到不安。以下没有警告:

FILE* check_file_size_and_reopen(FILE* fp) {
    struct stat info;
    int fd = fileno(fp);
    (void)fd;

    info.st_size = 0;

    if (info.st_size <= FILE_MAX_SIZE) {
        return fp;  
    }

    fclose(fp);
    rename(FILE_NAME, LAST_FILE_NAME);

    return fopen(FILE_NAME,"a+");
}

但是,这与以前的警告相同:

FILE* check_file_size_and_reopen(FILE* fp) {
    struct stat info;
    int fd = fileno(fp);

    fstat(fd, &info);

    if (info.st_size <= FILE_MAX_SIZE) {
        return fp;  
    }

    fclose(fp);
    rename(FILE_NAME, LAST_FILE_NAME);

    return fopen(FILE_NAME,"a+");
}

【问题讨论】:

  • 对我来说似乎是误报
  • 实际错误不是资源泄漏而是相反,如果第二个fopen失败,则将无效指针传递给fclose

标签: c memory-leaks resource-leak


【解决方案1】:

它可能对重新分配 fp 感到愤怒,所以你可以避开它:

FILE* check_file_size_and_reopen(FILE* fp) {
    struct stat info;

    fstat(fileno(fp), &info);

    if (info.st_size <= FILE_MAX_SIZE) {
      return fp;
    }

    fclose(fp);
    rename(FILE_NAME, LAST_FILE_NAME);
    return fopen(FILE_NAME,"a+");
}

【讨论】:

  • 这并没有改变推断的输出。好像是对fstat()的调用不喜欢
  • 印象中是fileno()消耗句柄吗?
  • 如果我继续拨打fileno()但省略fstat(),它不会发出警告
  • 调用stat(FILE_NAME, &amp;info)?
  • 警告仍然存在,即使调用类似于stat("~/.ackrc", &amp;info) 或其他一些完全不相关的文件
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-21
  • 1970-01-01
  • 2012-12-07
  • 2015-07-14
  • 2016-07-24
  • 2011-04-01
  • 1970-01-01
相关资源
最近更新 更多