Warning C26429
Symbol is never tested for nullness, it can be marked as
gsl::not_null
.
C++ Core Guidelines:
F.23: Use a not_null<T>
to indicate that "null" isn't a valid value
It's a common practice to use asserts to enforce assumptions about the validity of pointer values. The problem is, asserts don't expose assumptions through the interface (such as in return types or parameters). Asserts are also harder to maintain and keep in sync with other code changes. The recommendation is to use gsl::not_null
from the Guidelines Support Library to mark resources that should never have a null value. The rule USE_NOTNULL
helps to identify places that omit checks for null and hence can be updated to use gsl::not_null
.
Remarks
The logic of the rule requires code to dereference a pointer variable so that a null check (or enforcement of a non-null value) would be justified. So, warnings are emitted only if pointers are dereferenced and never tested for null.
The current implementation handles only plain pointers (or their aliases) and doesn't detect smart pointers, even though gsl::not_null
can be applied to smart pointers as well.
A variable is marked as checked for null when it's used in the following contexts:
- as a symbol expression in a branch condition, for example,
if (p) { ... }
; - non-bitwise logical operations;
- comparison operations where one operand is a constant expression that evaluates to zero.
The rule doesn't have full dataflow tracking. It can produce incorrect results in cases where indirect checks are used (such as when an intermediate variable holds a null value and is later used in a comparison).
Code analysis name: USE_NOTNULL
Example
Hidden expectation:
using client_collection = gsl::span<client*>;
// ...
void keep_alive(const connection *connection) // C26429
{
const client_collection clients = connection->get_clients();
for (ptrdiff_t i = 0; i < clients.size(); i++)
{
auto client = clients[i]; // C26429
client->send_heartbeat();
// ...
}
}
Hidden expectation clarified by gsl::not_null
:
using client_collection = gsl::span<gsl::not_null<client*>>;
// ...
void keep_alive(gsl::not_null<const connection*> connection)
{
const client_collection clients = connection->get_clients();
for (ptrdiff_t i = 0; i < clients.size(); i++)
{
auto client = clients[i];
client->send_heartbeat();
// ...
}
}