fopen是否可能返回stdout?是否需要调用fclose关闭它?
gcc静态分析器文件泄漏警告的疑问
我写了一段实现输出文件选项的C代码,简化后的最小示例如下:
#define _XOPEN_SOURCE #include <stdio.h> #include <string.h> static void output(const char *output_path) { FILE *output_file = stdout; if (output_path == NULL || *output_path == '\0' || strcmp(output_path, "-") == 0) { output_path = "stdout"; } else { output_file = fopen(output_path, "w"); if (output_file == NULL) return; } fprintf(stderr, "Output path: %s\n", output_path); fputs("Hello there\n", output_file); if (output_file != stdout) fclose(output_file); } int main(int argc, char *argv[]) { /* ... */ output(argc > 1 ? argv[1] : NULL); /* ... */ puts("Done"); return 0; }
这段代码的逻辑是:只有当传入非-的路径时才打开并关闭文件,否则直接使用stdout且不关闭(后续还要用它做其他输出)。即便之后不再使用stdout,我也遵循POSIX的建议不关闭它:
由于调用fclose()后对流的任何使用都会导致未定义行为,因此不应在stdin、stdout或stderr上调用fclose(),除非是在进程终止前立即调用(参见XBD进程终止),以避免在依赖这些流的其他标准接口中触发未定义行为。
但最近用gcc静态分析器检查时,它给出了文件泄漏的警告:
$ gcc --version gcc (Debian 13.3.0-1) 13.3.0 Copyright (C) 2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ gcc -fanalyzer main.c main.c: In function ‘output’: main.c:20:12: warning: leak of FILE ‘output_file’ [CWE-775] [-Wanalyzer-file-leak] 20 | if (output_file != stdout) | ^ ‘output’: events 1-7 | | 8 | if (output_path == NULL || *output_path == '\0' || strcmp(output_path, "-") == 0) { | | ^ | | | | | (1) following ‘false’ branch... |...... | 12 | output_file = fopen(output_path, "w"); | | ~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (2) ...to here | | (3) opened here | 13 | if (output_file == NULL) | | ~ | | | | | (4) assuming ‘output_file’ is non-NULL | | (5) following ‘false’ branch (when ‘output_file’ is non-NULL)... |...... | 17 | fprintf(stderr, "Output path: %s\n", output_path); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (6) ...to here |...... | 20 | if (output_file != stdout) | | ~ | | | | | (7) following ‘false’ branch... | ‘output’: event 8 | |cc1: | (8): ...to here | ‘output’: event 9 | | 20 | if (output_file != stdout) | | ^ | | | | | (9) ‘output_file’ leaks here; was opened at (3) | main.c:20:12: warning: leak of ‘output_file’ [CWE-401] [-Wanalyzer-malloc-leak] ‘output’: events 1-7 | | 8 | if (output_path == NULL || *output_path == '\0' || strcmp(output_path, "-") == 0) { | | ^ | | | | | (1) following ‘false’ branch... |...... | 12 | output_file = fopen(output_path, "w"); | | ~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (2) ...to here | | (3) allocated here | 13 | if (output_file == NULL) | | ~ | | | | | (4) assuming ‘output_file’ is non-NULL | | (5) following ‘false’ branch (when ‘output_file’ is non-NULL)... |...... | 17 | fprintf(stderr, "Output path: %s\n", output_path); | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (6) ...to here |...... | 20 | if (output_file != stdout) | | ~ | | | | | (7) following ‘false’ branch... | ‘output’: event 8 | |cc1: | (8): ...to here | ‘output’: event 9 | | 20 | if (output_file != stdout) | | ^ | | | | | (9) ‘output_file’ leaks here; was allocated at (3) |
我认为分析器应该能理解fopen/fclose的行为,但它的警告似乎暗示fopen可能返回stdout,这种情况下需要调用fclose关闭它。事实真的是这样吗?还是我误解了分析器的输出?
内容的提问来源于stack exchange,提问作者Josh Brobst
相关产品推荐
相关产品推荐

