Tutorials > valgrind

Valgrind

You can download the zip for the code below here

Introduction

Valgrind is a dynamic code analyzer software. This is a tool to help developpers with memory debugging, leak detection, and code profiling.

It was created in 2000 by Julian Seward and it aimed to be a free version of Purify (another code analyzer). This tool was initialy built to Linux x86 but it is now a generic framework.

It is mostly used for C and C++ languages, but cause it analyzes the compiled executable, it can work with other languages. Since it has become a framework, some modules (extensions) were created. For example cachegrind (caches errors) and hellgrind (threads errors).

A gui named Valkyrie was developped, but we will only work in command line.

Setup and use Valgrind

First, we need to install Valgrind. You can perform the installation with this very complicated command line :

$ apt install valgrind

You can check valgrind's website here for more informations. You can also take a look at the man documentation reachable below.

$ man valgrind

Compile the code

$ gcc main.c -o main

Run valgrind

$ valgrind ./main

TP

For each example below, you must compile and execute the binary using valgrind, read the report and understand what the issue is and how it is detected.

1 - Memory leaks

#include <stdlib.h>

int main(void)
{
    int *p = malloc(sizeof *p);
    *p = 10;
    p = NULL;
    return 0;    
}

2 - Use after free

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

int main(void)
{
    int *p = malloc(sizeof *p);
    if (p != NULL)
    {
        *p = 180;
        printf("\nValue before free = %d\n", *p);
        free(p);
        printf("\nValue after free = %d\n", *p);
    }
    return 0;
}

3 - Out of bounds

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

int main(void)
{
    int *p = malloc(3 * sizeof *p);
    if (p != NULL)
    {
        printf("\nWriting index 3\n");
        p[3] = 0;
        printf("\nWriting index -1\n");
        p[-1] = 0;
        free(p);
    }
    return 0;    
}

4 - Uninitialized variables

#include <stdio.h>

int main(void)
{
    int i;
    if (i)
    {
        printf("Hello, world !\n");
    }
    return 0;
}

5 - Invalid parameters (uninitialized values)

#include <unistd.h>
#include <stdlib.h>

int main( void )
{
    char* arr = malloc(10);
    (void) write( 1 /* stdout */, arr, 10 );
    return 0;
}

6 - Overlapping

#include <stdlib.h>
#include <string.h> 

int main(void)
{
    char* arr2 = malloc(20);
    char* arr1 = malloc(10);
    memcpy(arr1, arr2, 15);
    return 0;
}

7 - Null derefencing

#include <stdlib.h>

int main(void)
{
    int *p = NULL;
    *p = 0;
    return 0;    
}

8 - Limits

Compile and execute the code below (without then with valgrind):

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

void f(int a, int b)
{
    int *p1, *p2, *p3;
    p1 = (int*) malloc(sizeof(int));
    printf("\nmalloc p1 at %p\n", p1);
    *p1 = a;
    p2 = p1;
    if(a > b)
    {
        printf("\nfree p1 at %p\n", p1);
        free(p1);
    }
    p3 = (int*) malloc(sizeof(int));
    printf("\nmalloc p3 at %p\n", p3);
    *p3 = b;
    printf("\n%d\n", *p2);
    free(p3);
}

void main()
{
    // detected
    f(5, 4); 

    // not trigerring - not detected
    //f(3, 4); 
}

You have time, let's try on a bigger code !

pendu.c

In the first time compile and execute without valgrind !

You can just type words to guess like :

Everything seems fine ? Now execute it with valgrind.

What can you see ?

You can try to find the issue and fix it if you feel like ( it's not that hard :p )