Null pointer
In computing, a null pointer or null reference has a value saved for indicating that the pointer or reference does not refer to a valid object. Programs routinely use null pointers to represent conditions such as the end of a list of unknown length or the failure to perform some action; this use of null pointers can be compared to nullable types and to the Nothing value in an option type.
A null pointer should not be confused with an uninitialized pointer: a null pointer is guaranteed to compare unequal to any pointer that points to a valid object. However, depending on the language and implementation, an uninitialized pointer may not have any such guarantee. It might compare equal to other, valid pointers; or it might compare equal to null pointers. It might do both at different times. Or the comparison might be undefined behaviour.
C
In C, two null pointers of any type are guaranteed to compare equal.[1] The preprocessor macro NULL
is defined as an implementation-defined null pointer constant,[2] which in C99 can be portably expressed as the integer value 0
converted to the type void*
(pointer to void).[3] The C standard does not say that the null pointer is the same as the pointer to memory address 0, though that may be the case in practice. Dereferencing a null pointer is undefined behavior in C,[4] and a conforming implementation is allowed to assume that any pointer that is dereferenced is not null.
In practice, dereferencing a null pointer may result in an attempted read or write from memory that is not mapped, triggering a segmentation fault or memory access violation. This may manifest itself as a program crash, or be transformed into a software exception that can be caught by program code. There are, however, certain circumstances where this is not the case. For example, in x86 real mode, the address 0000:0000
is readable and also usually writable, and dereferencing a pointer to that address is a perfectly valid but typically unwanted action that may lead to undefined but non-crashing behavior in the application. There are occasions when dereferencing the pointer to address zero is intentional and well-defined; for example, BIOS code written in C for 16-bit real-mode x86 devices may write the IDT at physical address 0 of the machine by dereferencing a null pointer for writing. It is also possible for the compiler to optimize away the null pointer dereference, avoiding a segmentation fault but causing other undesired behavior.
C++
In C++, while the NULL
macro was inherited from C, the integer literal for zero has been traditionally preferred to represent a null pointer constant.[5] However, C++11 has introduced the explicit null pointer constant nullptr
to be used instead.
Other languages
In some programming language environments (at least one proprietary Lisp implementation, for example), the value used as the null pointer (called nil
in Lisp) may actually be a pointer to a block of internal data useful to the implementation (but not explicitly reachable from user programs), thus allowing the same register to be used as a useful constant and a quick way of accessing implementation internals. This is known as the nil
vector.
In languages with a tagged architecture, a possibly null pointer can be replaced with a tagged union which enforces explicit handling of the exceptional case; in fact, a possibly null pointer can be seen as a tagged pointer with a computed tag.
Programming languages use different literals for the null pointer. In Python, for example, a null value is called None
. In Pascal and Swift, a null pointer is called nil
. In Eiffel, it is called a void
reference.
Null dereferencing
Because a null pointer does not point to a meaningful object, an attempt to dereference (ie. access the data stored at that memory location) a null pointer usually (but not always) causes a run-time error or immediate program crash.
- In C, dereferencing a null pointer is undefined behavior.[4] Many implementations cause such code to result in the program being halted with an access violation, because the null pointer representation is chosen to be an address that is never allocated by the system for storing objects. However, this behavior is not universal. It's also not guaranteed, since compilers are permitted to optimize programs under the assumption that they're free of undefined behaviour.
- In Delphi and many other Pascal implementations, the constant
nil
represents a null pointer to the first address in memory which is also used to initialize managed variables. Dereferencing it raises an external OS exception which is being mapped onto a Pascal EAccessViolation exception instance if the System.SysUtils unit is linked in the uses clause. - In Java, access to a null reference triggers a
NullPointerException
(NPE), which can be caught by error handling code, but the preferred practice is to ensure that such exceptions never occur. - In .NET, access to null reference triggers a NullReferenceException to be thrown. Although catching these is generally considered bad practice, this exception type can be caught and handled by the program. Accessing it with an offset or dereferencing
- In Objective-C, messages may be sent to a
nil
object (which is a null pointer) without causing the program to be interrupted; the message is simply ignored, and the return value (if any) isnil
or0
, depending on the type.[6] - Before the introduction of SMAP, a null pointer dereference bug could be exploited by mapping pagezero into the attacker's address space and hence causing the null pointer to point to that region. This could lead to code execution in some cases.[7]
Mitigation
There are techniques to facilitate debugging null pointer dereferences.[8][9] Bond et al.[8] suggest to modify the JVM in order to keep track of null propagation. The idea of the Casper system[9] is to use source code transformation in order to track this propagation, without modifying the JVM. In some cases, it is possible to automatically generate a patch to fix null pointer exceptions.[10]
History
In 2009 Tony Hoare (C.A.R. Hoare) stated[11] that he invented the null reference in 1965 as part of the ALGOL W language. In that 2009 reference Hoare describes his invention as a "billion-dollar mistake":
I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
See also
References
Citations
- ISO/IEC 9899, clause 6.3.2.3, paragraph 4.
- ISO/IEC 9899, clause 7.17, paragraph 3: NULL... which expands to an implementation-defined null pointer constant...
- ISO/IEC 9899, clause 6.3.2.3, paragraph 3.
- ISO/IEC 9899, clause 6.5.3.2, paragraph 4, esp. footnote 87.
- Stroustrup, Bjarne (March 2001). "Chapter 5:
Theconst
qualifier (§5.4) prevents accidental redefinition ofNULL
and ensures thatNULL
can be used where a constant is required.". The C++ Programming Language (14th printing of 3rd ed.). United States and Canada: Addison–Wesley. p. 88. ISBN 0-201-88954-4. - The Objective-C 2.0 Programming Language, section "Sending Messages to nil".
- OS X exploitable kernel NULL pointer dereference in AppleGraphicsDeviceControl
- Bond, Michael D.; Nethercote, Nicholas; Kent, Stephen W.; Guyer, Samuel Z.; McKinley, Kathryn S. (2007). "Tracking bad apples": 405. doi:10.1145/1297027.1297057. Cite journal requires
|journal=
(help) - Cornu, Benoit; Barr, Earl T.; Seinturier, Lionel; Monperrus, Martin (2016). "Casper: Automatic tracking of null dereferences to inception with causality traces". Journal of Systems and Software. 122: 52–62. doi:10.1016/j.jss.2016.08.062. ISSN 0164-1212.
- Durieux, Thomas; Cornu, Benoit; Seinturier, Lionel; Monperrus, Martin (2017). "Dynamic patch generation for null pointer exceptions using metaprogramming" (PDF). 2017 IEEE 24th International Conference on Software Analysis, Evolution and Reengineering (SANER). IEEE: 349–358. doi:10.1109/SANER.2017.7884635. ISBN 978-1-5090-5501-2.
- Tony Hoare (2009-08-25). "Null References: The Billion Dollar Mistake". InfoQ.com.
Sources
- Joint Technical Committee ISO/IEC JTC 1, Subcommittee SC 22, Working Group WG 14 (2007-09-08). International Standard ISO/IEC 9899 (PDF) (Committee Draft).CS1 maint: multiple names: authors list (link)