Publicidad

martes, 9 de noviembre de 2010

Depuración con GDB

#include 
#include 

char* Mstrupr(char* szCad);

int main()
{
char szCadena[] = "Esto es una cadena";

printf("%s\n", Mstrupr(szCadena));
printf("%s\n", Mstrupr("Esto es otra cadena"));

return 0;
}

char* Mstrupr(char* szCad)
{
int i;

for (i=0; szCad[i]; i++)
szCad[i] = toupper(szCad[i]);

return szCad;
}



Compilamos y ...
Según el compilador no hay error alguno en el código, pero al ejecutar, esto es lo que sucede:
$ ./sample
ESTO ES UNA CADENA
Segmentation Fault (core dumped)
$
Para localizar el problema utilizamos gdb con el programa del siguiente modo:
$ gdb sample
.
.
(gdb) break main
Breakpoint 1 at 0x8048348: file sample.c, line 8
(gdb) run
Breakpoint 1, main() at sample.c:8
8     char szCadena[] = "Esto es una cadena";
(gdb) next
10    printf("%s\n", Mstrupr(szCadena));
(gdb) next
ESTO ES UNA CADENA
12    printf("%s\n", Mstrupr("Esto es otra cadena"));
(gdb) step
Mstrupr(szCad=0x804856f "Esto es otra cadena") at sample.c:17
21    for (i=0; szCad[i]; i++)
(gdb) next
22       szCad[i] = toupper(szCad[i]);
(gdb) next
Program received signal SIGSEGV, Segmentation fault
0x80484e1 in Mstrupr (szCad=0x08048e1 in Mstrupr (szCad=0x0804856f
"Esto es otra cadena") at sample.c:19
22       szCad[i] = toupper(szCad[i]);
(quit) next
Program terminated with signal SIGSEGV, Segmentation fault
The program no longer exists
(gdb) quit
$
Como vemos, el programa recibe la señal SIGSEGV cuyo significado es "fallo de segmentación" o "violación de segmento", eso quiere decir que nuestro programa ha intentado acceder a memoria que NO       le ha sido asignada por el sistema operativo.
El punto en el que el programa es abortado corresponde con la asignación:
szCad[i] = toupper(szCad[i]);
que corresponde a la función Mstrupr( ), es decir, el valor a la izquierda de la asignación es una localización de memoria que no podemos modificar. Dicha posición de memoria es parte de la cadena "Esto es otra cadena", concretamente el primer carácter.
Pero... ¿por qué no falló la función la primera vez que se llamó y sí la segunda? La respuesta es evidente a la vista del código: En la primera llamada, el argumento es una cadena estática, mientras que en la segunda llamada el argumento es un literal, y como es lógico un literal no puede modificarse porque no es una variable.
De modo que, para solucionar el problema debemos almacenar el literal en otra cadena igual que se hace con la primera. El código modificado quedaría como sigue (la función Mstrupr( ) no sufre ninguna modificación).
int main()
{
char szCadena[] = "Esto es una cadena";
char szOtraCadena[] = "Esto es otra cadena";

printf("%s\n", Mstrupr(szCadena));
printf("%s\n", Mstrupr(szOtraCadena));

return 0;
}
Al compilar y ejecutar el nuevo código obtenemos:
$ ./sample
ESTO ES UNA CADENA
ESTO ES OTRA CADENA
$

No hay comentarios: