例如,给出以下代码:
int f(int n)
{
if (n < 0)
return 0;
n = n + 100;
if (n < 0)
return 0;
return n;
}
假设您传入的数字非常接近整数溢出(小于100),编译器是否会生成会给您带来否定回报的代码?
以下是Simon Tatham的“The Descent to C”中关于这个问题的摘录:
“GNU C编译器(gcc)为此函数生成代码,如果传入(例如)最大表示能够'int'的值,则可返回负整数。因为编译器在第一个if语句之后知道n是正数,然后它假设不发生整数溢出,并使用该假设得出结论,在加法后n的值必须仍为正数,因此它完全删除第二个if语句并返回未选中的加法结果。 “
让我想知道C ++编译器中是否存在同样的问题,如果我不小心我的整数溢出检查不会被跳过。
答案 0 :(得分:8)
简答
编译器是否肯定会优化您的示例中的检查,我们不能对所有情况说明,但我们可以使用godbolt interactive compiler使用以下代码对gcc 4.9
进行测试( see it live 的):
int f(int n)
{
if (n < 0) return 0;
n = n + 100;
if (n < 0) return 0;
return n;
}
int f2(int n)
{
if (n < 0) return 0;
n = n + 100;
return n;
}
我们看到它为两个版本生成了相同的代码,这意味着它确实在第二次检查时丢失了:
f(int):
leal 100(%rdi), %eax #, tmp88
testl %edi, %edi # n
movl $0, %edx #, tmp89
cmovs %edx, %eax # tmp88,, tmp89, D.2246
ret
f2(int):
leal 100(%rdi), %eax #, tmp88
testl %edi, %edi # n
movl $0, %edx #, tmp89
cmovs %edx, %eax # tmp88,, tmp89, D.2249
ret
长答案
当您的代码展示undefined behavior或依赖于潜在的未定义行为(此示例中的有符号整数溢出)然后是,编译器可以进行假设并围绕它们进行优化。例如,它可以假设没有未定义的行为,因此根据该假设进行优化。最臭名昭着的例子可能是removal of a null check in the Linux kernel。代码如下:
struct foo *s = ...;
int x = s->f;
if (!s) return ERROR;
... use s ..
使用的逻辑是,由于s
被解除引用,因此它不能是空指针,否则将是未定义的行为,因此它优化了if (!s)
检查。相关文章说:
问题是第2行中s的取消引用允许编译器 推断s不为null(如果指针为null则为函数 未定义;编译器可以简单地忽略这种情况)。就这样 第3行中的null check得到了静默优化,现在是内核 如果攻击者可以找到一种方法来调用,则包含可利用的漏洞 这段代码带有空指针。
这同样适用于C和C ++,它们都具有围绕未定义行为的类似语言。在这两种情况下,标准都告诉我们未定义行为的结果是不可预测的,尽管两种语言中具体未定义的结果可能不同。 draft C++ standard定义了未定义的行为,如下所示:
本国际标准没有要求的行为
并包含以下注释(强调我的):
本国际标准可能会出现未定义的行为 省略任何明确的行为定义或程序使用时 错误的构造或错误的数据。 允许的未定义行为 范围从完全忽略情况与不可预测 结果,在翻译或程序执行期间表现 记录的环境特征(有或没有 发布诊断消息),终止翻译或 执行(发出诊断消息)。很多错误 程序结构不会产生未定义的行为;他们是 需要被诊断出来。
C11标准草案有类似的语言。
正确的签名溢出检查
您的检查不是防止有符号整数溢出的正确方法,您需要在执行操作之前进行检查,如果导致溢出则不执行操作。 Cert有一个good reference关于如何防止各种操作的有符号整数溢出。对于添加案例,它建议如下:
#include <limits.h>
void f(signed int si_a, signed int si_b) {
signed int sum;
if (((si_b > 0) && (si_a > (INT_MAX - si_b))) ||
((si_b < 0) && (si_a < (INT_MIN - si_b)))) {
/* Handle error */
} else {
sum = si_a + si_b;
}
如果我们将这个代码插入到godbolt中,我们可以看到检查被省略了,这是我们期望的行为。