CodeQL 文档

带符号溢出检查

ID: cpp/signed-overflow-check
Kind: problem
Security severity: 8.1
Severity: warning
Precision: high
Tags:
   - correctness
   - security
   - external/cwe/cwe-128
   - external/cwe/cwe-190
Query suites:
   - cpp-code-scanning.qls
   - cpp-security-extended.qls
   - cpp-security-and-quality.qls

点击查看 CodeQL 代码库中的查询

在检查整数溢出时,您可能经常编写 a + b < a 之类的测试。如果 ab 是无符号整数,则此方法有效,因为加法中的任何溢出都只会导致值“回绕”。但是,使用*带符号*整数是有问题的,因为根据 C 和 C++ 标准,带符号溢出的行为未定义。如果加法溢出并且结果未定义,则比较也将未定义;它可能会产生意外结果,或者可能会被优化编译器完全删除。

建议

解决此问题的方法可以分为以下两类之一

  1. 重写带符号表达式,使溢出不会发生,但带符号性保持不变。

  2. 将变量及其所有用途更改为无符号。以下情况都属于第一类。

  3. 给定 unsigned short n1, deltan1 + delta < n1,可以将其重写为 (unsigned short)(n1 + delta)&nbsp;<&nbsp;n1。请注意,由于 int 提升,n1 + delta 实际上不会溢出。

  4. 给定 unsigned short n1, deltan1 + delta < n1,也可以将其重写为 n1 > USHORT_MAX - delta。然后必须包含 limits.hclimits 头文件。

  5. 给定 int n1, deltan1 + delta < n1,可以将其重写为 n1 > INT_MAX - delta。必须确保 delta >= 0 并且已包含 limits.hclimits 头文件。

示例

在下面的例子中,尽管 delta 被声明为 unsigned short,但 C/C++ 类型提升规则要求将其类型提升为加法和比较中使用的较大类型,即 signed int。加法运算在有符号整数上执行,如果发生溢出,则可能具有未定义的行为。因此,整个(比较)表达式也可能具有未定义的结果。

bool foo(int n1, unsigned short delta) {
    return n1 + delta < n1; // BAD
}

以下示例建立在前面的示例之上。我们没有执行加法(可能会溢出),而是重新构建了解决方案,以便使用减法。由于 delta 被提升为 signed intINT_MAX 表示 signed int 可能的最大正值,因此表达式 INT_MAX - delta 永远不会小于零或大于 INT_MAX。因此,避免了任何溢出和下溢。

#include <limits.h>
bool foo(int n1, unsigned short delta) {
    return n1 > INT_MAX - delta; // GOOD
}

在下面的例子中,尽管 ndelta 都被声明为 unsigned short,但在加法运算之前,两者都被提升为 signed int。因为我们是从较窄的 short 类型开始的,所以保证加法不会溢出,因此是已定义的。但 n1 + delta 永远不会溢出意味着条件 n1 + delta < n1 永远不会成立,这可能不是程序员想要的。(另请参阅 cpp/bad-addition-overflow-check 查询)。

bool bar(unsigned short n1, unsigned short delta) {
    // NB: Comparison is always false
    return n1 + delta < n1; // GOOD (but misleading)
}

下一个示例提供了一个针对前一个示例的解决方案。尽管 n1 + delta 不会溢出,但将其转换为 unsigned short 会截断模 2^16 的加法结果,因此现在可以观察到 unsigned short“环绕”。此外,由于左侧现在是 unsigned short 类型,因此右侧不需要提升为 signed int

bool bar(unsigned short n1, unsigned short delta) {
    return (unsigned short)(n1 + delta) < n1; // GOOD
}

参考文献

  • ©GitHub 公司
  • 条款
  • 隐私