警告 C26430
未在所有路径上测试符号是否为 null。
C++ Core Guidelines:F.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;
}
规则 C26822 和 C26823 适用于取消引用(可能)null 指针。
此规则不执行完整的数据流跟踪。 在使用间接检查(例如,中间变量保留 null 值,稍后在比较中使用)的情况下可能会产生不正确的结果。