In computing, a null pointer (sometimes shortened to nullptr or null) or null reference is a value indicating that the pointer or reference does not refer to an 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 an object. However, in general, most languages do not offer such a guarantee for uninitialized pointers. 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 behavior. Also, in languages offering such support, the correct use depends on the individual experience of each developer and linter tools. Even when used properly, null pointers are semantically incomplete, since they do not offer the possibility to express the difference between "not applicable", "not currently known", and "not yet determined" values.

In systems 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.

Because a null pointer does not point to a meaningful object, an attempt to access the data stored at that (invalid) memory location may cause a run-time error or immediate program crash. This is the null pointer error, or null pointer exception. It is one of the most common types of software weaknesses, and Tony Hoare, who introduced the concept, has referred to it as a "billion dollar mistake". The preprocessor macro <code>NULL</code> is provided, defined as an implementation-defined null pointer constant in <code><stdlib.h></code>, which in C99 can be portably expressed with , the integer value <code>0</code> converted to the type <code>void*</code> (see pointer to void type). Since C23, a null pointer is represented with <code>nullptr</code> which is of type <code>nullptr_t</code> (first introduced to C++11), providing a type safe null pointer.

The C standard does not say that the null pointer is the same as the pointer to memory address&nbsp;0, though that may be the case in practice. Dereferencing a null pointer is undefined behavior in C,

C++

In C++, while the <code>NULL</code> macro was inherited from C, the integer literal for zero has been traditionally preferred to represent a null pointer constant. However, C++11 introduced the explicit null pointer constant <code>nullptr</code> and type <code>nullptr_t</code> to be used instead, providing a type-safe null pointer. <code>nullptr</code> and type <code>nullptr_t</code> were later introduced to C in C23.

Other languages

Programming languages use different literals for the null pointer. In Java and C#, the literal <code>null</code> is provided as a literal for reference types. In Pascal and Swift, a null pointer is called <code>nil</code>. In Eiffel, it is called a <code>void</code> reference. In Rust, the absence of a value is denoted as <code>None</code>, but a true null pointer is <code>std::ptr::null()</code>.

Null dereferencing

Because a null pointer does not point to a meaningful object, an attempt to dereference (i.e., access the data stored at that memory location) a null pointer usually (but not always) causes a run-time error or immediate program crash. MITRE lists the null pointer error as one of the most commonly exploited software weaknesses.

  • In C, dereferencing a null pointer is undefined behavior. 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 is also not guaranteed, since compilers are permitted to optimize programs under the assumption that they are free of undefined behavior. This behaviour is the same in C++, as there is no null pointer exception in the C++ language. On platforms such as Unix-like systems and Windows with the Visual Studio compiler, an access violation causes a C/C++ <code>SIGSEGV</code> signal to be issued. Although in C/C++ null dereferences are not exceptions which can be caught in C++ <code>try</code>/<code>catch</code> blocks, it is possible to "catch" such an access violation by using (<code>std::</code>)<code>signal()</code> in C/C++ to specify a handler to be called when that signal is issued.
  • Some external C++ libraries, such as POCO C++ Libraries, include a <code>NullPointerException</code> class. Unlike Java, where <code>java.lang.NullPointerException</code> extends <code>java.lang.RuntimeException</code>, <code>Poco::NullPointerException</code> instead extends <code>Poco::LogicException</code>.
  • In Cyclone, a failed null pointer check will throw a <code>Null_Exception</code>.
  • In D, much like C++, a null pointer dereference results in a segmentation fault.
  • In Delphi and many other Pascal implementations, the constant 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 mapped onto a Pascal exception instance if the unit is linked in the clause.
  • In Java, access to a null reference (<code>null</code>) causes a (NPE), which can be caught by error handling code, but the preferred practice is to ensure that such exceptions never occur.
  • In .NET and C#, access to null reference (<code>null</code>) causes a to be thrown. Although catching these is generally considered bad practice, this exception type can be caught and handled by the program.
  • In Objective-C, messages may be sent to a object (which is a null pointer) without causing the program to be interrupted; the message is simply ignored, and the return value (if any) is or , depending on the type.
  • In Rust, dereferencing a null pointer (<code>std::ptr::null()</code>) in an <code>unsafe</code> block results in undefined behaviour, which usually results in a segmentation fault or corrupted memory.
  • Before the introduction of Supervisor Mode Access Prevention (SMAP), a null pointer dereference bug could be exploited by mapping page zero 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.

Mitigation

While there could be languages with no nulls, most do have the possibility of nulls so there are techniques to avoid or aid debugging null pointer dereferences. Bond et al. suggest modifying the Java virtual machine (JVM) to keep track of null propagation. to avoid null dereferences, D, and Rust. Nullable type systems have also been widely adopted in mainstream programming languages: Kotlin, Swift, and TypeScript include them from the start, while C# and Scala have been retrofitted with nullable type systems.

In some languages, analysis can be performed using external tools, but these are weak compared to direct language support with compiler checks since they are limited by the language definition itself.

The last resort of level 3 is when a null reference occurs at runtime; debugging aids can help.

History

In 2009, Tony Hoare stated

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":

See also

  • Memory debugger
  • Zero page

Notes

References