C26429 USE_NOTNULL

"Symbol is never tested for nullness, it can be marked as gsl::not_null."

C++ Core Guidelines: F.23: Use a not_null to indicate that "null" is not a valid value

It is a common practice to use asserts to enforce assumptions about validity of pointer values. The problem with asserts is that they do not expose assumptions through the interface (e.g. 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 as a marker of resources which should never have null value. The rule USE_NOTNULL helps to identify places that omit checks for nullness 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 nullness check (or enforcement of non-null value) would be justified. So, warning will be emitted only if pointers are dereferenced and never tested for nullness.
    • 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 nullness when it is used in the following contexts:
    • as a symbol expression in a branch condition, e.g. "if (p) { ... }";
    • non-bitwise logical operations;
    • comparison operations where one operand is a constant expression which evaluates to zero.
    • The rule doesn’t have full dataflow tracking and can produce incorrect results in cases where indirect checks are used (e.g. when intermediate variable holds null value and later used in comparison). ## 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();
        // ...
    }
}

Example

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();
        // ...
    }
}