指针溢出检查¶
ID: cpp/pointer-overflow-check
Kind: problem
Security severity: 2.1
Severity: error
Precision: high
Tags:
- reliability
- security
- external/cwe/cwe-758
Query suites:
- cpp-code-scanning.qls
- cpp-security-extended.qls
- cpp-security-and-quality.qls
在检查整数溢出时,您通常会编写类似 p + i < p
的测试。如果 p
和 i
是无符号整数,此方法有效,因为加法中的任何溢出都会导致值简单地“环绕”。但是,当 p
是指针时,使用此模式存在问题,因为根据 C 和 C++ 标准,指针溢出具有未定义的行为。如果加法溢出并产生未定义的结果,则比较也会是未定义的;它可能会产生意外的结果,或者可能会被优化编译器完全删除。
建议¶
要检查索引 i
是否小于数组的长度,只需将这两个数字作为无符号整数进行比较:i < ARRAY_LENGTH
。如果数组的长度定义为两个指针 ptr
和 p_end
之间的差值,则编写 i < p_end - ptr
。如果 i
是有符号的,则将其强制转换为无符号,以防出现负数 i
。例如,编写 (size_t)i < p_end - ptr
。
示例¶
最常见的一种无效的指针溢出检查方法是检查数字 a
是否过大,首先检查将该数字添加到 ptr
是否超过分配的末尾,然后检查将其添加到 ptr
是否会创建一个指针,该指针过大以至于溢出并环绕。
bool not_in_range(T *ptr, T *ptr_end, size_t i) {
return ptr + i >= ptr_end || ptr + i < ptr; // BAD
}
在这两种检查中,操作的顺序都错误。首先,评估可能会导致未定义行为的表达式(ptr + i
),然后检查结果是否在范围内。但是,一旦在指针加法中发生了未定义的行为,就无法恢复:在可能的指针溢出之后执行范围检查已经太迟了。
虽然这不是本查询的主题,但表达式 ptr + i < ptr_end
也是一个无效的范围检查。在 C/C++ 中,创建指向分配末尾的最后一个位置之后的指针是未定义的行为。
下一个示例展示了如何以可移植的方式检查无符号数字是否超出 ptr
和 ptr_end
之间分配的范围。
bool not_in_range(T *ptr, T *ptr_end, size_t i) {
return i >= ptr_end - ptr; // GOOD
}