Friday, April 26, 2013

Use valgrind and find memory errors

The segmentation fault is the most frequently occurred runtime error in the C/C++ program compiled using gcc/g++. I have seen that students use TurboC++ compiler because it doesn't show the error like “segmentation fault”. Today's engineering students does not take any efforts to analyze why such kinds of problems occurs?
A program use memory space allocated to it which uses the stack and heap area. The memory is allocated here using runtime. For this we use the malloc function or new operator. Now, when the following situations occur, the program will show the “segmentation fault”.
- Memory is not released using delete/free.
- Using the array index which is not in the specified range.
- The uninitialized pointer is referenced in the program.
- Read only memory is attempted to be used for writing.
- Already freed pointer is dereferenced.

In order to find the reason of such different kinds of memory problem, we may use the valgrind which is a memory checker utility provided by the Linux system. It is used along with GDB. It is not possible for GDB  to find the memory errors in one stroke, so valgrind can be used. It is useful in many scenarios of C/C++ programming. Few of these are discussed in this blog post. Valgrind is used to notify the user with all the errors as given above. Generally, memory leakage problems can be easily detected by the valgrind. As the gcc is very robust compiler, the system tool is very much useful in the programming.

In order to download the valgrind latest version, use the following command on debian based Linux systems such as Ubuntu/Mint.

sudo apt-get install valgrind

or use following to install it on Redhat based Linux.

sudo yum install valgrind

As C/C++ don't have any automatic garbage collector, valgrind can be used to identify the garbages in the program. Lets write a simple program in C++.

#include<iostream>
using namespace std;
int main()
{
     int *x;
     x = new int(10);
     return 0;
}

This program is creating an array of 10 numbers using pointers. So, the memory of 10 locations is allocated to variable x using new operator. Now, compile the program by enabling the debugger to it using following command.

g++ -g prog.cpp -o prog

It will create the executable file named prog. Now use valgrind to check for the memory problems.

valgrind --tool=memcheck --leak-check=yes ./prog

This uses the tool “memcheck” by enabling the checking of the memory leakage ability.

==3550== Memcheck, a memory error detector
==3550== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==3550== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==3550== Command: ./prog
==3550==
==3550==
==3550== HEAP SUMMARY:
==3550== in use at exit: 4 bytes in 1 blocks
==3550== total heap usage: 1 allocs, 0 frees, 4 bytes allocated
==3550==
==3550== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==3550== at 0x402B733: operator new(unsigned int) (in /usr/lib/valgrind/vgpreload _memcheck -x86-linux.so)
==3550== by 0x80485B0: main (prog.cpp:6)
==3550==
==3550== LEAK SUMMARY:
==3550== definitely lost: 4 bytes in 1 blocks
==3550== indirectly lost: 0 bytes in 0 blocks
==3550== possibly lost: 0 bytes in 0 blocks
==3550== still reachable: 0 bytes in 0 blocks
==3550== suppressed: 0 bytes in 0 blocks
==3550==
==3550== For counts of detected and suppressed errors, rerun with: -v
==3550== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Here, 3550 is the process ID of your program. It has shown that the program has definitely lost 4 bytes in 1 block. This is shown because that the memory allocated is not freed. After adding 'delete x' statement at the end of the program, we will get this message using valgrind.

All heap blocks were freed -- no leaks are possible

Lets use the variable x[15] from the given array. It is not possible to use this variable from the array! I will write the following statement in the program.

x[15] = 34;

Now, valgrind shows the following statements:

==3608== Invalid write of size 4
==3608== at 0x80485C2: main (prog.cpp:7)
==3608== Address 0x4330064 is not stack'd, malloc'd or (recently) free'd

It means the line number 7 of prog.cpp has “invalid write of size 4 bytes”! We will easily identify that the memory is used in some wrong way in the program. Remember it is not a syntactical mistake!

Now when we use the uninitialized data in the program such as,

if (x[1]==1)
    x[1] = 0;

As the array is not initialized, the x[1] won't contain any value in it. When you compile the program and analyze it by valgrind, you will get the following output.

==3661== Invalid read of size 4
==3661== at 0x80485C2: main (prog.cpp:7)
==3661== Address 0x433002c is 0 bytes after a block of size 4 alloc'd
==3661== at 0x402B733: operator new(unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3661== by 0x80485B0: main (prog.cpp:6)

This is the error for uninitialized data in the program. You will identify that the statement on line number 6 has some uninitialized data variable in it.
I think using valgrind improves the quality of software development. A software developer must use it in order to solve the memory leakage problems. It has many features, you may use 'man valgrind' to see all these features of it.
Enjoy good programming!

No comments:

Post a Comment