带符号溢出检查¶
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
在检查整数溢出时,您可能经常编写 a + b < a
之类的测试。如果 a
或 b
是无符号整数,则此方法有效,因为加法中的任何溢出都只会导致值“回绕”。但是,使用*带符号*整数是有问题的,因为根据 C 和 C++ 标准,带符号溢出的行为未定义。如果加法溢出并且结果未定义,则比较也将未定义;它可能会产生意外结果,或者可能会被优化编译器完全删除。
建议¶
解决此问题的方法可以分为以下两类之一
重写带符号表达式,使溢出不会发生,但带符号性保持不变。
将变量及其所有用途更改为无符号。以下情况都属于第一类。
给定
unsigned short n1, delta
和n1 + delta < n1
,可以将其重写为(unsigned short)(n1 + delta) < n1
。请注意,由于int
提升,n1 + delta
实际上不会溢出。给定
unsigned short n1, delta
和n1 + delta < n1
,也可以将其重写为n1 > USHORT_MAX - delta
。然后必须包含limits.h
或climits
头文件。给定
int n1, delta
和n1 + delta < n1
,可以将其重写为n1 > INT_MAX - delta
。必须确保delta >= 0
并且已包含limits.h
或climits
头文件。
示例¶
在下面的例子中,尽管 delta
被声明为 unsigned short
,但 C/C++ 类型提升规则要求将其类型提升为加法和比较中使用的较大类型,即 signed int
。加法运算在有符号整数上执行,如果发生溢出,则可能具有未定义的行为。因此,整个(比较)表达式也可能具有未定义的结果。
bool foo(int n1, unsigned short delta) {
return n1 + delta < n1; // BAD
}
以下示例建立在前面的示例之上。我们没有执行加法(可能会溢出),而是重新构建了解决方案,以便使用减法。由于 delta
被提升为 signed int
且 INT_MAX
表示 signed int
可能的最大正值,因此表达式 INT_MAX - delta
永远不会小于零或大于 INT_MAX
。因此,避免了任何溢出和下溢。
#include <limits.h>
bool foo(int n1, unsigned short delta) {
return n1 > INT_MAX - delta; // GOOD
}
在下面的例子中,尽管 n
和 delta
都被声明为 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
}
参考文献¶
W. Dietz, P. Li, J. Regehr, V. Adve. 理解 C/C++ 中的整数溢出
常见弱点枚举: CWE-128。
常见弱点枚举: CWE-190。