Memcheck: a memory error detector - Valgrind

Valgrind is a memory mismanagement detector. It shows you memory leaks, deallocation errors, etc. Actually, Valgrind is a wrapper around a collection of tools that do many other things (e.g., cache profiling); however, here we focus on the default tool, memcheck.

Memcheck can detect:

  • Use of uninitialised memory
  • Reading/writing memory after it has been free'd
  • Reading/writing off the end of malloc'd blocks
  • Reading/writing inappropriate areas on the stack
  • Memory leaks -- where pointers to malloc'd blocks are lost forever
  • Mismatched use of malloc/new/new [] vs free/delete/delete []
  • Overlapping src and dst pointers in memcpy() and related functions
  • Some misuses of the POSIX pthreads API
Example :
//test.c
#include <stdio.h>

int main()
{
  char *p;

  // Allocation #1 of 19 bytes
  p = (char *) malloc(19);

  // Allocation #2 of 12 bytes
  p = (char *) malloc(12);
  free(p);

  // Allocation #3 of 16 bytes
  p = (char *) malloc(16);

  return 0;
}

To use this on our example program, test.c, try
gcc -o test -g test.c

This creates an executable named test. To check for memory leaks during the execution of test, try
valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./test

This outputs a report to the terminal like


[root@cisco valgrind]# valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./test
==5516== Memcheck, a memory error detector.
==5516== Copyright (C) 2002-2005, and GNU GPL'd, by Julian Seward et al.
==5516== Using LibVEX rev 1575, a library for dynamic binary translation.
==5516== Copyright (C) 2004-2005, and GNU GPL'd, by OpenWorks LLP.
==5516== Using valgrind-3.1.1, a dynamic binary instrumentation framework.
==5516== Copyright (C) 2000-2005, and GNU GPL'd, by Julian Seward et al.
==5516== For more details, rerun with: -v
==5516==
==5516==
==5516== FILE DESCRIPTORS: 3 open at exit.
==5516== Open file descriptor 2: /dev/pts/4
==5516==    <inherited from parent>
==5516==
==5516== Open file descriptor 1: /dev/pts/4
==5516==    <inherited from parent>
==5516==
==5516== Open file descriptor 0: /dev/pts/4
==5516==    <inherited from parent>
==5516==
==5516==
==5516== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 13 from 1)
==5516== malloc/free: in use at exit: 35 bytes in 2 blocks.
==5516== malloc/free: 3 allocs, 1 frees, 47 bytes allocated.
==5516== For counts of detected errors, rerun with: -v
==5516== searching for pointers to 2 not-freed blocks.
==5516== checked 47,332 bytes.
==5516==
==5516== 16 bytes in 1 blocks are definitely lost in loss record 1 of 2
==5516==    at 0x4004405: malloc (vg_replace_malloc.c:149)
==5516==    by 0x80483EF: main (test.c:15)
==5516==
==5516==
==5516== 19 bytes in 1 blocks are definitely lost in loss record 2 of 2
==5516==    at 0x4004405: malloc (vg_replace_malloc.c:149)
==5516==    by 0x80483C1: main (test.c:8)
==5516==
==5516== LEAK SUMMARY:
==5516==    definitely lost: 35 bytes in 2 blocks.
==5516==      possibly lost: 0 bytes in 0 blocks.
==5516==    still reachable: 0 bytes in 0 blocks.
==5516==         suppressed: 0 bytes in 0 blocks.


Let's look at the code to see what happened. Allocation #1 (19 byte leak) is lost because p is pointed elsewhere before the memory from Allocation #1 is freed. To help us track it down, Valgrind gives us a stack trace showing where the bytes were allocated. In the 19 byte leak entry, the bytes were allocate in test.c, line 8. Allocation #2 (12 byte leak) doesn't show up in the list because it is freed. Allocation #3 shows up in the list even though there is still a reference to it (p) at program termination. This is still a memory leak! Again, Valgrind tells us where to look for the allocation (test.c line 15).
 

At Summary its showing lost 35 bytes in 2 blocks:
Allocation #1(19) + Allocation #3(16) =35 bytes
 

No comments:

Post a Comment