Debug (Depuración)

Por Ariel Parra

¿Qué es la Depuración?

La depuración es el proceso de encontrar y resolver errores (o "bugs") en un programa de software. Los errores pueden incluir:

  • Errores lógicos: Resultados incorrectos debido a una lógica defectuosa.
  • Errores de tiempo de ejecución: Fallos que ocurren durante la ejecución del programa.
  • Errores de sintaxis: Problemas con la estructura del código que impiden la compilación.
  • Errores de memoria: Problemas en la memoria del heap, como fugas de memoria o acceso a memoria inválida.
  • Otros errores: Incluyen vulnerabilidades de seguridad y pérdida de datos.
CPC Γα=Ω5

Uso del #define dbg(...) de la plantilla

Una forma común de depurar es imprimiendo variables y valores con cout. Sin embargo, esto puede ser tedioso y poco eficiente. Nuestra macro dbg() simplifica este proceso al imprimir automáticamente el número de línea, el nombre de la variable y su valor, facilitando la identificación de problemas en el código.

#define dbg(...) cerr<<"LINE("<<__LINE__<<")->["<<#__VA_ARGS__<<"]: ["<<(__VA_ARGS__)<<"]\n";   
int i=3;
while(--i){
    dbg(i);// imprime: `LINE(3)->[i]: [2]` y `LINE(3)->[i]: [1]` 
}
int j = i;
dbg(j);// imprime: `LINE(6)->[j]: [0]`
CPC Γα=Ω5

Herramientas de GNU

CPC Γα=Ω5

AddressSanitizer (ASan)

AddressSanitizer es una herramienta para detectar errores de memoria, como desbordamientos de búfer, uso de memoria después de liberarla y accesos a memoria no válida. Está incluida en los compiladores gcc y g++, y se utiliza con el parámetro -fsanitize=address.

  • Compilación: Añade el parámetro -fsanitize=address:

    g++ -fsanitize=address -o my_program my_program.cpp
    
  • Ejecución:

    ./my_program
    
  • Resultado en la Ejecución:

    ==12345==ERROR: AddressSanitizer: use-after-free on address 0x0...
    

    Este mensaje indica que se está accediendo a memoria que ya ha sido liberada.

CPC Γα=Ω5

UndefinedBehaviorSanitizer (UBSan)

UndefinedBehaviorSanitizer detecta comportamientos indefinidos en el código, como divisiones por cero y desbordamientos de enteros. También está incluido en gcc y g++, y se utiliza con el parámetro -fsanitize=undefined.

  • Compilación: Añade el parámetro -fsanitize=undefined:

    g++ -fsanitize=undefined -o my_program my_program.cpp
    
  • Ejecución:

    ./my_program
    
  • Resultado en la Ejecución:

    ==12345==ERROR: UndefinedBehaviorSanitizer: division by zero on address 0x0...
    

    Este mensaje indica un comportamiento indefinido, como una división por cero.

CPC Γα=Ω5

GNU Debugger (GDB)

GNU Debugger (GDB) es una herramienta de depuración para programas escritos en C, C++, y otros lenguajes. Permite a los desarrolladores observar el comportamiento del programa en tiempo real y corregir errores.

Características Principales

  • Puntos de Interrupción: Permite detener la ejecución del programa en líneas específicas del código para examinar el estado del programa.
  • Inspección de Variables: Permite ver y modificar el valor de variables durante la ejecución.
  • Seguimiento de Ejecución: Permite avanzar línea por línea o función por función para observar cómo se ejecuta el código.
  • Control del Programa: Permite iniciar, detener y continuar la ejecución del programa bajo depuración.
CPC Γα=Ω5

Uso Básico de GDB

  1. Compilación con Información de Depuración: Añade la opción -g para incluir información de depuración:

    g++ -g -o my_program my_program.cpp
    
  2. Iniciar GDB:

    gdb my_program
    
  3. Comandos Básicos:

    • Iniciar el Programa: run
    • Establecer un Punto de Interrupción: break <número_de_línea> o break <nombre_de_función>
    • Continuar la Ejecución: continue
    • Paso a Paso: next (para avanzar una línea) o step (para entrar en funciones)
    • Ver el Valor de una Variable: print <nombre_variable>
    • Salir de GDB: quit
CPC Γα=Ω5

Ejemplo de uso de GDB:

gdb my_program
(gdb) break main
Breakpoint 1 at 0x4006d6: file my_program.cpp, line 5.
(gdb) run
Starting program: /path/to/my_program
Breakpoint 1, main () at my_program.cpp:5
5       int a = 10;
(gdb) print a
$1 = 10
(gdb) continue
  • Explicación:
    • break main: Establece un punto de interrupción en la función main.
    • run: Inicia la ejecución del programa hasta el primer punto de interrupción.
    • print a: Muestra el valor de la variable a.
CPC Γα=Ω5

Depuración en VScode

1. Instalar Extensiones:

C/C++ y Error lens

2. Configurar el Lanzador de Depuración

  • Haz clic en el ícono de depuración en la barra lateral izquierda o con el atajo Ctrl+Shift+D.
  • Haz clic en el enlace "Run and Debug" o en el engranaje para crear un archivo de configuración.
  • Selecciona la configuración "C++ (GDB/LLDB)"
CPC Γα=Ω5

3. Añadir Puntos de Interrupción (breakpoints)

  • Establecer un Punto de Interrupción: Haz clic en el margen izquierdo junto a la línea de código donde deseas detener la ejecución. Aparecerá un círculo rojo, indicando que se ha establecido un punto de interrupción.

#c

CPC Γα=Ω5

4. Iniciar la Depuración

  • Ejecutar el Depurador:

    • Haz clic en el ícono de "Play" o selecciona "Start Debugging" en el menú "Run".
    • El programa se ejecutará hasta el primer punto de interrupción.
  • Control de Ejecución:

    • Continuar (F5): Continúa la ejecución hasta el siguiente punto de interrupción.
    • Paso a Paso (F10): Avanza una línea a la vez, sin entrar en funciones.
    • Entrar en Función (F11): Avanza una línea, entrando en la función si se llama a una.
    • Salir de Función (Shift+F11): Continúa la ejecución hasta que la función actual termine.
CPC Γα=Ω5

5. Inspeccionar y Modificar Variables

  • Ver Variables:

    • Las variables locales y globales se mostrarán en la ventana de "Variables" durante la depuración.
  • Modificar Valores:

    • Puedes modificar los valores de las variables durante la ejecución para probar diferentes escenarios.
  • Ver Pila (stack) de Llamadas:

    • La "Call Stack" muestra la secuencia de llamadas de funciones hasta el punto de interrupción actual, permitiendo entender cómo se llegó a ese punto.
CPC Γα=Ω5

Actividad en clase

Depurar en VScode este código:

#include <bits/stdc++>
using namespace std;
int main() {
    int arr[] = { -12, -1234, -45, -67, -1 };
    int n = sizeof(arr) / sizeof(arr[0]);
    int res = 0;
        for (int i = 0; i < n; i++) {
            if (arr[i] > res)
                res = arr[i];
        }
    cout << "Maximum element of array: " << res;
}
CPC Γα=Ω5
#c

Valgrind y Dr. Memory

#c

CPC Γα=Ω5

Valgrind

Es la herramienta para la detección de errores más conocida en la industria, detecta errores tanto de memoria, como accesos inválidos y fugas de memoria. Es usado principalmente en sistemas Linux.

  • Compilación y Ejecución:
    1. Compilar el Programa: Asegúrate de compilar con información de depuración:
      g++ -g -o my_program my_program.cpp
      
    2. Ejecutar Valgrind:
      valgrind --leak-check=full ./my_program
      
  • Resultado en la Ejecución:
    • Valgrind imprimirá un informe detallado sobre errores de memoria, incluyendo accesos inválidos y fugas.
CPC Γα=Ω5

Dr. Memory

Es una herramienta para la detección de errores de memoria similar a Valgrind, como desbordamientos de búfer y fugas. Pero es más rápido en comparación con Valgrind y a diferencia de Valgrind, si esta disponible tanto para Windows, así como para Linux.

  • Uso:
    1. Compilar el Programa: Asegúrate de compilar con información de depuración:
      g++ -g -o my_program my_program.cpp
      
    2. Ejecutar Dr. Memory:
      drmemory -- ./my_program
      
  • Resultado en la Ejecución:
    • Dr. Memory proporcionará informes sobre errores de memoria, destacando problemas como accesos a memoria no válida y fugas.
CPC Γα=Ω5

Referencias

CPC Γα=Ω5
CPC Γα=Ω5
CPC Γα=Ω5