[Tip] Detectar bucles infinitos

For Hang Problem

For Hung Problem

Hoy en la lista de correo de GoLang he descubierto una cosa muy curiosa e importante en el desarrollo de software:
¿Cómo detectar el punto de programa donde se ejecuta un bucle infinito?

Ian Lance Taylor escribió lo siguiente:

    You should be able to get a stack trace by sending a SIGSEGV signal
    (signal 11).

No es una cosa que suela ocurrir frecuentemente (si lo comparamos con los Segmentation faults) pero cuando pasa, ¡madre mía! para encontrar el error.

He hecho un pequeño ejemplo que puede servir como procedimiento para aplicar en casos reales donde esto ocurra.

  1. Supongamos el siguiente código en C:
    #include <stdio.h>
    
    int func1()
    {
      int x,y;
    
      return x*y;
    }
    int func2()
    {
       for (;;)
       {
           func1();
       }
    }
    
    int func3()
    {
       func2();
    
    }
    
    int main(void)
    {
    
       printf("forever for stack trace\n");
    
       func3();
    
    return 0;
    
    }
    
    
  2. Lo guardamos como “testStack.c” y lo compilamos:
    gcc -o testStack testStack.c
  3. Para poder ver la pila de invocaciones del programa es necesario poder generar un core. En muchas distribuciones, por seguridad, no se permite generar cores. Es necesario invocar a “ulimit” con un límite grande para el tamaño máximo de core generado:
     ulimit -c  10000000 
  4. Ejecutamos nuestro programa:
     ./testStack
    

    forever for stack trace

  5. Ahora viene lo interesante. Abrimos otra ventana de shell y mandamos un SIGSEGV a “testStack”:
    pkill -11 testStack 
  6. En la ventana de ejecución de “testStack”, vemos como aparece:
    Fallo de segmentación
  7. Para ver donde se ha quedado, basta con llamar a gdb y pedirle el backtrace:
    gdb ./testStack core
    
    GNU gdb 6.8-debian
    Copyright (C) 2008 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html&gt;
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type “show copying”
    and “show warranty” for details.
    This GDB was configured as “i486-linux-gnu”…
    warning: Can’t read pathname for load map: Input/output error.
    Reading symbols from /lib/tls/i686/cmov/libc.so.6…done.
    Loaded symbols for /lib/tls/i686/cmov/libc.so.6
    Reading symbols from /lib/ld-linux.so.2…done.
    Loaded symbols for /lib/ld-linux.so.2
    Core was generated by `./testStack’.
    Program terminated with signal 11, Segmentation fault.
    [New process 2024]
    #0  0x080483c4 in func1 ()
    (gdb) bt
    #0  0x080483c4 in func1 ()
    #1  0x080483db in func2 ()
    #2  0x080483e8 in func3 ()
    #3  0x0804840c in main ()
    Current language:  auto; currently asm
    (gdb)
  8. Como se puede apreciar, nuestro programa se encontraba ejecutando la func1() en el momento de recibir el SIGSEGV. ¡Ya sabemos que por alguna func{1,2,3} está el problema! En este caso es un poco inútil, pero en software real puede ahorrarnos muchos dolores de cabeza.

Espero que este tip os sirva. A mi desde luego que sí🙂

Translate to:English
MenefanteMenéame TwitterTwitter

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: