1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

VALGRIND Memory Leak Detection Tutorial

Discussion in 'C' started by poornaMoksha, Sep 24, 2011.

Tags:
  1. poornaMoksha

    poornaMoksha New Member

    Joined:
    Jan 29, 2011
    Messages:
    150
    Likes Received:
    33
    Trophy Points:
    0
    Occupation:
    Software developer
    Location:
    India
    In a language like 'C', the programmer has almost complete control over memory operations but this brings in a problem that many of you might have faced : Memory errors. Although GDB can be used in many areas of these kind of problems but there are sometimes when programmer doesn't want to put too many breakpoints in the code. Also in a scenario where memory leak occurs, tool like GDB is of little help. So in situation like these a tool VALGRIND is extremely helpful. Lets discuss it today.

    Valgrind works on executable files. Just simply run 'valgrind ./a.out' (of course with arguments needed by your program). Also make sure that you have turned off the optimizations for your program and use flag '-g' while compiling the code in order to see line numbers in output.

    Examples



    Lets understand the capability of Valgrind by focusing on various memory errors.

    1) Lets consider a situation here:

    Here is the code :

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char** argv){
      int k;
      int *p = malloc(sizeof(int) * 10);
      if (!p) return -1; /*malloc failed*/
      for (k = 0; k < 11; k++){
        a[k] = k; //here lies the problem for k = 10
      }
      free(p);
      return 0;
    }
    The problem with this code is that we are allocating memory eqvivalent to 10 integers but accessing 11th element thinking it as a part of allocated memory. Now when the above program is run, my compiler gives this kind of output :
    Code:
    *** glibc detected *** ./test_valgrind: free(): invalid next size (fast): 0x0000000001172010 ***
    ======= Backtrace: =========
    /lib/libc.so.6(+0x775b6)[0x7fe4371cc5b6]
    /lib/libc.so.6(cfree+0x73)[0x7fe4371d2e83]
    ./test_valgrind[0x4005c0]
    /lib/libc.so.6(__libc_start_main+0xfd)[0x7fe437173c4d]
    ./test_valgrind[0x4004a9]
    ======= Memory map: ========
    00400000-00401000 r-xp 00000000 08:05 1448916                            /home/himanshu/practice/test_valgrind
    00600000-00601000 r--p 00000000 08:05 1448916                            /home/himanshu/practice/test_valgrind
    00601000-00602000 rw-p 00001000 08:05 1448916                            /home/himanshu/practice/test_valgrind
    01172000-01193000 rw-p 00000000 00:00 0                                  [heap]
    7fe430000000-7fe430021000 rw-p 00000000 00:00 0
    7fe430021000-7fe434000000 ---p 00000000 00:00 0
    7fe436f3e000-7fe436f54000 r-xp 00000000 08:05 262224                     /lib/libgcc_s.so.1
    7fe436f54000-7fe437153000 ---p 00016000 08:05 262224                     /lib/libgcc_s.so.1
    7fe437153000-7fe437154000 r--p 00015000 08:05 262224                     /lib/libgcc_s.so.1
    7fe437154000-7fe437155000 rw-p 00016000 08:05 262224                     /lib/libgcc_s.so.1
    7fe437155000-7fe4372cf000 r-xp 00000000 08:05 265935                     /lib/libc-2.11.1.so
    7fe4372cf000-7fe4374ce000 ---p 0017a000 08:05 265935                     /lib/libc-2.11.1.so
    7fe4374ce000-7fe4374d2000 r--p 00179000 08:05 265935                     /lib/libc-2.11.1.so
    7fe4374d2000-7fe4374d3000 rw-p 0017d000 08:05 265935                     /lib/libc-2.11.1.so
    7fe4374d3000-7fe4374d8000 rw-p 00000000 00:00 0
    7fe4374d8000-7fe4374f8000 r-xp 00000000 08:05 265932                     /lib/ld-2.11.1.so
    7fe4376d5000-7fe4376d8000 rw-p 00000000 00:00 0
    7fe4376f5000-7fe4376f7000 rw-p 00000000 00:00 0
    7fe4376f7000-7fe4376f8000 r--p 0001f000 08:05 265932                     /lib/ld-2.11.1.so
    7fe4376f8000-7fe4376f9000 rw-p 00020000 08:05 265932                     /lib/ld-2.11.1.so
    7fe4376f9000-7fe4376fa000 rw-p 00000000 00:00 0
    7fff22e72000-7fff22e87000 rw-p 00000000 00:00 0                          [stack]
    7fff22fff000-7fff23000000 r-xp 00000000 00:00 0                          [vdso]
    ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
    Aborted
    
    This is bit difficult to decode especially for a newbie to understand what went wrong and where? Since its a small demo code so it could be easy to find out where the problem is but consider thousands of lines of code giving this type of run time error. In that situation using tool like valgrind is unavoidable.

    Now, lets use valgrind, run the following command :

    $ valgrind ./test_valgrind

    and here is the output :

    ==6034== Memcheck, a memory error detector
    ==6034== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
    ==6034== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
    ==6034== Command: ./test_valgrind
    ==6034==
    ==6034== Invalid write of size 4
    ==6034== at 0x4005A8: main (valgrind.c:9)

    ==6034== Address 0x51b0068 is 0 bytes after a block of size 40 alloc'd
    ==6034== at 0x4C274A8: malloc (vg_replace_malloc.c:236)
    ==6034== by 0x40057C: main (valgrind.c:6)
    ==6034==
    ==6034==
    ==6034== FILE DESCRIPTORS: 3 open at exit.
    ==6034== Open file descriptor 2: /dev/pts/1
    ==6034== <inherited from parent>
    ==6034==
    ==6034== Open file descriptor 1: /dev/pts/1
    ==6034== <inherited from parent>
    ==6034==
    ==6034== Open file descriptor 0: /dev/pts/1
    ==6034== <inherited from parent>
    ==6034==
    ==6034==
    ==6034== HEAP SUMMARY:
    ==6034== in use at exit: 0 bytes in 0 blocks
    ==6034== total heap usage: 1 allocs, 1 frees, 40 bytes allocated
    ==6034==
    ==6034== All heap blocks were freed -- no leaks are possible
    ==6034==
    ==6034== For counts of detected and suppressed errors, rerun with: -v
    ==6034== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
    So as you can see the output, Valgrind tells the error that there was an 'Invalid write of size 4'. Also it tells the line number (see the line in bold above)

    2) Lets consider another situation, here is the code :

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char** argv){
      int k;
      int *p = malloc(sizeof(int) * 10);
      if (!p) return -1; /*malloc failed*/
      for (k = 0; k < 10; k++){ // Read from k=0 to k=9
        p[k] = k;
      }
    
      for (k = 0; k < 11; k++){
          printf("\n p[%d] = [%d] \n",k,p[k]); // Problem is here when we try to read the array at index k = 10
      }
      free(p);
      return 0;
    }
    Here is the output without using valgrind :

    p[0] = [0]

    p[1] = [1]

    p[2] = [2]

    p[3] = [3]

    p[4] = [4]

    p[5] = [5]

    p[6] = [6]

    p[7] = [7]

    p[8] = [8]

    p[9] = [9]

    p[10] = [135121]

    but when we run the above code with valgrind we get the following output :

    ==6084== Memcheck, a memory error detector
    ==6084== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
    ==6084== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
    ==6084== Command: ./test_valgrind
    ==6084==

    p[0] = [0]

    p[1] = [1]

    p[2] = [2]

    p[3] = [3]

    p[4] = [4]

    p[5] = [5]

    p[6] = [6]

    p[7] = [7]

    p[8] = [8]

    p[9] = [9]
    ==6084== Invalid read of size 4
    ==6084== at 0x40061A: main (valgrind.c:13)

    ==6084== Address 0x51b0068 is 0 bytes after a block of size 40 alloc'd
    ==6084== at 0x4C274A8: malloc (vg_replace_malloc.c:236)
    ==6084== by 0x4005CC: main (valgrind.c:6)
    ==6084==

    p[10] = [0]
    ==6084==
    ==6084== HEAP SUMMARY:
    ==6084== in use at exit: 0 bytes in 0 blocks
    ==6084== total heap usage: 1 allocs, 1 frees, 40 bytes allocated
    ==6084==
    ==6084== All heap blocks were freed -- no leaks are possible
    ==6084==
    ==6084== For counts of detected and suppressed errors, rerun with: -v
    ==6084== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
    So here we can see that valgrind easily tells that after reading the array at index '9' there is an invalid read of 4 bytes. It also tells the line number (see the line in bold above)

    3) Lets try one more scenario, here is the code :

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char** argv){
      int k;
      int *p = malloc(sizeof(int) * 10);
      int *ptr = malloc(5); // Problem is here as this memory is not freed anywhere.
      if (!p) return -1; /*malloc failed*/
      for (k = 0; k < 10; k++){
        p[k] = k;
      }
    
      for (k = 0; k < 10; k++){
          printf("\n p[%d] = [%d] \n",k,p[k]);
      }
      free(p);
      return 0;
    }
    Now In above program a memory of 5 characters is allocated but is not free'd any where in the program.

    When we run the program normally, programmer gets no clue that a memory was leaked. But when we run the above program with valgrind (use --leak-check=full flag this time), we get the following output :

    ==6167== Memcheck, a memory error detector
    ==6167== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
    ==6167== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
    ==6167== Command: ./test_valgrind
    ==6167==

    p[0] = [0]

    p[1] = [1]

    p[2] = [2]

    p[3] = [3]

    p[4] = [4]

    p[5] = [5]

    p[6] = [6]

    p[7] = [7]

    p[8] = [8]

    p[9] = [9]
    ==6167==
    ==6167== HEAP SUMMARY:
    ==6167== in use at exit: 5 bytes in 1 blocks
    ==6167== total heap usage: 2 allocs, 1 frees, 45 bytes allocated
    ==6167==
    ==6167== 5 bytes in 1 blocks are definitely lost in loss record 1 of 1
    ==6167== at 0x4C274A8: malloc (vg_replace_malloc.c:236)
    ==6167== by 0x4005DA: main (valgrind.c:7)

    ==6167==
    ==6167== LEAK SUMMARY:
    ==6167== definitely lost: 5 bytes in 1 blocks
    ==6167== indirectly lost: 0 bytes in 0 blocks
    ==6167== possibly lost: 0 bytes in 0 blocks
    ==6167== still reachable: 0 bytes in 0 blocks
    ==6167== suppressed: 0 bytes in 0 blocks
    ==6167==
    ==6167== For counts of detected and suppressed errors, rerun with: -v
    ==6167== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
    Here also, one can easily figure out that 5 bytes were not freed(see bold line in the output above) in the program and hence there was a memory leak.

    Conclusion



    I think the above three example help to present a strong conclusion that how useful is this tool for detecting run time memory related issues which otherwise are very difficult to find.
     
  2. StarDrago

    StarDrago New Member

    Joined:
    Nov 12, 2011
    Messages:
    49
    Likes Received:
    2
    Trophy Points:
    0
    I use deleaker - it's much more convenient for me....
     
  3. Scripting

    Scripting John Hoder

    Joined:
    Jun 29, 2010
    Messages:
    421
    Likes Received:
    57
    Trophy Points:
    0
    Occupation:
    School for life
    Location:
    /root
    valgrind is useful tool, good tutorial too!
     
  4. StarDrago

    StarDrago New Member

    Joined:
    Nov 12, 2011
    Messages:
    49
    Likes Received:
    2
    Trophy Points:
    0
    dn't dispute with me:cuss: :crazy: . I'm nice! :D
     
  5. Scripting

    Scripting John Hoder

    Joined:
    Jun 29, 2010
    Messages:
    421
    Likes Received:
    57
    Trophy Points:
    0
    Occupation:
    School for life
    Location:
    /root
    Yea, dealeaker is good too :wacky: Cheerz! :D
     
  6. StarDrago

    StarDrago New Member

    Joined:
    Nov 12, 2011
    Messages:
    49
    Likes Received:
    2
    Trophy Points:
    0
    It's true :pleased:
     
  7. StarDrago

    StarDrago New Member

    Joined:
    Nov 12, 2011
    Messages:
    49
    Likes Received:
    2
    Trophy Points:
    0
    Does anybody among me use it tool? :pleased:
     
  8. MasterAvalons

    MasterAvalons New Member

    Joined:
    May 14, 2012
    Messages:
    18
    Likes Received:
    2
    Trophy Points:
    0
    Yes, of course. :pleased:
     

Share This Page