Valgrind also includes a set of useful profiling tools, including the cache, heap and callgraph profilers valgrid tools. Documentation for these tools is here: valgrind tools docs
In /home/newhall/public/valgrind_examples/
is an example program with bad memory access errors (comments in
the code describe the type of error). You can try out valgrind on this
program to get an idea of how it works and what types of errors it can find.
valgrind -v ./a.out valgrind -v ./a.out >& out # re-direct valgrind (and a.out) output to file 'out'
If you look through the out file, you may see memory errors listed like this (each line of valgrind output starts with ==processid==):
==9860== Invalid write of size 1 ==9860== at 0x8048532: foo (main.c:28) ==9860== by 0x804859F: main (main.c:48) ==9860== by 0x4023514E: __libc_start_main (in /lib/libc-2.2.5.so) ==9860== by 0x80483D0: (within /home/newhall/public/purify_examples/badprog) ==9860== Address 0x40F33061 is 0 bytes after a block of size 5 alloc'd ==9860== at 0x401678B8: malloc (vg_clientfuncs.c:103) ==9860== by 0x80484C8: foo (main.c:17) ==9860== by 0x804859F: main (main.c:48) ==9860== by 0x4023514E: __libc_start_main (in /lib/libc-2.2.5.so)This tells me that in function foo, at line 28 in main.c, my program is writing 1 byte beyond the array that was allocated at line 17 in function foo (9860 was the process ID of my running program). If I look at lines 17 and 28 of my program, the error is obvious (my loop executes one to many times, accessing c[5], which is beyond the end of array c, on the last iteration):
17 c = (char *)malloc(sizeof(char)*5); 18 strcpy(c, "cccc"); 19 ... 27 for(i=0; i <= 5; i++) { 28 c[i] = str[i]; 29 }NOTE: at the end of a valgrind run memory leak information is printed out. Although removing all memeory leaks from your program is important, other types of valgrind errors are more critical to correctness (and to remove strange behavior) from your program's execution. Look for and fix other errors like invalid reads and writes, using unitialized memory first, then fix memory leaks.
# compile with -g gcc -Wall -g -o valtester valtester.c # run on valgrind valgrind ./valtester ==5674== Memcheck, a memory error detector ==5674== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==5674== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==5674== Command: valtester ==5674== ==5674== Invalid write of size 1 ==5674== at 0x1087D9: foo (valtester.c:29) ==5674== by 0x10885C: main (valtester.c:49) ==5674== Address 0x522d095 is 0 bytes after a block of size 5 alloc'd ==5674== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==5674== by 0x108774: foo (valtester.c:18) ==5674== by 0x10885C: main (valtester.c:49) ==5674== ==5674== Invalid read of size 1 ==5674== at 0x4C32D04: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==5674== by 0x4E994D2: vfprintf (vfprintf.c:1643) ==5674== by 0x4EA0F25: printf (printf.c:33) ==5674== by 0x108804: foo (valtester.c:34) ==5674== by 0x10885C: main (valtester.c:49) ==5674== Address 0x522d095 is 0 bytes after a block of size 5 alloc'd ==5674== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==5674== by 0x108774: foo (valtester.c:18) ==5674== by 0x10885C: main (valtester.c:49) ==5674== ...There are a lot of memory access errors in this program. Taking a look at the first couple errors that valgrind finds (Invalid Write and Invalid Read), indicate that the program is accessing unallocated memory. Valigrind ouput indicates that the invalid write happens at line 29 of the program, and it happens to a memory location that is just beyond an allocated block of heap memory of size 5:
==5674== Invalid write of size 1 ==5674== at 0x1087D9: foo (valtester.c:29) ==5674== by 0x10885C: main (valtester.c:49) ==5674== Address 0x522d095 is 0 bytes after a block of size 5 alloc'dLooking at that line of code in the program:
28 for(i=0; i <=5; i++) { 29 c[i] = str[i];shows array element access in a loop. A likely explaination is that the loop bounds are off, resulting in accessing elements beyond the bounds of an array. Since this is an Invalid Write error, the error is with assigning (or writing to) the ith bucket of array c.
The other part of the valgrind information indicates where the memory around this write error was allocated:
==5674== Address 0x522d095 is 0 bytes after a block of size 5 alloc'd ==5674== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==5674== by 0x108774: foo (valtester.c:18) ==5674== by 0x10885C: main (valtester.c:49)Looking at line 18 in the program:
18 c = (char *)malloc(sizeof(char)*5);shows that c points to malloced space of size 5, but the for loop bounds at line 28 result in indexing into c at index 5, which is invalid. This leads to writing beyond the bounds of the array resulting in the Invalid Write error.
At this point, you could change the program (either allocate more space, or change the for loop bounds to not go beyond the end of the array). And re-running in valgrind will result in this memory access error no longer being displayed. By changing the loop bounds to `i < 5` (and also noting, and fixing the same error for the statically declared array), recompiling and running in valgrind, you can see that this error has been fixed:
gcc -Wall -g -o valtester valtester.c valgrind ./valtester ==5688== Memcheck, a memory error detector ==5688== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==5688== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==5688== Command: valtester ==5688== ==5688== Invalid read of size 1 ==5688== at 0x4C32D04: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==5688== by 0x4E994D2: vfprintf (vfprintf.c:1643) ==5688== by 0x4EA0F25: printf (printf.c:33) ==5688== by 0x108804: foo (valtester.c:34) ==5688== by 0x10885C: main (valtester.c:49) ==5688== Address 0x522d095 is 0 bytes after a block of size 5 alloc'd ==5688== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==5688== by 0x108774: foo (valtester.c:18) ==5688== by 0x10885C: main (valtester.c:49) ...The first that is listed was the second error from the first run: we have successfully fix one memory access error!
In looking at this ouput, it looks like the error is in the vfprintf function in the stdio library. However, it is unlikely that there is really an error in this library function. Instead, the error is much more likely in our program code that calls C standard library functions (i.e. we are passing in a bad value to this function). Looking at our program code where this error occurs (at line 34 in valtester.c):
34 printf("a = %s, b = %s c = %s\n", a, b, c);we see that array c is an argument for a string placeholder value in the format string passsed to printf. This means that printf expects c's contents to be formatted as a C string. If we look at how c is initialized (in the for loop we just fixed the bounds of), we notice that there is no code to ever null terminate the string c. One fix is to explicitly add code to null terminate the c string (this is not the only way to fix this problem, and it may not be the right way for this program, but it will get rid of the Invalid read):
c[4] = '\0';re-compiling the fixed version and running in valgrind again results in this error being removed:
gcc -Wall -g -o valtester valtester.c valgrind ./valtester ==8977== Memcheck, a memory error detector ==8977== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==8977== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==8977== Command: valtester ==8977== a = sssssbbbb, b = bbbb c = ssss s = ssssss ==8977== Conditional jump or move depends on uninitialised value(s) ==8977== at 0x4C32CF9: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==8977== by 0x4E994D2: vfprintf (vfprintf.c:1643) ==8977== by 0x4EA0F25: printf (printf.c:33) ==8977== by 0x10880F: foo (valtester.c:35) ==8977== by 0x1088A5: main (valtester.c:55) ...The program now ran much further before valgrind finds the first heap memory access error. We would continue on this way, fixing errors and re-running until all errors are removed. The next error has to do with using uninitialized heap memory (the program is accessing valid malloc'ed memory space, but the program is not initializing the memory before the values stored in it are being used).
One thing to note about this example, is that even though valgrind cannot find memory access errors with stack memory, because our program had a similar stack memory error to a heap memory error that valgrind did find, we were able to see and fix the stack memory error too (the one with the loop bounds error in accessing array a).
At the end of each run of valgrind is a list of memory leaked by the program.
==5674== HEAP SUMMARY: ==5674== in use at exit: 23 bytes in 4 blocks ==5674== total heap usage: 8 allocs, 5 frees, 1,071 bytes allocated ==5674== ==5674== LEAK SUMMARY: ==5674== definitely lost: 23 bytes in 4 blocks ==5674== indirectly lost: 0 bytes in 0 blocks ==5674== possibly lost: 0 bytes in 0 blocks ==5674== still reachable: 0 bytes in 0 blocks ==5674== suppressed: 0 bytes in 0 blocks ==5674== Rerun with --leak-check=full to see details of leaked memory ==5674== ==5674== For counts of detected and suppressed errors, rerun with: -v ==5674== Use --track-origins=yes to see where uninitialised values come from ==5674== ERROR SUMMARY: 24 errors from 11 contexts (suppressed: 0 from 0)Fixing memory leaks should be done after you have fixed all other memory access errors in your program. Leaking heap memory (losing an address of heap space before it is free'ed), can lead to running out of program memory space, but other types of memory access errors are more critial to program's runtime behavior, and fixing some of those may change the memory leak behavior of your program.
Re-running valgrind with the leak-check=full flag will produce more verbose output about memory leaks that you can then go in and fix in your program (leaked memory means all variables storing the address of a particular chunk of malloc'ed heap space have gone out of scope before the program explicitly free'ed this heap space. This results in leaked memory (memory space that can never be freed'ed because the program no longer has a variable that points to it):
valgrind --leak-check=full valtester ... ==8700== HEAP SUMMARY: ==8700== in use at exit: 23 bytes in 4 blocks ==8700== total heap usage: 8 allocs, 5 frees, 1,071 bytes allocated ==8700== ==8700== 5 bytes in 1 blocks are definitely lost in loss record 1 of 4 ==8700== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==8700== by 0x108774: foo (valtester.c:18) ==8700== by 0x10885C: main (valtester.c:49) ==8700== ...the more verbose memory leak information provides source code line numbers where space that was leaked was allocated. The above showing that the program is leaking the memory allocated at line 18 (i.e. the array c is allocated but never freed). The fix is to explicitly free arra c before the function return:
free(c); c = NULL;
valgrind --help # see valgrind help info valgrind -v ./a.out # more verbose output valgrind --gdb-attach=yes ./a.out # attach gdb after each error valgrind finds valgrind --logfile=valout ./a.out # all valgrind output to file named valout.valgrind --leak-check=yes ./a.out # enable verbose memory leak error reporting