Valgrind has multiple tools in its suite to help you write better C programs. One of the tools is Memcheck which can check for mistakes in allocating and using memory. In this post I’ll share basic usage of the Valgrind Memcheck tool and some of the mistakes I’ve made while using the tool.

Basic Usage

Install Valgrind, if you don’t have it already.

$ sudo apt install valgrind # On Debian

Now you can use it by calling your program as an argument to Valgrind.

$ valgrind ./main

The Memcheck tool is the default tool in Valgrind, but you can specify it with the --tool=memcheck argument. The output from running the command above will contain information about any mistakes you made with using memory.

Imagine you have the main.c program below.

#include <stdlib.h>

void
my_function(void) {
    int *x = malloc(3 * sizeof(*x));
    x[4] = 42;
}

int
main() {
    my_function();
    return 0;
}

The function my_function() allocates space for three integers on the heap, and assigns the address of the 1st integer to x. It then tries to assign the integer 42 past the allocated block, which is a mistake. If you run main by itself you won’t get any indication that you’ve made a mistake.

$ gcc -o main -Wall main.c && ./main
$

But if you run it with Valgrind, it tells you about your invalid write.

$ gcc -o main -Wall main.c && valgrind ./main
==25614== Memcheck, a memory error detector
==25614== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==25614== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==25614== Command: ./main
==25614== 
==25614== Invalid write of size 4
==25614==    at 0x10916B: my_function (in /home/bigturtle/learning/c/main)
==25614==    by 0x109180: main (in /home/bigturtle/learning/c/main)
==25614==  Address 0x4a97050 is 4 bytes after a block of size 12 alloc'd
==25614==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==25614==    by 0x10915E: my_function (in /home/bigturtle/learning/c/main)
==25614==    by 0x109180: main (in /home/bigturtle/learning/c/main)
==25614== 
==25614== 
==25614== HEAP SUMMARY:
==25614==     in use at exit: 12 bytes in 1 blocks
==25614==   total heap usage: 1 allocs, 0 frees, 12 bytes allocated
==25614== 
==25614== LEAK SUMMARY:
==25614==    definitely lost: 12 bytes in 1 blocks
==25614==    indirectly lost: 0 bytes in 0 blocks
==25614==      possibly lost: 0 bytes in 0 blocks
==25614==    still reachable: 0 bytes in 0 blocks
==25614==         suppressed: 0 bytes in 0 blocks
==25614== Rerun with --leak-check=full to see details of leaked memory
==25614== 
==25614== For lists of detected and suppressed errors, rerun with: -s
==25614== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

It also tells you about another mistake you’ve made in main.c. You forgot to free x. You can see this in the “LEAK SUMMARY” section: definitely lost: 12 bytes in 1 blocks

If you run Valgrind again with the --leak-check=yes argument it will tell you about each leak in detail.

$ gcc -o main -Wall main.c && valgrind --leak-check=yes ./main
==25875== Memcheck, a memory error detector
==25875== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==25875== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==25875== Command: ./main
==25875== 
==25875== Invalid write of size 4
==25875==    at 0x10916B: my_function (in /home/bigturtle/learning/c/main)
==25875==    by 0x109180: main (in /home/bigturtle/learning/c/main)
==25875==  Address 0x4a97050 is 4 bytes after a block of size 12 alloc'd
==25875==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==25875==    by 0x10915E: my_function (in /home/bigturtle/learning/c/main)
==25875==    by 0x109180: main (in /home/bigturtle/learning/c/main)
==25875== 
==25875== 
==25875== HEAP SUMMARY:
==25875==     in use at exit: 12 bytes in 1 blocks
==25875==   total heap usage: 1 allocs, 0 frees, 12 bytes allocated
==25875== 
==25875== 12 bytes in 1 blocks are definitely lost in loss record 1 of 1
==25875==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==25875==    by 0x10915E: my_function (in /home/bigturtle/learning/c/main)
==25875==    by 0x109180: main (in /home/bigturtle/learning/c/main)
==25875== 
==25875== LEAK SUMMARY:
==25875==    definitely lost: 12 bytes in 1 blocks
==25875==    indirectly lost: 0 bytes in 0 blocks
==25875==      possibly lost: 0 bytes in 0 blocks
==25875==    still reachable: 0 bytes in 0 blocks
==25875==         suppressed: 0 bytes in 0 blocks
==25875== 
==25875== For lists of detected and suppressed errors, rerun with: -s
==25875== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

If you want line numbers in the error messages, compile your program with the -g flag to include debugging information.

$ gcc -o main -Wall -g main.c && valgrind --leak-check=yes ./main
==50454== Memcheck, a memory error detector
==50454== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==50454== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==50454== Command: ./main
==50454== 
==50454== Invalid write of size 4
==50454==    at 0x10916B: my_function (main.c:6)
==50454==    by 0x109180: main (main.c:11)
==50454==  Address 0x4a97050 is 4 bytes after a block of size 12 alloc'd
==50454==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==50454==    by 0x10915E: my_function (main.c:5)
==50454==    by 0x109180: main (main.c:11)
==50454== 
==50454== 
==50454== HEAP SUMMARY:
==50454==     in use at exit: 12 bytes in 1 blocks
==50454==   total heap usage: 1 allocs, 0 frees, 12 bytes allocated
==50454== 
==50454== 12 bytes in 1 blocks are definitely lost in loss record 1 of 1
==50454==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==50454==    by 0x10915E: my_function (main.c:5)
==50454==    by 0x109180: main (main.c:11)
==50454== 
==50454== LEAK SUMMARY:
==50454==    definitely lost: 12 bytes in 1 blocks
==50454==    indirectly lost: 0 bytes in 0 blocks
==50454==      possibly lost: 0 bytes in 0 blocks
==50454==    still reachable: 0 bytes in 0 blocks
==50454==         suppressed: 0 bytes in 0 blocks
==50454== 
==50454== For lists of detected and suppressed errors, rerun with: -s
==50454== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

Valgrind And Optimization Levels

One gotcha I’ve run into is that sometimes the compiler can optimize away your mistakes. If you compile the main.c example above with optimization level 1, -O1, you won’t get any errors with Valgrind.

$ gcc -o main -Wall -g -O1 main.c && valgrind --leak-check=yes ./main
==51276== Memcheck, a memory error detector
==51276== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==51276== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==51276== Command: ./main
==51276== 
==51276== 
==51276== HEAP SUMMARY:
==51276==     in use at exit: 0 bytes in 0 blocks
==51276==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==51276== 
==51276== All heap blocks were freed -- no leaks are possible
==51276== 
==51276== For lists of detected and suppressed errors, rerun with: -s
==51276== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

That’s because with -O1 the compiler sees that you’re not really doing anything useful with x so it just removed it (and your mistake). You can see the optimized version of your code by adding the -fdump-tree-optimized flag to gcc and examining the main*.optimized file in your working directory.

You can also prove that this is what gcc is doing by passing x as an argument to a function, like printf().

#include <stdio.h>
#include <stdlib.h>

void
my_function(void) {
    int *x = malloc(3 * sizeof(*x));
    x[4] = 0;
    printf("This is the ptr x %p\n", x);
}

int
main() {
    my_function();
    return 0;
}

Now even if you compile it with -O1 you will get the error in Valgrind again.

Another option is to use the the -fno-builtin-malloc flag for gcc. So your gcc invocation becomes: gcc -o main -Wall -g -O1 -fno-builtin-malloc main.c. You will get the error in Valgrind again with this flag.

It is nice that the compiler removes your mistake for you. But I prefer my programs to be completely free from memory mistakes just in case someone compiles it with optimization level zero (-O0). So if feasible, it is best to use -O0 when working with Valgrind.

Valgrind And Segmentation Faults

Another reason to use Valgrind is that it can give you more information about segmentation faults that occur in your program. This is because Valgrind acts as a synthetic CPU and it hands each piece of your code to the Memcheck tool before actually running it. Therefore, you can get an error message before the segmentation fault occurs.

For example, examine the following main.c below.

#include <stdio.h>
#include <stdlib.h>

int
main() {
    char *wat[6] = {"T", "u", "r", "t", "l", "e"};
    printf("%s\n", wat[7]);
    return 0;
}

The printf() reads past the end of the variable wat. This will cause a segmentation fault. If you run it without Valgrind, you get no other clue other than a segmentation fault occurred.

$ gcc -o main -Wall -g -O0 main.c && ./main
Segmentation fault (core dumped)

However with Valgrind, you get more information, including the line number of the mistake.

$ gcc -o main -Wall -g -O0 main.c && valgrind ./main
==29297== Memcheck, a memory error detector
==29297== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==29297== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==29297== Command: ./main
==29297== 
==29297== Invalid read of size 1
==29297==    at 0x484ED16: strlen (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==29297==    by 0x48ECEE7: puts (ioputs.c:35)
==29297==    by 0x1091D1: main (main.c:7)
==29297==  Address 0xeddeb0d3c1e34a00 is not stack'd, malloc'd or (recently) free'd
==29297== 
==29297== 
==29297== Process terminating with default action of signal 11 (SIGSEGV)
==29297==  General Protection Fault
==29297==    at 0x484ED16: strlen (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==29297==    by 0x48ECEE7: puts (ioputs.c:35)
==29297==    by 0x1091D1: main (main.c:7)
==29297== 
==29297== HEAP SUMMARY:
==29297==     in use at exit: 0 bytes in 0 blocks
==29297==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==29297== 
==29297== All heap blocks were freed -- no leaks are possible
==29297== 
==29297== For lists of detected and suppressed errors, rerun with: -s
==29297== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

Valgrind And Bash Scripts

Real world projects are usually compiled not by invoking gcc directly, but with complicated autotools configurations. Sometimes these configurations specify that programs are wrapped in automatically generated bash scripts to ensure compatibility with various systems.

Be careful when running Valgrind with these scripts because Valgrind will attempt to check not only your program, but /bin/bash as well. This is a problem because sometimes bash itself has a memory error. So it is important to make sure that you use Valgrind directly with the generated machine code of your program. This might not always be what make outputs.

Suppressing Valgrind Errors

If you do run into the problem of a memory mistake in a third party library that you don’t control, you can tell Valgrind to suppress an error by adding it to a suppression file.

To suppress an error, first tell Valgrind to output a suppression for each error it finds by adding the --gen-suppressions=all flag.

Going back to the original version of main.c above:

#include <stdlib.h>

void
my_function(void) {
    int *x = malloc(3 * sizeof(*x));
    x[4] = 42;
}

int
main() {
    my_function();
    return 0;
}

Adding, --gen-suppressions=all gives you:

$ gcc -o main -O0 -g main.c && valgrind --gen-suppressions=all --leak-check=yes ./main 
==31333== Memcheck, a memory error detector
==31333== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==31333== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==31333== Command: ./main
==31333== 
==31333== Invalid write of size 4
==31333==    at 0x10916B: my_function (main.c:6)
==31333==    by 0x109180: main (main.c:11)
==31333==  Address 0x4a97050 is 4 bytes after a block of size 12 alloc'd
==31333==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==31333==    by 0x10915E: my_function (main.c:5)
==31333==    by 0x109180: main (main.c:11)
==31333== 
{
   <insert_a_suppression_name_here>
   Memcheck:Addr4
   fun:my_function
   fun:main
}
==31333== 
==31333== HEAP SUMMARY:
==31333==     in use at exit: 12 bytes in 1 blocks
==31333==   total heap usage: 1 allocs, 0 frees, 12 bytes allocated
==31333== 
==31333== 12 bytes in 1 blocks are definitely lost in loss record 1 of 1
==31333==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==31333==    by 0x10915E: my_function (main.c:5)
==31333==    by 0x109180: main (main.c:11)
==31333== 
{
   <insert_a_suppression_name_here>
   Memcheck:Leak
   match-leak-kinds: definite
   fun:malloc
   fun:my_function
   fun:main
}
==31333== LEAK SUMMARY:
==31333==    definitely lost: 12 bytes in 1 blocks
==31333==    indirectly lost: 0 bytes in 0 blocks
==31333==      possibly lost: 0 bytes in 0 blocks
==31333==    still reachable: 0 bytes in 0 blocks
==31333==         suppressed: 0 bytes in 0 blocks
==31333== 
==31333== For lists of detected and suppressed errors, rerun with: -s
==31333== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

If you want to suppress the “Invalid write” mistake in line 5, create a new file called “valgrind.supp” in your working directory. Then add the lines:

{
   <insert_a_suppression_name_here>
   Memcheck:Addr4
   fun:my_function
   fun:main
}

to the file, which you copy and pasted from the Valgrind output with the --gen-suppressions=all flag.

Now if you run Valgrind again but with an additional flag, --suppressions=valgrind.supp, the “Invalid write” mistake in line 5 will no longer show up.

$ valgrind --leak-check=yes --suppressions=valgrind.supp ./main
==32021== Memcheck, a memory error detector
==32021== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==32021== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==32021== Command: ./main
==32021== 
==32021== 
==32021== HEAP SUMMARY:
==32021==     in use at exit: 12 bytes in 1 blocks
==32021==   total heap usage: 1 allocs, 0 frees, 12 bytes allocated
==32021== 
==32021== 12 bytes in 1 blocks are definitely lost in loss record 1 of 1
==32021==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==32021==    by 0x10915E: my_function (main.c:5)
==32021==    by 0x109180: main (main.c:11)
==32021== 
==32021== LEAK SUMMARY:
==32021==    definitely lost: 12 bytes in 1 blocks
==32021==    indirectly lost: 0 bytes in 0 blocks
==32021==      possibly lost: 0 bytes in 0 blocks
==32021==    still reachable: 0 bytes in 0 blocks
==32021==         suppressed: 0 bytes in 0 blocks
==32021== 
==32021== For lists of detected and suppressed errors, rerun with: -s
==32021== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 1 from 1)

That is all for basic Valgrind Memcheck usage. You can read more about Valgrind in the official documentation, including how to use the other tools in its suite.