En informática , un puntero nulo o una referencia nula es un valor que se guarda para indicar que el puntero o la referencia no se refiere a un objeto válido . Los programas utilizan habitualmente punteros nulos para representar condiciones como el final de una lista de longitud desconocida o la imposibilidad de realizar alguna acción; este uso de punteros nulos se puede comparar con los tipos que aceptan valores NULL y con el valor Nothing en un tipo de opción .
Un puntero nulo no debe confundirse con un puntero no inicializado : se garantiza que un puntero nulo no se compara con cualquier puntero que apunte a un objeto válido. Sin embargo, dependiendo del idioma y la implementación, un puntero no inicializado puede no tener tal garantía. Podría compararse igual a otros punteros válidos; o podría compararse igual a punteros nulos. Puede hacer ambas cosas en diferentes momentos; o la comparación puede ser un comportamiento indefinido .
C
En C , se garantiza que dos punteros nulos de cualquier tipo se comparen igual. [1] La macro del preprocesador NULL
se define como una constante de puntero nulo definida por la implementación, [2] que en C99 se puede expresar de forma portátil como el valor entero 0
convertido al tipo void*
(puntero a vacío ). [3] El estándar C no dice que el puntero nulo sea el mismo que el puntero a la dirección de memoria 0, aunque ese puede ser el caso en la práctica. Desreferenciar un puntero nulo es un comportamiento indefinido en C, [4] y una implementación conforme puede asumir que cualquier puntero desreferenciado no es nulo.
En la práctica, desreferenciar un puntero nulo puede resultar en un intento de lectura o escritura de la memoria que no está mapeada, lo que desencadena una falla de segmentación o una violación de acceso a la memoria. Esto puede manifestarse como un bloqueo del programa o transformarse en una excepción de software que puede ser detectada por el código del programa. Sin embargo, existen determinadas circunstancias en las que este no es el caso. Por ejemplo, en el modo real x86 , la dirección es legible y, por lo general, también se puede escribir, y desreferenciar un puntero a esa dirección es una acción perfectamente válida pero generalmente no deseada que puede conducir a un comportamiento indefinido pero sin fallas en la aplicación. Hay ocasiones en las que desreferenciar el puntero a la dirección cero es intencional y está bien definido; por ejemplo, el código BIOS escrito en C para dispositivos x86 en modo real de 16 bits puede escribir el IDT en la dirección física 0 de la máquina desreferenciando un puntero nulo para escritura. También es posible que el compilador optimice la desreferencia del puntero nulo, evitando un error de segmentación pero provocando otro comportamiento no deseado .0000:0000
C ++
En C ++, mientras que la NULL
macro se heredó de C, tradicionalmente se ha preferido el literal entero para cero para representar una constante de puntero nulo. [5] Sin embargo, C ++ 11 ha introducido la constante de puntero nulo explícito nullptr
que se utilizará en su lugar.
Otros idiomas
En algunos entornos de lenguaje de programación (al menos una implementación patentada de Lisp, por ejemplo), [ cita requerida ] el valor usado como puntero nulo (llamado nil
en Lisp ) puede ser en realidad un puntero a un bloque de datos internos útiles para la implementación (pero no accesible explícitamente desde los programas de usuario), lo que permite utilizar el mismo registro como una constante útil y una forma rápida de acceder a los componentes internos de la implementación. Esto se conoce como nil
vector .
En lenguajes con una arquitectura etiquetada , un puntero posiblemente nulo se puede reemplazar con una unión etiquetada que impone el manejo explícito del caso excepcional; de hecho, un puntero posiblemente nulo puede verse como un puntero etiquetado con una etiqueta calculada.
Los lenguajes de programación utilizan diferentes literales para el puntero nulo . En Python, por ejemplo, se llama a un valor nulo None
. En Pascal y Swift , se llama a un puntero nulo nil
. En Eiffel , se llama void
referencia.
Desreferenciación nula
Debido a que un puntero nulo no apunta a un objeto significativo, un intento de desreferenciar (es decir, acceder a los datos almacenados en esa ubicación de memoria) un puntero nulo generalmente (pero no siempre) causa un error en tiempo de ejecución o un bloqueo inmediato del programa.
- En C , desreferenciar un puntero nulo es un comportamiento indefinido . [4] Muchas implementaciones hacen que dicho código dé como resultado que el programa se detenga con una violación de acceso , porque la representación del puntero nulo se elige para ser una dirección que el sistema nunca asigna para almacenar objetos. Sin embargo, este comportamiento no es universal. Tampoco está garantizado, ya que los compiladores pueden optimizar programas bajo el supuesto de que están libres de comportamiento indefinido.
- En Delphi y muchas otras implementaciones de Pascal, la constante
nil
representa un puntero nulo a la primera dirección en la memoria que también se usa para inicializar las variables administradas. Desreferenciarlo genera una excepción de sistema operativo externo que se asigna a una instancia de excepción Pascal EAccessViolation si la unidad System.SysUtils está vinculada en la cláusula uses. - En Java , el acceso a una referencia nula desencadena un
NullPointerException
(NPE), que puede detectarse mediante el código de manejo de errores, pero la práctica preferida es asegurarse de que tales excepciones nunca ocurran. - En .NET , el acceso a una referencia nula desencadena una excepción NullReferenceException. Aunque detectarlos generalmente se considera una mala práctica, el programa puede detectar y manejar este tipo de excepción.
- En Objective-C , los mensajes pueden enviarse a un
nil
objeto (que es un puntero nulo) sin provocar la interrupción del programa; el mensaje simplemente se ignora y el valor de retorno (si lo hay) esnil
o0
, según el tipo. [6] - Antes de la introducción de SMAP , un error de desreferencia de puntero nulo podría explotarse mapeando pagezero en el espacio de direcciones del atacante y, por lo tanto, haciendo que el puntero nulo apunte a esa región. Esto podría llevar a la ejecución de código en algunos casos. [7]
Mitigación
Existen técnicas para facilitar la depuración de las desreferencias de puntero nulo. [8] [9] Bond y col. [8] sugiere modificar la JVM para realizar un seguimiento de la propagación nula. La idea del sistema Casper [9] es utilizar la transformación del código fuente para rastrear esta propagación, sin modificar la JVM. En algunos casos, es posible generar automáticamente un parche para corregir excepciones de puntero nulo. [10]
Historia
En 2009 , Tony Hoare (CAR Hoare) declaró [11] que inventó la referencia nula en 1965 como parte del ALGOL W idioma. En esa referencia de 2009, Hoare describe su invento como un "error de mil millones de dólares":
Yo lo llamo mi error de mil millones de dólares. Fue la invención de la referencia nula en 1965. En ese momento, estaba diseñando el primer sistema de tipos completo para referencias en un lenguaje orientado a objetos (ALGOL W). Mi objetivo era garantizar que todo uso de referencias fuera absolutamente seguro, y que el compilador las verificara automáticamente. Pero no pude resistir la tentación de poner una referencia nula, simplemente porque era muy fácil de implementar. Esto ha dado lugar a innumerables errores, vulnerabilidades y caídas del sistema, que probablemente han causado mil millones de dólares de dolor y daño en los últimos cuarenta años.
Ver también
- Depurador de memoria
- Página cero
Referencias
Citas
- ^ ISO / IEC 9899 , cláusula 6.3.2.3, párrafo 4.
- ^ ISO / IEC 9899 , cláusula 7.17, párrafo 3: NULL ... que se expande a una constante de puntero nulo definida por la implementación ...
- ^ ISO / IEC 9899 , cláusula 6.3.2.3, párrafo 3.
- ^ a b ISO / IEC 9899 , cláusula 6.5.3.2, párrafo 4, esp. nota al pie 87.
- ^ Stroustrup, Bjarne (marzo de 2001). "Capítulo 5:
Elconst
calificador (§5.4) evita la redefinición accidentalNULL
y garantiza queNULL
se pueda utilizar cuando se requiera una constante". El lenguaje de programación C ++ (14ª edición de la 3ª ed.). Estados Unidos y Canadá: Addison – Wesley. pag. 88 . ISBN 0-201-88954-4. - ^ El lenguaje de programación Objective-C 2.0 , sección "Envío de mensajes a cero" .
- ^ Desreferencia del puntero NULL del kernel explotable de OS X en AppleGraphicsDeviceControl
- ^ a b Bond, Michael D .; Nethercote, Nicholas; Kent, Stephen W .; Guyer, Samuel Z .; McKinley, Kathryn S. (2007). "Seguimiento de manzanas podridas ": 405. doi : 10.1145 / 1297027.1297057 . Cite journal requiere
|journal=
( ayuda ) - ^ a b Cornu, Benoit; Barr, Earl T .; Seinturier, Lionel; Monperrus, Martín (2016). "Casper: seguimiento automático de desreferencias nulas al inicio con trazas de causalidad" . Revista de sistemas y software . 122 : 52–62. doi : 10.1016 / j.jss.2016.08.062 . ISSN 0164-1212 .
- ^ Durieux, Thomas; Cornu, Benoit; Seinturier, Lionel; Monperrus, Martín (2017). "Generación dinámica de parches para excepciones de puntero nulo mediante metaprogramación" (PDF) . 2017 IEEE 24th International Conference on Software Analysis, Evolution and Reengineering (SANER) . IEEE: 349–358. arXiv : 1812.00409 . doi : 10.1109 / SANER.2017.7884635 . ISBN 978-1-5090-5501-2.
- ^ Tony Hoare (25 de agosto de 2009). "Referencias nulas: el error de mil millones de dólares" . InfoQ.com.
Fuentes
- Comité Técnico Conjunto ISO / IEC JTC 1, Subcomité SC 22, Grupo de Trabajo WG 14 (2007-09-08). Norma Internacional ISO / IEC 9899 (PDF) (Borrador del Comité).CS1 maint: varios nombres: lista de autores ( enlace )