警告 C26430

未在所有路径上测试符号是否为 null。

C++ Core GuidelinesF.23:使用 not_null<T> 指示“null”不是有效值

如果代码曾经检查指针变量是否为 null,则它应该一致地执行此操作并验证所有路径上的指针。 有时,对是否为 null 进行过度积极的检查要好过某个复杂分支发生硬崩溃。 理想情况下,此类代码应重构为不太复杂(通过将其拆分为多个函数),并依赖于像 gsl::not_null 这样的标记。 这些标记允许代码隔离算法的各个部分,这些算法可以对有效指针值进行安全假设。 规则 TEST_ON_ALL_PATHS 有助于查找 null 检查不一致的位置(这意味着可能需要审查假设)。 或者,它会查找实际 bug,其中潜在的 null 值可以绕过某些代码路径中的 null 检查。

注解

该规则期望代码取消引用指针变量,该规则期望代码取消引用指针变量,以便证明 null 检查(或强制执行非 null 值)是合理的。 如果没有取消引用,则规则将暂停。

当前实现仅处理普通指针(或其别名),并且不检测智能指针,即使 null 检查同样适用于智能指针。

在以下上下文中使用变量时,该变量被标记为已进行 null 检查:

  • 作为分支条件中的符号表达式,例如在 if (p) { ... } 中;
  • 在非按位逻辑操作中;
  • 在比较运算(其中一个操作数是计算结果为零的常量表达式)中。

从以下项分配指针值时,假定隐式 null 检查:

  • 通过引发 operator new 执行的分配;
  • 从标有 gsl::not_null 的类型获得的指针。

示例

不一致的测试表明了逻辑错误

void merge_states(const state *left, const state *right) // C26430
{
    if (*left && *right)
        converge(left, right);
    else
    {
        // ...
        if (!left && !right)                            // Logic error!
            discard(left, right);
    }
}

不一致的测试揭示了逻辑错误 - 已更正

void merge_states(gsl::not_null<const state *> left, gsl::not_null<const state *> right)
{
    if (*left && *right)
        converge(left, right);
    else
    {
        // ...
        if (*left && *right)
            discard(left, right);
    }
}

启发

确保指针的取消引用不为 null 时,此规则不需要每个取消引用都具有之前的 null 检查。 相反,在首次取消引用指针之前,它需要 null 检查。 以下函数不触发 C26430:

void f(int* p)
{
    if (p)
        *p = 1;
    *p = 2;
}

以下函数会生成 C26430,因为存在一条没有 null 检查且可分配 *p 的路径:

void f(bool b, int* p)
{
    if (b && p)
        *p = 1;
    *p = 2;
}

规则 C26822C26823 适用于取消引用(可能)null 指针。

此规则不执行完整的数据流跟踪。 在使用间接检查(例如,中间变量保留 null 值,稍后在比较中使用)的情况下可能会产生不正确的结果。

另请参阅

C26822
C26823