from:http://www.thegeekstuff.com/2011/11/valgrind-memcheck/


One major aspect of system programming is to handle memory related issues effectively. The more you work close to the system, the more memory related issues you need to face.

Sometimes these issues are very trivial while many times it becomes a nightmare to debug memory related issues. So, as a practice many tools are used for debugging memory related issues.

In this article, we will discuss the most popular open source memory management framework VALGRIND.

From Valgrind.org :

Valgrind is an instrumentation framework for building dynamic analysis tools. It comes with a set of tools each of which performs some kind of debugging, profiling, or similar task that helps you improve your programs. Valgrind’s architecture is modular, so new tools can be created easily and without disturbing the existing structure.

A number of useful tools are supplied as standard.

  1. Memcheck is a memory error detector. It helps you make your programs, particularly those written in C and C++, more correct.
  2. Cachegrind is a cache and branch-prediction profiler. It helps you make your programs run faster.
  3. Callgrind is a call-graph generating cache profiler. It has some overlap with Cachegrind, but also gathers some information that Cachegrind does not.
  4. Helgrind is a thread error detector. It helps you make your multi-threaded programs more correct.
  5. DRD is also a thread error detector. It is similar to Helgrind but uses different analysis techniques and so may find different problems.
  6. Massif is a heap profiler. It helps you make your programs use less memory.
  7. DHAT is a different kind of heap profiler. It helps you understand issues of block lifetimes, block utilisation, and layout inefficiencies.
  8. SGcheck is an experimental tool that can detect overruns of stack and global arrays. Its functionality is complementary to that of Memcheck: SGcheck finds problems that Memcheck can’t, and vice versa..
  9. BBV is an experimental SimPoint basic block vector generator. It is useful to people doing computer architecture research and development.

There are also a couple of minor tools that aren’t useful to most users: Lackey is an example tool that illustrates some instrumentation basics; and Nulgrind is the minimal Valgrind tool that does no analysis or instrumentation, and is only useful for testing purposes.

Here in this article we will focus on the tool ‘memcheck’.

Using Valgrind Memcheck

The memcheck tool is used as follows :

valgrind --tool=memcheck ./a.out

As clear from the command above, the main binary is ‘Valgrind’ and the tool which we want to use is specified by the option ‘–tool’. The ‘a.out’ above signifies the executable over which we want to run memcheck.

This tool can detect the following memory related problems :

  • Use of uninitialized memory
  • Reading/writing memory after it has been freed
  • Reading/writing off the end of malloc’d blocks
  • Memory leaks
  • Mismatched use of malloc/new/new[] vs free/delete/delete[]
  • Doubly freed memory

Note : The above list is not exhaustive but contains the popular problems detected by this tool.

Lets discuss the above scenarios one by one:

Note : All the test code described below should be compiled using gcc with -g option(to generate line numbers in memcheck output) enabled. As we discussed earlier for a C program to get compiled into an executable, it has to go through 4 different stages.

1. Use of uninitialized memory

Code :

#include <stdio.h> #include <stdlib.h>   int main(void) {     char *p;       char c = *p;       printf("\n [%c]\n",c);       return 0; }

In the above code, we try to use an uninitialized pointer ‘p’.

Lets run memcheck and see the result.

$ valgrind --tool=memcheck ./val ==2862== Memcheck, a memory error detector ==2862== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al. ==2862== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info ==2862== Command: ./val ==2862== ==2862== Use of uninitialised value of size 8 ==2862==    at 0x400530: main (valgrind.c:8) ==2862==  [#] ==2862== ==2862== HEAP SUMMARY: ==2862==     in use at exit: 0 bytes in 0 blocks ==2862==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated ==2862== ==2862== All heap blocks were freed -- no leaks are possible ==2862== ==2862== For counts of detected and suppressed errors, rerun with: -v ==2862== Use --track-origins=yes to see where uninitialized values come from ==2862== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)

As seen from the output above, Valgrind detects the uninitialized variable and gives a warning(see the lines in bold above).

2. Reading/writing memory after it has been freed

Code :

#include <stdio.h> #include <stdlib.h>   int main(void) {     char *p = malloc(1);     *p = 'a';       char c = *p;       printf("\n [%c]\n",c);       free(p);     c = *p;     return 0; }

In the above piece of code, we have freed a pointer ‘p’ and then again we have tried to access the value help by the pointer.

Lets run memcheck and see what Valgrind has to offer for this scenario.

$ valgrind --tool=memcheck ./val ==2849== Memcheck, a memory error detector ==2849== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al. ==2849== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info ==2849== Command: ./val ==2849==    [a] ==2849== Invalid read of size 1 ==2849==    at 0x400603: main (valgrind.c:30) ==2849==  Address 0x51b0040 is 0 bytes inside a block of size 1 free'd ==2849==    at 0x4C270BD: free (vg_replace_malloc.c:366) ==2849==    by 0x4005FE: main (valgrind.c:29) ==2849== ==2849== ==2849== HEAP SUMMARY: ==2849==     in use at exit: 0 bytes in 0 blocks ==2849==   total heap usage: 1 allocs, 1 frees, 1 bytes allocated ==2849== ==2849== All heap blocks were freed -- no leaks are possible ==2849== ==2849== For counts of detected and suppressed errors, rerun with: -v ==2849== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)

As seen in the output above, the tool detects the invalid read and prints the warning ‘Invalid read of size 1′.

On a side note, to debug a c program use gdb.

3. Reading/writing off the end of malloc’d blocks

Code :

#include <stdio.h> #include <stdlib.h>   int main(void) {     char *p = malloc(1);     *p = 'a';       char c = *(p+1);       printf("\n [%c]\n",c);       free(p);     return 0; }

In the above piece of code, we have allocated 1 byte for ‘p’ but we access the the address p+1 while reading the value into ‘c’.

Now we run Valgrind on this piece of code :

$ valgrind --tool=memcheck ./val ==2835== Memcheck, a memory error detector ==2835== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al. ==2835== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info ==2835== Command: ./val ==2835== ==2835== Invalid read of size 1 ==2835==    at 0x4005D9: main (valgrind.c:25) ==2835==  Address 0x51b0041 is 0 bytes after a block of size 1 alloc'd ==2835==    at 0x4C274A8: malloc (vg_replace_malloc.c:236) ==2835==    by 0x4005C5: main (valgrind.c:22) ==2835==    [] ==2835== ==2835== HEAP SUMMARY: ==2835==     in use at exit: 0 bytes in 0 blocks ==2835==   total heap usage: 1 allocs, 1 frees, 1 bytes allocated ==2835== ==2835== All heap blocks were freed -- no leaks are possible ==2835== ==2835== For counts of detected and suppressed errors, rerun with: -v ==2835== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)

Again, this tool detects the invalid read done in this case.

4. Memory leaks

Code:

#include <stdio.h> #include <stdlib.h>   int main(void) {     char *p = malloc(1);     *p = 'a';       char c = *p;       printf("\n [%c]\n",c);       return 0; }

In this code, we have malloced one byte but haven’t freed it. Now lets run Valgrind and see what happens :

$ valgrind --tool=memcheck --leak-check=full ./val ==2888== Memcheck, a memory error detector ==2888== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al. ==2888== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info ==2888== Command: ./val ==2888==    [a] ==2888== ==2888== HEAP SUMMARY: ==2888==     in use at exit: 1 bytes in 1 blocks ==2888==   total heap usage: 1 allocs, 0 frees, 1 bytes allocated ==2888== ==2888== 1 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==2888==    at 0x4C274A8: malloc (vg_replace_malloc.c:236) ==2888==    by 0x400575: main (valgrind.c:6) ==2888== ==2888== LEAK SUMMARY: ==2888==    definitely lost: 1 bytes in 1 blocks ==2888==    indirectly lost: 0 bytes in 0 blocks ==2888==      possibly lost: 0 bytes in 0 blocks ==2888==    still reachable: 0 bytes in 0 blocks ==2888==         suppressed: 0 bytes in 0 blocks ==2888== ==2888== For counts of detected and suppressed errors, rerun with: -v ==2888== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)

The lines (in bold above) shows that this tool was able to detect the leaked memory.

Note: In this case we added an extra option ‘–leak-check=full’ to get verbose details of the memory leak.

5. Mismatched use of malloc/new/new[] vs free/delete/delete[]

Code:

#include <stdio.h> #include <stdlib.h> #include<iostream>   int main(void) {     char *p = (char*)malloc(1);     *p = 'a';       char c = *p;       printf("\n [%c]\n",c);     delete p;     return 0; }

In the above code, we have used malloc() to allocate memory but used delete operator to delete the memory.

Note : Use g++ to compile the above code as delete operator was introduced in C++ and to compile c++ code, g++ tool is used.

Lets run this tool and see :

$ valgrind --tool=memcheck --leak-check=full ./val ==2972== Memcheck, a memory error detector ==2972== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al. ==2972== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info ==2972== Command: ./val ==2972==    [a] ==2972== Mismatched free() / delete / delete [] ==2972==    at 0x4C26DCF: operator delete(void*) (vg_replace_malloc.c:387) ==2972==    by 0x40080B: main (valgrind.c:13) ==2972==  Address 0x595e040 is 0 bytes inside a block of size 1 alloc'd ==2972==    at 0x4C274A8: malloc (vg_replace_malloc.c:236) ==2972==    by 0x4007D5: main (valgrind.c:7) ==2972== ==2972== ==2972== HEAP SUMMARY: ==2972==     in use at exit: 0 bytes in 0 blocks ==2972==   total heap usage: 1 allocs, 1 frees, 1 bytes allocated ==2972== ==2972== All heap blocks were freed -- no leaks are possible ==2972== ==2972== For counts of detected and suppressed errors, rerun with: -v ==2972== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)

We see from the output above (see lines in bold), the tool clearly states ‘Mismatched free() / delete / delete []‘

You can try and use the combination ‘new’ and ‘free’ in a test code and see what result this tool gives.

6. Doubly freed memory

Code :

#include <stdio.h> #include <stdlib.h>   int main(void) {     char *p = (char*)malloc(1);     *p = 'a';       char c = *p;     printf("\n [%c]\n",c);     free(p);     free(p);     return 0; }

In the above peice of code, we have freed the memory pointed by ‘p’ twice. Now, lets run the tool memcheck :

$ valgrind --tool=memcheck --leak-check=full ./val ==3167== Memcheck, a memory error detector ==3167== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al. ==3167== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info ==3167== Command: ./val ==3167==    [a] ==3167== Invalid free() / delete / delete[] ==3167==    at 0x4C270BD: free (vg_replace_malloc.c:366) ==3167==    by 0x40060A: main (valgrind.c:12) ==3167==  Address 0x51b0040 is 0 bytes inside a block of size 1 free'd ==3167==    at 0x4C270BD: free (vg_replace_malloc.c:366) ==3167==    by 0x4005FE: main (valgrind.c:11) ==3167== ==3167== ==3167== HEAP SUMMARY: ==3167==     in use at exit: 0 bytes in 0 blocks ==3167==   total heap usage: 1 allocs, 2 frees, 1 bytes allocated ==3167== ==3167== All heap blocks were freed -- no leaks are possible ==3167== ==3167== For counts of detected and suppressed errors, rerun with: -v ==3167== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)

As seen from the output above(lines in bold), the tool detects that we have called free twice on the same pointer.

In this article, we concentrated on memory management framework Valgrind and used the tool memcheck (provided by this framework) to describe how it makes life easy for a developer working close to memory. This tool can detect many memory related problems that are very hard to find manually.