Cómo identificar un error de segmentación en C - C/C++

Cómo identificar un error de segmentación en C - C/C++

Lee este artículo si alguna vez has desarrollado una aplicación en C/C++ en Linux, y todo iba bien después de compilarlo hasta que al ejecutar obtuviste un mensaje de error de segmentación. Aquí te explicamos a qué se pudo deber.

¿Cuáles pueden ser los mensajes de error?

Los mensajes pueden ser los siguientes:

Erreur de segmentación

o

Segmentation fault

¿A qué se deben estos mensajes?

Cuando cometemos un error en un programa escrito en un lenguaje de alto nivel (perl, python, java etc.) suele aparecer un mensaje de error detallado: el tipo de error que se ha producido, la línea del programa en donde ha tenido lugar...

Con un lenguaje compilado (como C o C++) nuestros programas no están bajo la tutela de ningún intérprete o máquina virtual. Por lo tanto, nadie encontrará y analizará nuestros errores. Pero existen programas llamados depuradores que nos facilitan la tarea.

Los sistemas operativos suelen asignar una porción de memoria a cada aplicación. Si una aplicación intenta acceder directamente a una posición de memoria que no le pertenece o a una posición de memoria incorrecta, el sistema operativo detendrá la aplicación y generará un error (en Linux: Error de segmentación).

¿Cómo identificar errores en C?

Tomemos como ejemplo un programa en C creado de manera intencionada para que genere un error de segmentación:

void devuelve_error_de_segmentacion()
{
 int *puntero_peligroso=(int *) 100;
 int test=*puntero_peligroso;
}

int main(int argc, char ** argv)
{
 devuelve_error_de_segmentacion();
 return 0;
}

En la función devuelve_error_de_segmentacion, el puntero_peligroso apunta hacia la dirección 100 en la memoria. Esta es una dirección que no puede pertenecer a una aplicación normal y, por tanto, cuando puntero_peligroso intente leer lo que hay ahí, el programa colapsará y mostrará el mensaje “Error de segmentación”.

Para depurar este programa empezaremos por compilarlo cargando sus símbolos de depuración. Esto permite leer los nombres de las funciones y variables utilizadas en el programa una vez compilado y de este modo el depurador podrá hacer un seguimiento del error e indicar los nombres de estas en vez de dar únicamente su dirección.

La opción a la que se hace referencia es la opción –g.

Compilamos:

gcc -g test.c -o test

Corremos el programa en el depurador:

gdb ./test

Aparecerá el prompt comenzando por:

(gdb)

Escribimos el comando run y observamos lo que pasa:

Program received signal SIGSEGV, Segmentation fault.
0x08048334 in devuelve_error_de_segmentacion () at test.c:4
4               int test=*puntero_peligroso;

El depurador nos indica la línea del archivo que ocasiona el error, así como la función y el contenido de la línea, es un error en la función devuelve_error_de_segmentacion en el archivo fuente test.c en la línea 4 cuyo contenido es:

int test=*puntero_peligroso;

Ahora supongamos que queremos saber qué función ha llamado a otra desde el inicio del programa hasta que se produjo el error.

Escribimos el comando bt:

(gdb) bt
#0  0x08048334 in da_error__de_segmentación () at test.c:4
#1  0x0804834e in main () at test.c:9

Y obtenemos lo que buscábamos.

¿Cómo identificar errores C++?

En relación al error de segmentación no hay mucho que añadir. Tan sólo que hay que utilizar el comando g++ con la opción –g del mismo modo que con gcc.

El informe de gdb será el mismo pero con detalles sobre las clases concernidas.

Ejemplo:

//Archivo test.cpp
class Test{
 public:
  int a;
  Test(){};
  ~Test(){};
  int incremente_a(){ a++; };
};

int main()
{
 Test *t;
 t=(Test *)100;
 t->incremente_a();
 return 0;
}

Compilamos:

g++ -g test.cpp -o test

Ejecutamos el depurador:

gdb ./test

Escribimos los mismos comandos que antes y aparecen todos los detalles:

(gdb) run
Starting program: /home/chantecode/Desktop/test 
Program received signal SIGSEGV, Segmentation fault.
0x080483fc in Test::incremente_a (this=0x64) at test.cpp:7
7                       int incremente_a(){ a++; };
(gdb) bt
#0  0x080483fc in Test::incremente_a (this=0x64) at test.cpp:7
#1  0x080483e7 in main () at test.cpp:14

Lenguajes