c - 打开和关闭日志文件会导致 C 中的内存泄漏

标签 c valgrind glib gstring

调试遗留代码。我有一个用 C 编写的程序。它实际上要长得多,但我创建了一个小的可重现程序来显示问题(请忽略这个程序没有多大意义的事实)。程序:

#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <malloc.h>
#include <ctype.h>
#include <glib.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>


#define FILE_SEP "/"
#define LENGTH 10

FILE *log_file;
char TMP[LENGTH];
char RESULT_DIRECTORY[LENGTH + 12];

int open_log() {
    GString *path = g_string_new(RESULT_DIRECTORY);
    g_string_append(path, FILE_SEP);
    g_string_append(path, TMP);
    g_string_append(path,".usr");
    log_file = fopen(path->str,"w");
    if (!log_file)
        return 1;
    
    return 0;
}

void close_log() {
    fclose(log_file);
}


int main(int argc, char *argv[]) {
    strcpy(TMP, "tmp");
    strcpy(RESULT_DIRECTORY, "/home/");
    if (open_log()) {
        return 1;
    }
    close_log();
    return 0;
}

运行 valgrind 我得到:

> valgrind --tool=memcheck --track-origins=yes --leak-check=full --show-reachable=yes program
==84011== Memcheck, a memory error detector
==84011== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==84011== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==84011== Command: c_status_reader
==84011== 
==84011== 
==84011== HEAP SUMMARY:
==84011==     in use at exit: 5,292 bytes in 9 blocks
==84011==   total heap usage: 10 allocs, 1 frees, 5,860 bytes allocated
==84011== 
==84011== 16 bytes in 1 blocks are possibly lost in loss record 1 of 7
==84011==    at 0x4C29104: malloc (vg_replace_malloc.c:299)
==84011==    by 0x4C29278: realloc (vg_replace_malloc.c:785)
==84011==    by 0x5078ABD: g_realloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x5092B13: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x5093C99: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x108BE0: open_log (program.c:21)
==84011==    by 0x108A6E: main (program.c:40)
==84011== 
==84011== 252 bytes in 1 blocks are still reachable in loss record 2 of 7
==84011==    at 0x4C27393: calloc (vg_replace_malloc.c:711)
==84011==    by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x508CCE2: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x508EB5C: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x108BE0: open_log (program.c:21)
==84011==    by 0x108A6E: main (program.c:40)
==84011== 
==84011== 496 bytes in 1 blocks are possibly lost in loss record 3 of 7
==84011==    at 0x4C2710E: memalign (vg_replace_malloc.c:858)
==84011==    by 0x4C271A9: posix_memalign (vg_replace_malloc.c:1021)
==84011==    by 0x508D4B0: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x508ECE2: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x108BE0: open_log (program.c:21)
==84011==    by 0x108A6E: main (program.c:40)
==84011== 
==84011== 504 bytes in 1 blocks are still reachable in loss record 4 of 7
==84011==    at 0x4C27393: calloc (vg_replace_malloc.c:711)
==84011==    by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x508CCC3: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x508EB5C: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x108BE0: open_log (program.c:21)
==84011==    by 0x108A6E: main (program.c:40)
==84011== 
==84011== 504 bytes in 1 blocks are still reachable in loss record 5 of 7
==84011==    at 0x4C27393: calloc (vg_replace_malloc.c:711)
==84011==    by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x508CD2A: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x508EB5C: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x108BE0: open_log (program.c:21)
==84011==    by 0x108A6E: main (program.c:40)
==84011== 
==84011== 1,488 bytes in 3 blocks are possibly lost in loss record 6 of 7
==84011==    at 0x4C2710E: memalign (vg_replace_malloc.c:858)
==84011==    by 0x4C271A9: posix_memalign (vg_replace_malloc.c:1021)
==84011==    by 0x508D4B0: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x508ED22: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x108BE0: open_log (program.c:21)
==84011==    by 0x108A6E: main (program.c:40)
==84011== 
==84011== 2,032 bytes in 1 blocks are still reachable in loss record 7 of 7
==84011==    at 0x4C27393: calloc (vg_replace_malloc.c:711)
==84011==    by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x508EB12: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011==    by 0x108BE0: open_log (program.c:21)
==84011==    by 0x108A6E: main (program.c:40)
==84011== 
==84011== LEAK SUMMARY:
==84011==    definitely lost: 0 bytes in 0 blocks
==84011==    indirectly lost: 0 bytes in 0 blocks
==84011==      possibly lost: 2,000 bytes in 5 blocks
==84011==    still reachable: 3,292 bytes in 4 blocks
==84011==         suppressed: 0 bytes in 0 blocks
==84011== 
==84011== For counts of detected and suppressed errors, rerun with: -v
==84011== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 6 from 5)

我认为我理解这个问题 - 它在某处缺少 g_string_free 调用。但是,当我实际使用它时,它说:仍然可达:8 个 block 中的 5,276 字节。例如,我只有以下 open_log (并且没有调用 close_log):

int open_log() {
    GString *path = g_string_new(RESULT_DIRECTORY);
    g_string_append(path, FILE_SEP);
    g_string_free(path,TRUE);
    //log_file = fopen(path->str,"w");
    //if (!log_file)
    //    return 1;
    return 0;
}

我得到:

==88254==
==88254== LEAK SUMMARY:
==88254==    definitely lost: 0 bytes in 0 blocks
==88254==    indirectly lost: 0 bytes in 0 blocks
==88254==      possibly lost: 0 bytes in 0 blocks
==88254==    still reachable: 5,276 bytes in 8 blocks
==88254==         suppressed: 0 bytes in 0 blocks

但是,如果我删除 g_string_append(path, FILE_SEP); 那么它实际上可以工作!所以我猜测,当我执行 g_string_free 时,它只会删除初始字符串 path 而不是附加部分。这是对的吗?我该如何解决这些问题?

编辑:

实际上,我尝试的第一个想法是在 fopen 之后添加 g_string_free(path, TRUE);,但我仍然看到内存泄漏。代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#include<string.h>
#include<malloc.h>
#include<ctype.h>
#include<glib.h>
#include<stdlib.h>


#define FILE_SEP "/"
#define LENGTH 10

FILE *log_file;
char TMP[LENGTH];
char RESULT_DIRECTORY[LENGTH + 12];

int open_log(void) {
    GString *path = g_string_new(RESULT_DIRECTORY);
    g_string_append(path, FILE_SEP);
    g_string_append(path, TMP);
    g_string_append(path, ".usr");
    log_file = fopen(path->str, "w");
    g_string_free(path, TRUE);
    
    if (!log_file)
        return 1;
    
    return 0;
}

void close_log() {
    if (log_file) {
        fclose(log_file);
        log_file = NULL;
    }
}


int main(int argc, char *argv[]) {
    strcpy(TMP, "tmp");
    strcpy(RESULT_DIRECTORY, "/home/");
    if (open_log()) {
        return 1;
    }
    close_log();
    return 0;
}

valgrind 输出:

==23525== Memcheck, a memory error detector
==23525== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==23525== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==23525== Command: c_status_reader
==23525== 
==23525== 
==23525== HEAP SUMMARY:
==23525==     in use at exit: 5,276 bytes in 8 blocks
==23525==   total heap usage: 10 allocs, 2 frees, 5,860 bytes allocated
==23525== 
==23525== 252 bytes in 1 blocks are still reachable in loss record 1 of 6
==23525==    at 0x4C27393: calloc (vg_replace_malloc.c:711)
==23525==    by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x508CCE2: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x508EB5C: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x108C31: open_log (program.c:21)
==23525==    by 0x108ABC: main (program.c:45)
==23525== 
==23525== 496 bytes in 1 blocks are still reachable in loss record 2 of 6
==23525==    at 0x4C2710E: memalign (vg_replace_malloc.c:858)
==23525==    by 0x4C271A9: posix_memalign (vg_replace_malloc.c:1021)
==23525==    by 0x508D4B0: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x508ECE2: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x108C31: open_log (program.c:21)
==23525==    by 0x108ABC: main (program.c:45)
==23525== 
==23525== 504 bytes in 1 blocks are still reachable in loss record 3 of 6
==23525==    at 0x4C27393: calloc (vg_replace_malloc.c:711)
==23525==    by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x508CCC3: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x508EB5C: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x108C31: open_log (program.c:21)
==23525==    by 0x108ABC: main (program.c:45)
==23525== 
==23525== 504 bytes in 1 blocks are still reachable in loss record 4 of 6
==23525==    at 0x4C27393: calloc (vg_replace_malloc.c:711)
==23525==    by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x508CD2A: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x508EB5C: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x108C31: open_log (program.c:21)
==23525==    by 0x108ABC: main (program.c:45)
==23525== 
==23525== 1,488 bytes in 3 blocks are still reachable in loss record 5 of 6
==23525==    at 0x4C2710E: memalign (vg_replace_malloc.c:858)
==23525==    by 0x4C271A9: posix_memalign (vg_replace_malloc.c:1021)
==23525==    by 0x508D4B0: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x508ED22: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x108C31: open_log (program.c:21)
==23525==    by 0x108ABC: main (program.c:45)
==23525== 
==23525== 2,032 bytes in 1 blocks are still reachable in loss record 6 of 6
==23525==    at 0x4C27393: calloc (vg_replace_malloc.c:711)
==23525==    by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x508EB12: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525==    by 0x108C31: open_log (program.c:21)
==23525==    by 0x108ABC: main (program.c:45)
==23525== 
==23525== LEAK SUMMARY:
==23525==    definitely lost: 0 bytes in 0 blocks
==23525==    indirectly lost: 0 bytes in 0 blocks
==23525==      possibly lost: 0 bytes in 0 blocks
==23525==    still reachable: 5,276 bytes in 8 blocks
==23525==         suppressed: 0 bytes in 0 blocks
==23525== 
==23525== For counts of detected and suppressed errors, rerun with: -v
==23525== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 5)

为什么没有解决?我什至尝试将 path 设置为全局变量,并在 close_log 函数中调用 g_string_free 。但没有成功。

最佳答案

您的第一个假设是正确的,您既没有在 open_log 中也没有在 close_log 中调用 g_string_free,因此会出现内存泄漏。

至于

But, when I actually use it, it says: still reachable: 5,276 bytes in 8 blocks.. For example I have only the following open_log (and without calling close_log):

引文中的最后一句话就是答案。您没有调用 close_log,因此 FILE *log_file 现在泄漏。

if I remove g_string_append(path, FILE_SEP); then it actually works!

如果删除 g_string_append,则 log_file = fopen(path->str,"w"); 无法打开文件,因为它是目录,fopen 返回 NULL 并且没有任何泄漏。

如果在所有修复后仍然出现内存泄漏,那么您会看到 valgrind 关于 glib 内部内容的误报。 glib 开发人员非常友善,他们提供了特殊文件来抑制 valgrinds 中的此类误报:

/usr/share/glib-2.0/valgrind/glib.supp

此路径可能会有所不同,查找glib.supp,使用命令locate valgrind/glib.supp。将文件与 valgrind 一起使用:

valgrind --suppressions=/usr/share/glib-2.0/valgrind/glib.supp <...>

关于c - 打开和关闭日志文件会导致 C 中的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71550326/

相关文章:

c - strcmp 对 2 个相同字符串的行为不当

c++ - 在 C/C++ 中声明这些类型的表的简洁方法?

c - 在 c 中使用 glib 中的 glist 时释放内存会在调用函数时出现内存读/写错误

c - 使用 g_ptr_array 时出现错误 : g_ptr_array_add: assertion 'rarray' failed on c,

c - 如何在杂乱纹理上放置杂乱 Actor ?

c - 如何编写一个内核模块来查找内核中的路由表和arp缓存?

c - 二进制 "|"的无效操作数

c++ - 为什么 QApplication 会出现内存泄漏?

c - 在 valgrind 下运行时,setrlimit 失败并显示不允许操作

c++ - 全局重载运算符 new/new[] delete/delete[] C++