How to detect memory leak in c program using valgrind?

What is memory leak?

Please refer to my previous post for a discussion on What is memory in C a program?

Installing valgrind on ubuntu linux

Please follow the below simple command to install valgrind, the memory leak checker in linux:


~$ sudo apt-get install valgrind

This should install valgrind on your ubuntu linux without any pain.

Checking memory leak with valgrind

Linked List is a linked list implementation in C and we will use it as an example source code to be run with valgrind. This program Linked List has an inherent problem of memory leak which we will try to figure out using valgrind.

Compiling the program

We use the below gcc commands and options to compile the program:


gcc -m32 -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wdeclaration-after-statement -O2 linked_list.c -o linked_list

The reason for extra gcc flag used here is to make the code more robust in simple terms. Now after the compilation we have the below binary file in the directory where we did the compilation:


$ ls -la linked_list
-rwxrwxr-x 1 vbhadra vbhadra 7379 Jan 30 14:59 linked_list

Run the binary with valgrind


$ valgrind --leak-check=full ./linked_list
==5186== Memcheck, a memory error detector
==5186== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==5186== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==5186== Command: ./linked_list
==5186==
5
10
20
30
40
50
=============
5
10
20
40
50
=============
5
10
20
25
40
50
=============
2
5
10
20
25
40
50
==5186==
==5186== HEAP SUMMARY:
==5186== in use at exit: 56 bytes in 7 blocks
==5186== total heap usage: 8 allocs, 1 frees, 64 bytes allocated
==5186==
==5186== 56 (8 direct, 48 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
==5186== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5186== by 0x804866B: insert_node (in /home/vbhadra/linked_list)
==5186== by 0x4060532: (below main) (libc-start.c:226)
==5186==
==5186== LEAK SUMMARY:
==5186== definitely lost: 8 bytes in 1 blocks
==5186== indirectly lost: 48 bytes in 6 blocks
==5186== possibly lost: 0 bytes in 0 blocks
==5186== still reachable: 0 bytes in 0 blocks
==5186== suppressed: 0 bytes in 0 blocks
==5186==
==5186== For counts of detected and suppressed errors, rerun with: -v
==5186== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Analyzing the valgrind output

Looking at the output generated by valgrind is as simple as it can get. Look at the below bits in the output:

HEAP SUMMARY: Section which talks about the usage of the heap (dynamic) memory which the program has used

in use at exit: 56 bytes in 7 blocks : this says it all. There are 56 bytes which the program didn’t free() while existing as a result this memory is still not freed and hence a leak in the available memory in the system.

valgrind gives the details of the memory leak in further sections as can be seen as below:


==5186== 56 (8 direct, 48 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
==5186== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5186== by 0x804866B: insert_node (in /home/vbhadra/linked_list)
==5186== by 0x4060532: (below main) (libc-start.c:226)

In the above valgrind specifying exactly which functions are responsible for the leaked memory, here in this case function like, insert_node().

This line in the output is interesting:

For counts of detected and suppressed errors, rerun with: -v 

So curiously enough let’s run with the -v (verbose) option again as below:


$ valgrind --leak-check=full -v ./linked_list

==5219== Memcheck, a memory error detector
==5219== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==5219== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==5219== Command: ./linked_list
==5219==
--5219-- Valgrind options:
--5219-- --suppressions=/usr/lib/valgrind/debian-libc6-dbg.supp
--5219-- --leak-check=full
--5219-- -v
--5219-- Contents of /proc/version:
--5219-- Linux version 3.13.0-32-generic (buildd@toyol) (gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) ) #57~precise1-Ubuntu SMP Tue Jul 15 03:50:54 UTC 2014
--5219-- Arch and hwcaps: X86, x86-sse1-sse2
--5219-- Page sizes: currently 4096, max supported 4096
--5219-- Valgrind library directory: /usr/lib/valgrind
--5219-- Reading syms from /lib/i386-linux-gnu/ld-2.15.so (0x4000000)
--5219-- Considering /lib/i386-linux-gnu/ld-2.15.so ..
--5219-- .. CRC mismatch (computed 367abd4e wanted f7cf9207)
--5219-- Considering /usr/lib/debug/lib/i386-linux-gnu/ld-2.15.so ..
--5219-- .. CRC is valid
--5219-- Reading syms from /home/vbhadra/linked_list (0x8048000)
--5219-- Reading syms from /usr/lib/valgrind/memcheck-x86-linux (0x38000000)
--5219-- Considering /usr/lib/valgrind/memcheck-x86-linux ..
--5219-- .. CRC mismatch (computed 2a2bce46 wanted 9ac1affc)
--5219-- object doesn't have a symbol table
--5219-- object doesn't have a dynamic symbol table
--5219-- Reading suppressions file: /usr/lib/valgrind/debian-libc6-dbg.supp
--5219-- Reading suppressions file: /usr/lib/valgrind/default.supp
==5219== embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-5219-by-vbhadra-on-???
==5219== embedded gdbserver: writing to /tmp/vgdb-pipe-to-vgdb-from-5219-by-vbhadra-on-???
==5219== embedded gdbserver: shared mem /tmp/vgdb-pipe-shared-mem-vgdb-5219-by-vbhadra-on-???
==5219==
==5219== TO CONTROL THIS PROCESS USING vgdb (which you probably
==5219== don't want to do, unless you know exactly what you're doing,
==5219== or are doing some strange experiment):
==5219== /usr/lib/valgrind/../../bin/vgdb --pid=5219 ...command...
==5219==
==5219== TO DEBUG THIS PROCESS USING GDB: start GDB like this
==5219== /path/to/gdb ./linked_list
==5219== and then give GDB the following command
==5219== target remote | /usr/lib/valgrind/../../bin/vgdb --pid=5219
==5219== --pid is optional if only one valgrind process is running
==5219==
--5219-- REDIR: 0x4018290 (strlen) redirected to 0x38056b04 (???)
--5219-- REDIR: 0x4018010 (index) redirected to 0x38056adf (???)
--5219-- Reading syms from /usr/lib/valgrind/vgpreload_core-x86-linux.so (0x4025000)
--5219-- Considering /usr/lib/valgrind/vgpreload_core-x86-linux.so ..
--5219-- .. CRC mismatch (computed 33f4d79f wanted ac058c14)
--5219-- object doesn't have a symbol table
--5219-- Reading syms from /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so (0x4028000)
--5219-- Considering /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so ..
--5219-- .. CRC mismatch (computed 8c6a0645 wanted b38afa17)
--5219-- object doesn't have a symbol table
--5219-- Reading syms from /lib/i386-linux-gnu/libc-2.15.so (0x4047000)
--5219-- Considering /lib/i386-linux-gnu/libc-2.15.so ..
--5219-- .. CRC mismatch (computed 93120d7a wanted e36e9332)
--5219-- Considering /usr/lib/debug/lib/i386-linux-gnu/libc-2.15.so ..
--5219-- .. CRC is valid
--5219-- REDIR: 0x40c4260 (strnlen) redirected to 0x40254a0 (_vgnU_ifunc_wrapper)
--5219-- REDIR: 0x40c57b0 (strncasecmp) redirected to 0x40254a0 (_vgnU_ifunc_wrapper)
--5219-- REDIR: 0x40c4400 (__GI_strrchr) redirected to 0x402c1b0 (__GI_strrchr)
--5219-- REDIR: 0x40bfef0 (malloc) redirected to 0x402be00 (malloc)
--5219-- REDIR: 0x40c6ad0 (strchrnul) redirected to 0x402ebe0 (strchrnul)
5
--5219-- REDIR: 0x40c03d0 (free) redirected to 0x402b000 (free)
10
20
30
40
50
=============
5
10
20
40
50
=============
5
10
20
25
40
50
=============
2
5
10
20
25
40
50
==5219==
==5219== HEAP SUMMARY:
==5219== in use at exit: 56 bytes in 7 blocks
==5219== total heap usage: 8 allocs, 1 frees, 64 bytes allocated
==5219==
==5219== Searching for pointers to 7 not-freed blocks
==5219== Checked 57,420 bytes
==5219==
==5219== 56 (8 direct, 48 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
==5219== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5219== by 0x804866B: insert_node (in /home/vbhadra/linked_list)
==5219== by 0x4060532: (below main) (libc-start.c:226)
==5219==
==5219== LEAK SUMMARY:
==5219== definitely lost: 8 bytes in 1 blocks
==5219== indirectly lost: 48 bytes in 6 blocks
==5219== possibly lost: 0 bytes in 0 blocks
==5219== still reachable: 0 bytes in 0 blocks
==5219== suppressed: 0 bytes in 0 blocks
==5219==
==5219== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
==5219== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
vbhadra@vbhadra-VirtualBox:~$

As you can see in verbose mode valgrind generates quite a lot extra information which may or may not be of your interest. Fro example you can control valgrind through gdb and the steps to do that can found in the above verbose output. I am not going to discuss this here in this post but would perhaps try to post something in future.

Now here is the linked list implementation which removes the memory leak problem, linked_list_no_mleak.c.

Compile the program in the same way as earlier and run it with valgrind again as below:


$ valgrind --leak-check=full ./linked_list
==5346== Memcheck, a memory error detector
==5346== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==5346== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==5346== Command: ./linked_list
==5346==
5
10
20
30
40
50
=============
5
10
20
40
50
=============
5
10
20
25
40
50
=============
2
5
10
20
25
40
50
Deleting node with val = 2
Deleting node with val = 5
Deleting node with val = 10
Deleting node with val = 20
Deleting node with val = 25
Deleting node with val = 40
Deleting node with val = 50
=============
==5346==
==5346== HEAP SUMMARY:
==5346== in use at exit: 0 bytes in 0 blocks
==5346== total heap usage: 8 allocs, 8 frees, 64 bytes allocated
==5346==
==5346== All heap blocks were freed -- no leaks are possible
==5346==
==5346== For counts of detected and suppressed errors, rerun with: -v
==5346== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
vbhadra@vbhadra-VirtualBox:~$

If you look into the HEAP SUMMARY section, it says “in use at exit: 0 bytes in 0 blocks“, “All heap blocks were freed — no leaks are possible“.

So our program is now memory leak issue free.

 

 

 

 

 

 

 

 

 

One thought on “How to detect memory leak in c program using valgrind?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s