Valgrind Tutorial

Valgrind is an excellent tool for solving two problems in your programs: memory leak e access to invalid memory locations (which can lead to segmentation fault).

The following are some examples of how to use Valgrind.

Consider the following program that reads 10 numbers and then prints them in reverse order.

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

int main(int argc, char const *argv[]) {
  int i, *vetor = malloc(10 * sizeof(int));
  for (i = 0; i < 10; i++)
    scanf("%d", &vetor[i]);
  for (i = 9; i >= 0; i--)
    printf("%d\n", vetor[i]);
  return 0;
}

This program has a memory leak: the allocated vector is not deallocated before the program ends.

This can be detected with Valgrind. Suppose the compiled file calls SCHEDULE and that you have a test file called entry (such as those provided in SuSy).

At the terminal, run:

valgrind --leak-check=full ./programa < entrada**

You will see the following result.

==1918== Memcheck, a memory error detector
==1918== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==1918== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==1918== Command: ./programa
==1918==

...

==1918==
==1918== HEAP SUMMARY:
==1918==     in use at exit: 40 bytes in 1 blocks
==1918==   total heap usage: 3 allocs, 2 frees, 5,160 bytes allocated
==1918==
==1918== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==1918==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==1918==    by 0x108758: main (programa.c:5)
==1918==
==1918== LEAK SUMMARY:
==1918==    definitely lost: 40 bytes in 1 blocks
==1918==    indirectly lost: 0 bytes in 0 blocks
==1918==      possibly lost: 0 bytes in 0 blocks
==1918==    still reachable: 0 bytes in 0 blocks
==1918==         suppressed: 0 bytes in 0 blocks
==1918==
==1918== For counts of detected and suppressed errors, rerun with: -v
==1918== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

In the beginning Valgrind gives some standard messages, then we see the program output (replaced here by…) and then Valgrind warns that there were lost bytes in the HEAP SUMMARY and LEAK SUMMARY sections. We lost 40 bytes in one block (called a malloc). More than that, they warn that the malloc responsible for the leak was in the file programa.c, in line 5 (programa.c: 5).

Suppose you correct the code by releasing the vector:

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

int main(int argc, char const *argv[]) {
  int i, *vetor = malloc(10 * sizeof(int));
  for (i = 0; i < 10; i++)
    scanf("%d", &vetor[i]);
  for (i = 9; i >= 0; i--)
    printf("%d\n", vetor[i]);
  free(vetor);
  return 0;
}

Then the output of valgrind will be:

==1931== Memcheck, a memory error detector
==1931== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==1931== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==1931== Command: ./programa
==1931==

...

==1931==
==1931== HEAP SUMMARY:
==1931==     in use at exit: 0 bytes in 0 blocks
==1931==   total heap usage: 3 allocs, 3 frees, 5,160 bytes allocated
==1931==
==1931== All heap blocks were freed -- no leaks are possible
==1931==
==1931== For counts of detected and suppressed errors, rerun with: -v
==1931== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

That is, in this case there is no memory leak!

Valgrind also warns of access errors to invalid positions. For example, the following program tries to write the number 1 in position 0 of the vector, but the vector starts as NULL, that is, we try to write in the 0x0 (NULL) position of memory.

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

int main(int argc, char const *argv[]) {
  int *vetor = NULL;
  vetor[0] = 1;
  return 0;
}

In this case, Valgrind warns us that we are doing illegal writing on line 6 of the program.c. So it is possible to know what caused the segmentation fault.

==1990== Memcheck, a memory error detector
==1990== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==1990== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==1990== Command: ./programa
==1990==
==1990== Invalid write of size 4
==1990==    at 0x108677: main (programa.c:6)
==1990==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==1990==
==1990==
==1990== Process terminating with default action of signal 11 (SIGSEGV)
==1990==  Access not within mapped region at address 0x0
==1990==    at 0x108677: main (programa.c:6)
==1990==  If you believe this happened as a result of a stack
==1990==  overflow in your program's main thread (unlikely but
==1990==  possible), you can try to increase the size of the
==1990==  main thread stack using the --main-stacksize= flag.
==1990==  The main thread stack size used in this run was 8388608.
==1990==
==1990== HEAP SUMMARY:
==1990==     in use at exit: 0 bytes in 0 blocks
==1990==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==1990==
==1990== All heap blocks were freed -- no leaks are possible
==1990==
==1990== For counts of detected and suppressed errors, rerun with: -v
==1990== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault

See another example, where we allocate a vector of 8 positions, but try to use up to 10 positions.

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

int main(int argc, char const *argv[]) {
  int i, *vetor = malloc(8 * sizeof(int));
  for (i = 0; i < 10; i++)
    scanf("%d", &vetor[i]);
  for (i = 9; i >= 0; i--)
    printf("%d\n", vetor[i]);
  free(vetor);
  return 0;
}

The valgrind output indicates the problem of writing in the wrong position of the vector line 7 (invalid write of size 4), indicating where the closest memory block was allocated (a 32-byte block allocated in program.c: 5) and indicates also the problem of reading in the wrong position (invalid read of size 4).

==1955== Memcheck, a memory error detector
==1955== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==1955== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==1955== Command: ./programa
==1955==
==1955== Invalid write of size 4
==1955==    at 0x4E91794: _IO_vfscanf (vfscanf.c:1902)
==1955==    by 0x4E9C23A: scanf (scanf.c:33)
==1955==    by 0x1087CD: main (programa.c:7)
==1955==  Address 0x51d7060 is 0 bytes after a block of size 32 alloc'd
==1955==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==1955==    by 0x108798: main (programa.c:5)
==1955==
==1955== Invalid read of size 4
==1955==    at 0x1087F5: main (programa.c:9)
==1955==  Address 0x51d7064 is 4 bytes after a block of size 32 alloc'd
==1955==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==1955==    by 0x108798: main (programa.c:5)
==1955==

...

==1955==
==1955== HEAP SUMMARY:
==1955==     in use at exit: 0 bytes in 0 blocks
==1955==   total heap usage: 3 allocs, 3 frees, 5,152 bytes allocated
==1955==
==1955== All heap blocks were freed -- no leaks are possible
==1955==
==1955== For counts of detected and suppressed errors, rerun with: -v
==1955== ERROR SUMMARY: 4 errors from 2 contexts (suppressed: 0 from 0)