c – Still Reachable Leak detected by Valgrind

c – Still Reachable Leak detected by Valgrind

There is more than one way to define memory leak. In particular, there are two primary definitions of memory leak that are in common usage among programmers.

The first commonly used definition of memory leak is, Memory was allocated and was not subsequently freed before the program terminated. However, many programmers (rightly) argue that certain types of memory leaks that fit this definition dont actually pose any sort of problem, and therefore should not be considered true memory leaks.

An arguably stricter (and more useful) definition of memory leak is, Memory was allocated and cannot be subsequently freed because the program no longer has any pointers to the allocated memory block. In other words, you cannot free memory that you no longer have any pointers to. Such memory is therefore a memory leak. Valgrind uses this stricter definition of the term memory leak. This is the type of leak which can potentially cause significant heap depletion, especially for long lived processes.

The still reachable category within Valgrinds leak report refers to allocations that fit only the first definition of memory leak. These blocks were not freed, but they could have been freed (if the programmer had wanted to) because the program still was keeping track of pointers to those memory blocks.

In general, there is no need to worry about still reachable blocks. They dont pose the sort of problem that true memory leaks can cause. For instance, there is normally no potential for heap exhaustion from still reachable blocks. This is because these blocks are usually one-time allocations, references to which are kept throughout the duration of the processs lifetime. While you could go through and ensure that your program frees all allocated memory, there is usually no practical benefit from doing so since the operating system will reclaim all of the processs memory after the process terminates, anyway. Contrast this with true memory leaks which, if left unfixed, could cause a process to run out of memory if left running long enough, or will simply cause a process to consume far more memory than is necessary.

Probably the only time it is useful to ensure that all allocations have matching frees is if your leak detection tools cannot tell which blocks are still reachable (but Valgrind can do this) or if your operating system doesnt reclaim all of a terminating processs memory (all platforms which Valgrind has been ported to do this).

Since there is some routine from the the pthread family on the bottom (but I dont know that particular one), my guess would be that you have launched some thread as joinable that has terminated execution.

The exit state information of that thread is kept available until you call pthread_join. Thus, the memory is kept in a loss record at program termination, but it is still reachable since you could use pthread_join to access it.

If this analysis is correct, either launch these threads detached, or join them before terminating your program.

Edit: I ran your sample program (after some obvious corrections) and I dont have errors but the following

==18933== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
--18933-- 
--18933-- used_suppression:      2 dl-hack3-cond-1
--18933-- used_suppression:      2 glibc-2.5.x-on-SUSE-10.2-(PPC)-2a

Since the dl- thing resembles much of what you see I guess that you see a known problem that has a solution in terms of a suppression file for valgrind. Perhaps your system is not up to date, or your distribution doesnt maintain these things. (Mine is ubuntu 10.4, 64bit)

c – Still Reachable Leak detected by Valgrind

Here is a proper explanation of still reachable:

Still reachable are leaks assigned to global and static-local variables. Because valgrind tracks global and static variables it can exclude memory allocations that are assigned once-and-forget. A global variable assigned an allocation once and never reassigned that allocation is typically not a leak in the sense that it does not grow indefinitely. It is still a leak in the strict sense, but can usually be ignored unless you are pedantic.

Local variables that are assigned allocations and not freed are almost always leaks.

Here is an example

int foo(void)
{
    static char *working_buf = NULL;
    char *temp_buf;
    if (!working_buf) {
         working_buf = (char *) malloc(16 * 1024);
    }
    temp_buf = (char *) malloc(5 * 1024);

    ....
    ....
    ....

}

Valgrind will report working_buf as still reachable – 16k and temp_buf as definitely lost – 5k.

Leave a Reply

Your email address will not be published.