viernes, diciembre 30, 2011

¿Puede ser la dirección 0 de memoria un puntero válido en C y Unix?

Teóricamente, según el standar C, la definición del llamado puntero nulo es una expresión entera de valor 0, representada por la macro NULL, que debe estar definida en el fichero stddef.h como mínimo. Cuando programamos en C, solemos usar dicho valor para indicar un puntero no válido, comparamos con él y a veces para evitar cantadas usadamos la macro assert para asegurarnos que no vamos a usar el valor del puntero nulo para acceder a algún objeto en memoria. Desreferenciar el puntero nulo teóricamente debe de devolverver un valor no definido (cuando no directamente por los mecanismos de protección de memoria el sistema operativo acabe abortando la ejecución del programa).

Esto no sería una anécdota hasta que el otro día ejecutando un programa bajo valgrind para buscar posibles problemas en la gestión de memoria del mismo me encontré una llamada a mmap , bajo MacOS X que me devolvía como puntero 0 y errno = 0,es decir, que era un puntero válido. Notar que mmap en caso de error devuelve MAP_FAILED, que suele estar definido como -1 (0xFFFFFFFF en una máquina en el que el tamaño del puntero sea de 32 bits), lo cual hacía que mi programa cascara miserablemente en una macro assert que tenía puesta para evitar los punteros nulos. Desconozco que tipo de interacción tendrá valgrind con la llamada mmap en MacOS X, pero se produce.

No soy el único que se ha encontrado con esto, como puede verse en el código que hay en NULL can be a valid address. Si se ejecuta el programa en el enlace anterior baja la shell normal, muere con un segfaul. Pero bajo valgrind no, el NULL pointer se convierte en una dirección válida.


Technorati Tags: ,

No hay comentarios: