3

I'm trying to figure out why Valgrind does not emit any warning even if, in the following piece of code, there is no free after the malloc:

#include "stdlib.h"
#include "string.h"

char* ptr;

int main (int argc, char *argv[]) {
    ptr = static_cast<char*>(malloc(5 * sizeof(char)));
    strcpy(ptr, "test");
}

Is there some kind of "automatic free" I'm not aware of or am I missing something else?

Thanks.

gscaparrotti
  • 663
  • 5
  • 21
  • 4
    Just guessing, but if you alloc memory and store it in a global, it is never a leak unless you replace pointer with something else, otherwise you can always access it. Whether valgrind can detect the latter case is another matter. –  Feb 10 '20 at 16:44
  • This may be the case. I assumed that arriving at the end of the `main` would have been a good reason to mark that memory as lost, even though at that point the execution is over. – gscaparrotti Feb 10 '20 at 16:47
  • Valgrind will certainly know about this memory and report it as `still reachable`. Your program doesn't have a memory leak because it has not lost the last reference to the allocated memory. After `main` exits, the program hasn't quite terminated yet. In C, there are `atexit` handlers to call and cleanup in the library, and `C++` has global destructors. – Kaz Feb 10 '20 at 17:09

2 Answers2

4

It does report the issue, but to see it you need to run Valgrind with --leak-check=full --show-leak-kinds=all options:

$ valgrind --leak-check=full --show-leak-kinds=all ./a.out
==317235== Memcheck, a memory error detector
==317235== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==317235== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==317235== Command: ./a.out
==317235== 
==317235== 
==317235== HEAP SUMMARY:
==317235==     in use at exit: 5 bytes in 1 blocks
==317235==   total heap usage: 2 allocs, 1 frees, 72,709 bytes allocated
==317235== 
==317235== 5 bytes in 1 blocks are still reachable in loss record 1 of 1
==317235==    at 0x483980B: malloc (vg_replace_malloc.c:309)
==317235==    by 0x40113E: main (1.cpp:7)
==317235== 
==317235== LEAK SUMMARY:
==317235==    definitely lost: 0 bytes in 0 blocks
==317235==    indirectly lost: 0 bytes in 0 blocks
==317235==      possibly lost: 0 bytes in 0 blocks
==317235==    still reachable: 5 bytes in 1 blocks
==317235==         suppressed: 0 bytes in 0 blocks
==317235== 
==317235== For lists of detected and suppressed errors, rerun with: -s
==317235== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Even if you run Valgrind without any options you can see the issue in HEAP SUMMARY section:

==317235==     in use at exit: 5 bytes in 1 blocks

but without any more details.

ks1322
  • 33,961
  • 14
  • 109
  • 164
  • Thank you, it worked for me as well. At first I tried only with `--leak-check=full`, but it clearly wasn't enough. – gscaparrotti Feb 10 '20 at 16:51
  • I also noticed another warning: `==2937==72,704 bytes in 1 blocks are still reachable in loss record 1 of 1 ==2937==at 0x483577F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) [...some traces...] ==2937==by 0x40010C9: ??? (in /lib/x86_64-linux-gnu/ld-2.28.so)` I'm assuming this isn't my fault, is it? – gscaparrotti Feb 10 '20 at 17:03
  • 1
    Yes, this is probably GCC fault, see https://stackoverflow.com/q/31775034/72178. – ks1322 Feb 10 '20 at 17:08
2

A memory leak means the loss of a pointer value to allocated memory. Once the value has been lost, it is no longer possible to release the memory.

The lifetime of a static pointer is the the entire execution of the process. Thus the pointer value was never lost, because it was always stored, and at no point of the program is there a situation where the pointer couldn't be freed.

Valgrind documentation classifies such memory as:

"Still reachable". This covers cases 1 and 2 (for the BBB blocks) above. A start-pointer or chain of start-pointers to the block is found. Since the block is still pointed at, the programmer could, at least in principle, have freed it before program exit. "Still reachable" blocks are very common and arguably not a problem. So, by default, Memcheck won't report such blocks individually.


Is there some kind of "automatic free"

Not in the sense of a call to free, but once a program stops, it no longer exists and its allocations are of no concern.

eerorika
  • 232,697
  • 12
  • 197
  • 326