Punteros en C y Linux lo que no hay que hacer con ellos

Me han mandado un E-mail con una pregunta interesante pidiéndome un ejemplo práctico del problema de los punteros.

Me dicen que no entiende porque siempre lee en todos los manuales de C lo útil y peligroso de los punteros, cuando solo los manejan como una variable mas.

Bueno ya que ando en mi rato de escribir sobre programación, responder con un ejemplo practico como se me ha solicitado, no sin antes tirar mi rollo acerca del problema =)

Los teóricamente son variables sin tipo, porque un puntero tendra el tipo de la zona de memoria a la que apunta, como su nombre en ingles dice pointer o puntero, este tipo de variable es eso, un apuntador y a punta a donde sea

Su utilidad radica en que podemos accesar por medio de ellos a zonas de memoria donde de otra forma no podríamos, su punto débil es que en tiempo de ejecución C no comprueba los punteros esto es simples, no tiene porque y luego C es un lenguaje nivel medio, con menos ganas tiene porque.

Sin embargo podemos confiar en el sistema operativo en que no permitirá que un mal puntero uno dejado por ahí por un programador termine modificando valores de otros programas, al menos podemos confiar en GNU/Linux y otros tipos de Unix =), claro que es una mala práctica de programación dejar punteros sueltos por ahí. En el mejor de los casos modificaremos valores de memoria de nuestro programa y causaremos que falle.

Lo peor que puede pasarnos en un programa de producción, es que nuestro puntero apunte a una zona de memoria de nuestro programa y modifique cosas que no debe, si lo hace el programa no fallara, debería, pero no lo hará, debería darnos un fallo de segmento pero en lugar de eso como apunta a una zona de memoria en la que tiene “permiso” continuara ejecutándose pero con información poco confiable y es esto el riesgo de los punteros, el programa no falla pero ya no puedes confiar en lo que el programa procesa y peor aún, al no existir un fallo palpable depurar un programa con un mal puntero se vuelve una tarea titánica, mas si el programa de mas cientos de líneas de código.
Ahora que hare para comprobar esto, deliberadamente escribiré un programa que manipule un puntero que no retendrá los valores en la memoria ram.

¿Por qué fallara y por que casi nadie se mete en líos con los punteros?

No se meten en líos por suerte, porque muchas personas usan los punteros en variables que no caducan en todo el programa o el puntero caduca junto con la variable eliminando el riesgo.

Nuestro programa fallara porque voy a apuntar a una zona “volátil” y como lo hare.

Bueno no es un secreto que cada que un programa llama una función a ejecutarse, esta reserva la memoria para que se ejecute además reserva la memoria para las variables locales de dicha función y al terminar de ejecutarse antes de continuar la ejecución de un programa se libera toda la memoria ocupada y se destruyen las variables o lo que es igual se liberan los segmentos de variables ocupadas por la función y quedan a disposición de nuevas funciones y nuevas variables

El programa que hará lo siguiente.

Un puntero global o que se mantendrá vivo durante toda la ejecución del programa sera llamado dentro de una función y se le asignara la dirección de memoria de una variable dentro de esa función, al terminar de ejecutarse la función como dije anteriormente los datos serán destruidos pero nuestro puntero seguirá vivo a apuntando a una variable “muerta”, esto es una mala práctica de programación con punteros.

El programa accesara inmediatamente a la zona muerta y leera el valor de dicha zona si este no ha sido modificado aunque la variable este muerta quedara el valor residual y podremos leerlo, después de eso, deliberadamente lanzare una función para fines practicos un sleep, esta reciclara la memoria y cuando intentemos leer la zona… ZAS los datos o están corruptos o no están.

Luego le hare una asignación manual de un valor y este se escribirá en esa zona de memoria por que nuestro apuntador apunta ahí, si existiría algún dato importante de otra variable ahí, seria destruido y luego consultare el valor, hay que recordar que esa zona se considera libre y puede ser usada en cualquier momento por otra función, entonces, lanzare otra función , otro sleep que volverá a usarla y a pisotear lo que había almacenado ahí.

Para fines practico nada de lo que almaceno en esa zona esta seguro de no ser destruido peor aun, nada en esa zona esta seguro por que igual por medio del puntero puedo destruir la información de otra función que en ese momento este en esa zona de memoria causando que el programa haga cosas raras.

El código

#include <stdio.h>

int *puntero = NULL;
int mem = 0;

int funcion1()
{
        int entero = 100;
        mem = &entero;
        printf (“Direccion local %p
almacenada %p\n”,&entero,mem);
        return 0;
}

int main ()
{
funcion1 ();

puntero = mem;
printf (“Valor en el Puntero %d en %p\n”,*puntero,mem);

sleep (2);

printf (“Valor en el Puntero %d en %p\n”,*puntero,mem);

*puntero = 10;

printf (“Valor en el Puntero %d en %p\n”,*puntero,mem);

sleep (2);

printf (“Valor en el Puntero %d en %p\n”,*puntero,mem);

return 0;
}

Ojo, aunque confió en la protección de memoria de Linux, nunca ejecutes este código como root que aunque se ve tan inofensivo, y no debería pasar nada malo al final el programa no se sale de su propia asignación de ram, sin embargo no hay que abusar de la suerte y terminemos con un programa inestable y con acceso root, eso sí es malo, muy malo para nuestro GNU/Linux

El video de la práctica.

5 Comments

Add a Comment

Comment spam protected by SpamBam