These errors usually lead to crashes.
This is a situation where we need Valgrind. Valgrind works directly with the executables, with no need to recompile, relink or modify the program to be checked. Valgrind decides whether the program should be modified to avoid memory leak, and also points out the spots of "leak."
Valgrind simulates every single instruction your program executes. For this reason, Valgrind finds errors not only in your application but also in all supporting dynamically-linked (.so-format) libraries, including the GNU C library, the X client libraries, Qt if you work with KDE, and so on. That often includes libraries, for example the GNU C library, which may contain memory access violations.
#valgrind ps -ax |
Valgrind provides thousands of options. We deliberately avoid them, not to make this article boring.
Consider the output of Valgrind for some test program:
==1353== Invalid read of size 4 ==1353== at 0x80484F6: print (valg_eg.c:7) ==1353== by 0x8048561: main (valg_eg.c:16) ==1353== by 0x4026D177: __libc_start_main (../sysdeps/generic/libc-start.c :129) ==1353== by 0x80483F1: free@@GLIBC_2.0 (in /home/deepu/valg/a.out) ==1353== Address 0x40C9104C is 0 bytes after a block of size 40 alloc'd ==1353== at 0x40046824: malloc (vg_clientfuncs.c:100) ==1353== by 0x8048524: main (valg_eg.c:12) ==1353== by 0x4026D177: __libc_start_main (../sysdeps/generic/libc-start.c :129) ==1353== by 0x80483F1: free@@GLIBC_2.0 (in /home/deepu/valg/a.out) |
Sources of uninitialized data are:
#include <stdlib.h> int main() { int p, t; if (p == 5) /*Error occurs here*/ t = p+1; return 0; } |
#include <stdlib.h> int main() { int *p, i, a; p = malloc(10*sizeof(int)); p[11] = 1; /* invalid write error */ a = p[11]; /* invalid read error */ free(p); return 0; } |
#include <stdlib.h> int main() { int *p, i; p = malloc(10*sizeof(int)); for(i = 0;i < 10;i++) p[i] = i; free(p); free(p); /* Error: p has already been freed */ return 0; } |
#include <stdlib.h> int main() { int *p, i; p = ( int* ) malloc(10*sizeof(int)); for(i = 0;i < 10;i++) p[i] = i; delete(p); /* Error: function mismatch */ return 0; } |
==1066== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) ==1066== malloc/free: in use at exit: 0 bytes in 0 blocks. ==1066== malloc/free: 1 allocs, 1 frees, 40 bytes allocated. ==1066== For a detailed leak analysis, rerun with: --leak-check=yes ==1066== For counts of detected errors, rerun with: -v |
Valgrind checks all parameters to system calls.
#include <stdlib.h> #include <unistd.h> int main() { int *p; p = malloc(10); read(0, p, 100); /* Error: unaddressable bytes */ free(p); return 0; } |
==1045== Syscall param read(buf) contains unaddressable byte(s) ==1045== at 0x4032AF44: __libc_read (in /lib/i686/libc-2.2.2.so) ==1045== by 0x4026D177: __libc_start_main (../sysdeps/generic/libc-start.c:129) ==1045== by 0x80483E1: read@@GLIBC_2.0 (in /home/deepu/valg/a.out) |
Consider the following program:
#include <stdlib.h> int main() { int *p, i; p = malloc(5*sizeof(int)); for(i = 0;i < 5;i++) p[i] = i; return 0; } |
==1048== LEAK SUMMARY: ==1048== definitely lost: 20 bytes in 1 blocks. ==1048== possibly lost: 0 bytes in 0 blocks. ==1048== still reachable: 0 bytes in 0 blocks. |
{ Error name Type fun:function name, which contains the error to suppress fun:function name, which calls the function specified above } |
Error name can be any name. type=ValueN, if the error is an uninitialized value error. =AddrN, if it is an address error.(N=sizeof(data type)) =Free, if it is a free error (eg:mismatched free) =Cond, if error is due to uninitialized CPU condition code. =Param, if it is an invalid system call parameter error. |
You can then run the program with:
valgrind --suppressions=path/to/the/supp_file.supp testprog |