The vulnerability as described in ISO/IEC TR 24772-1:2019 clause 6.13 exists in C++. Dereferencing a pointer with the value of nullptr
is undefined behavior [EWF].
Using pointers is inherently problematic especially for function parameters and return values, due to the following issues:
nullptr
value valid in context?nullptr
value?T[]
as a function parameter type is identical to T*
)Using values instead of pointers sidesteps all pointer vulnerabilities, especially when returned from a function. For example, standard library containers like std::vector
have value semantics and do not suffer from this vulnerability.
C++ references cannot be null in a well-defined program and solve the null-dereferencing vulnerability. They are particularly useful as function parameters. Using a reference as function return type requires the caller to avoid accessing an object outisde of its lifetime (see [XYK], [DCM]).
If absence of a value is necessary, a class type for optional values such as std::optional
provides well-defined behaviour and single-object ownership. In case of attempting to access the value of an empty std::optional
an exception is thrown.
Note: Be aware that optional<T&>
is not supported by the standard library. For representing optional references std::optional<std::reference_wrapper<T>>
or a non-standard implementation of optional
supporting references can be used.
If dynamically allocated objects are required, std::unique_ptr<T>
can be used for lifetime-management and for transferring ownership. When shared ownership of such objects is necessary, std::shared_ptr<T>
is a solution. Using std::shared_ptr<T const>
provides value semantics for immutable heap-allocated objects thus sidestepping most of the issues of pointers above. Constructing a smart pointer through the factories std::make_unique
or std::make_shared
will return a non-null smart pointer or throw an exception and thus prevent the vulnerability of null pointers, in contrast to legacy allocation mechanisms and some overloads of operator new
. However, in general dereferencing a std::unique_ptr
or std::shared_ptr
equal to nullptr
causes undefined behaviour, for example, when such a smart pointer is default constructed or a std::unique_ptr
is in a moved-from state. For further information see also [XYL].
To avoid the vulnerability or mitigate its ill effects, C++ software developers can:
Avoid the need for pointers by using values.
Prefer references over pointers for parameters.
Use std::optional
instead of a pointer to represent a potentially empty value.
Use containers with value semantics instead of plain arrays such as std::array
, std::vector
.
Use make_unique()
or make_shared()
for dynamically allocating objects.
If using objects of pointer-like types that may be a nullptr
value is unavoidable, use the avoidance mechanisms of ISO/IEC 24772-1 clause 6.13.5.
Use static and dynamic analysis tools to detect potential violations of this guideline.