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