Instalación

Opción 1: Instalación en Linux (recomendado)

Valgrind es una herramienta que solo se encuentra disponible en Linux. No tiene alternativa para Windows y la versión de macOS tiene un lanzamiento experimental, por lo que la instalación local de la herramienta requiere utilizar un sistema operativo Linux.

No obstante, la instalación local en un entorno de Linux es la alternativa recomendada. Ver la guía de instalación de Linux para alternativas sin tener que reemplazar Windows o macOS como sistema operativo principal.

La instalación de las herramientas depende de la distribución elegida. En Ubuntu los comandos relevantes son:

sudo apt update
sudo apt install build-essential valgrind

En este caso, build-essential incluye gcc entre otras herramientas útiles.

Opción 2: Replit

replit.com es una plataforma para programar en la nube. Una cuenta con un plan gratuito es suficiente para tener el entorno de desarrollo.

Una vez creada la cuenta, se debe crear un nuevo Repl tomando como template una plantilla del lenguaje C.

Dentro del proyecto en sí, hacia la derecha se verá una pestaña de Console y otra de Shell. La que interesará para ejecución de comandos será Shell. La misma es una terminal en un entorno de Linux con gcc ya instalado. Para la instalación de Valgrind, alcanza con ejecutar el comando valgrind y la plataforma ofrecerá alternativas para instalarlo.

El resto de los comandos ofrecidos por el curso deben ejecutarse dentro de dicha terminal.

Verificación de instalación de herramientas y uso

Para asegurar que los comandos estén bien instalados, se debe ejecutar cada uno con el argumento --version. Las salidas obtenidas deberán indicar la versión de cada programa sin error. Por ejemplo:

$ gcc --version
gcc (GCC) 13.2.1 20240417
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ valgrind --version
valgrind-3.23.0

Si se cuenta con un archivo fuente main.c con el siguiente contenido:

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

int main() {
    int* numero = malloc(sizeof(int));
    *numero = 6;
    printf("El numero es: %d\n", *numero);
}

Puede compilarse utilizando gcc. Se incluyen unos argumentos más para que el binario pueda inspeccionarse en detalle con Valgrind:

$ gcc -g -O0 main.c -o main

Si ejecutamos el programa normalmente, no vamos a ver una salida inesperada:

$ ./main
El numero es: 6

Si ejecutamos el programa con Valgrind junto con argumentos adicionales para obtener más información de los errores, vamos a observar el reporte del uso de memoria dinámica:

$ valgrind --leak-check=full --track-origins=yes --show-reachable=yes --error-exitcode=2 ./main
==37797== Memcheck, a memory error detector
==37797== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==37797== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
==37797== Command: ./main
==37797==
El numero es: 6
==37797==
==37797== HEAP SUMMARY:
==37797==     in use at exit: 4 bytes in 1 blocks
==37797==   total heap usage: 2 allocs, 1 frees, 1,028 bytes allocated
==37797==
==37797== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==37797==    at 0x4842788: malloc (vg_replace_malloc.c:446)
==37797==    by 0x10915A: main (main.c:5)
==37797==
==37797== LEAK SUMMARY:
==37797==    definitely lost: 4 bytes in 1 blocks
==37797==    indirectly lost: 0 bytes in 0 blocks
==37797==      possibly lost: 0 bytes in 0 blocks
==37797==    still reachable: 0 bytes in 0 blocks
==37797==         suppressed: 0 bytes in 0 blocks
==37797==
==37797== For lists of detected and suppressed errors, rerun with: -s
==37797== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Se observa que hay 4 bytes de memoria perdidos, de los cuales son esperados pues contábamos con una instrucción malloc para solicitar memoria y el programa finaliza sin un free de ese espacio de memoria solicitado. Valgrind indica que la memoria se solicitó en la línea 5, por lo que agregaremos su free relevante al finalizar la ejecución:

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

int main() {
    int* numero = malloc(sizeof(int));
    *numero = 6;
    printf("El numero es: %d\n", *numero);
    free(numero);
}

Luego de compilar y ejecutar Valgrind, la salida cambia y vemos que el programa se ejecutó sin errores ni pérdidas de memoria:

$ gcc -g -O0 main.c -o main

$ valgrind --leak-check=full --track-origins=yes --show-reachable=yes --error-exitcode=2 ./main
==41475== Memcheck, a memory error detector
==41475== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==41475== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
==41475== Command: ./main
==41475==
El numero es: 6
==41475==
==41475== HEAP SUMMARY:
==41475==     in use at exit: 0 bytes in 0 blocks
==41475==   total heap usage: 2 allocs, 2 frees, 1,028 bytes allocated
==41475==
==41475== All heap blocks were freed -- no leaks are possible
==41475==
==41475== For lists of detected and suppressed errors, rerun with: -s
==41475== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)