Qué es un error de segmentación
Si desarrollaste una aplicación en C/C++ bajo Linux. Lo compilaste, todo iba bien. Luego ejecutas la aplicación para probarla y obtienes uno de estos dos mensajes:
Erreur de segmentación
o
Segmentation fault
Cuando cometemos un error en un programa escrito en un lenguaje de alto nivel (perl, python, java etc...), nos aparece un mensaje de error detallado: el tipo de error que se ha producido, la línea del programa en que se produjo, …
Con un lenguaje compilado (transformado en un lenguaje que puede ser comprendido directamente por el procesador) como C o C++, nuestros programas no están bajo la tutela de ningún interprete o máquina virtual. Por lo tanto nadie encontrará y analizará nuestros errores.
Felizmente existen programas llamados depuradores que nos facilitan la tarea.
Como es sabido, los actuales sistemas operativos (Windows nt/2000/XP/; Linux); asignan 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 en una posición de memoria incorrecta, el sistema operativo detendrá la aplicación y generará un error (bajo Linux: Error de segmentación)
En C
Tomemos como ejemplo un programa en C creado intencionalmente para que se plante y 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.
Cuando puntero_peligroso intente leer lo que hay en la dirección de memoria 100 para asignar el valor guardado en esta dirección a la variable test, el programa se plantará, y mostrará el mensaje “Error de segmentación”.
Para depurar este programa empezaremos por compilarlo cargándole sus símbolos de depuración. Esto permite cargar los nombres de las funciones y variables utilizadas en el programa una vez compilado, de este modo el depurador podrá hacer un seguimiento del error e indicar los nombres de las funciones concernidas en vez de dar únicamente su dirección.
La opción a la que hago 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
Observamos lo que pasa:
(gdb) run
Starting program: /home/chantecode/Desktop/test
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 concernida 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
En C++
En relación al error de segmentación no hay mucho que añadir, solo que hay que utilizar el comando g++ con la opción –g del mismo modo que con gcc.
La 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
Y listo!
PD: El
artículo original fue escrito por kilian, contribuidor de
CommentCaMarche