valgrind --trace-children=yes reports leak despite atexit cleanup

心已入冬 提交于 2021-01-27 06:09:26

问题


I'm trying to avoid false positives with valgrind, but I'm suck with a combination of atexit() and fork(), despite using --trace-children=yes. My code:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

static int * arr;

static void cleanup() {
    free(arr);
    printf("free arr as: %p\n", (void *)arr);
}

int main()
{
    arr = malloc(16 * sizeof(int));
    printf("allocated arr as: %p\n", (void *)arr);
    atexit(cleanup);

    pid_t pid = fork();
    if (pid == -1) {
        exit(1);
    } else if (pid == 0) {
        // child
        _exit(0);
    } else {
        // parent
        exit(0);
    }
}

Command-line:

$ clang -Weverything leak.c 
$ valgrind --trace-children=yes ./a.out 
==3287== Memcheck, a memory error detector
==3287== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==3287== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==3287== Command: ./a.out
==3287== 
allocated arr as: 0x5202040
free arr as: 0x5202040
==3288== 
==3288== HEAP SUMMARY:
==3288==     in use at exit: 64 bytes in 1 blocks
==3288==   total heap usage: 2 allocs, 1 frees, 1,088 bytes allocated
==3288== 
==3288== LEAK SUMMARY:
==3288==    definitely lost: 0 bytes in 0 blocks
==3288==    indirectly lost: 0 bytes in 0 blocks
==3288==      possibly lost: 0 bytes in 0 blocks
==3288==    still reachable: 64 bytes in 1 blocks
==3288==         suppressed: 0 bytes in 0 blocks
==3288== Rerun with --leak-check=full to see details of leaked memory
==3288== 
==3288== For counts of detected and suppressed errors, rerun with: -v
==3288== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==3287== 
==3287== HEAP SUMMARY:
==3287==     in use at exit: 0 bytes in 0 blocks
==3287==   total heap usage: 2 allocs, 2 frees, 1,088 bytes allocated
==3287== 
==3287== All heap blocks were freed -- no leaks are possible
==3287== 
==3287== For counts of detected and suppressed errors, rerun with: -v
==3287== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Based on the printf() output, it looks like there's no leaks. Can I convince valgrind of this, or should I just add this to my valgrind suppression file?


回答1:


Based on the printf() output, it looks like there's no leaks. Can I convince valgrind of this, or should I just add this to my valgrind suppression file?

It appears that valgrind is right. If you interpret the printf() output as indicating that there are no leaks, then you're not appreciating the effect of fork().

When you fork a child, it gets a complete copy of its parent's address space. This is typically implemented via copy-on-write pages, but it still constitutes memory belonging to the child. In your case, that includes a copy of dynamically-allocated array arr.

The child exits by calling _exit(), so although it inherits its parent's exit-handler registrations, registered exit handlers are not called in that process. You can tell that is so because you see the output of cleanup() only once. As a result, the copy of arr belonging to the child is never freed, as valgrind tells you.

It's a bit pedantic to call this a memory leak, though. The memory in question is still reachable when the program terminates, at which time it gets reclaimed by the system. It simply is not explicitly freed before termination.




回答2:


You are using _exit() in child process. As per _exit's man page :

The function _exit() is like exit(3), but does not call any functions registered with atexit(3) or on_exit(3). 

Change it to exit(0). It should work.



来源:https://stackoverflow.com/questions/42143707/valgrind-trace-children-yes-reports-leak-despite-atexit-cleanup

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!