Lenguaje C - C/C++ Error de segmentación

Noviembre 2016


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!

Consulta también :
El documento «Lenguaje C - C/C++ Error de segmentación» de CCM (es.ccm.net) se encuentra disponible bajo una licencia Creative Commons. Puedes copiarlo o modificarlo siempre y cuando respetes las condiciones de dicha licencia y des crédito a CCM.