Visual C ++是否考虑未定义的有符号整数溢出?

时间:2014-06-29 05:25:25

标签: c++ visual-c++ c++11

最近得到了很多关注,在C和C ++中正式未定义有符号整数溢出。但是,给定的实现可以选择定义它;在C ++中,实现可以将std::numeric_limits<signed T>::is_modulo设置为true以指示已为该类型定义了有符号整数溢出,并且像无符号整数一样包装。

Visual C ++将std::numeric_limits<signed int>::is_modulo设置为true。这几乎不是一个可靠的指标,因为GCC多年来将其设置为真,并且未定义签名溢出。我从来没有遇到过一个案例,其中Visual C ++的优化器已经完成了任何事情,但是给签名整数提供了环绕行为 - 直到本周早些时候。

我发现了一个案例,如果精确INT_MAX的值传递给特定函数,优化器会发出x86-64汇编代码,这些代码行为不正确。我不知道它是否是一个错误,因为Visual C ++似乎没有说明是否认为已经定义了有符号整数溢出。所以我想知道,它应该在Visual C ++中定义吗?

编辑:我在阅读Visual C ++ 2013 Update 2中一个不在Update 1中的令人讨厌的错误时发现了这一点,如果启用了优化,则以下循环会生成错误的机器代码:

void func (int *b, int n)
{
  for (int i = 0; i < n; i++)
    b[i * (n + 1)] = 1;
}

更新2错误会导致重复行生成代码,就好像它是b[i] = 1;一样,这显然是错误的。它变成rep stosd

真正有趣的是之前的版本更新1中存在奇怪。它生成的代码无法正确处理n完全等于{{1}的情况}。具体来说,如果INT_MAXn,则乘法就像INT_MAX n而不是long long一样 - 换句话说,加法int }不会导致结果变为n + 1

这是Update 1中的汇编代码:

INT_MIN

问题是我不知道这是否是编译器错误 - 在GCC和Clang中,这不会是编译器错误,因为那些编译器认为有符号整数溢出/下溢是未定义的。这是否是Visual C ++中的错误取决于Visual C ++是否认为有符号整数溢出/下溢未定义。

除了这个之外我见过的其他每个案例都显示Visual C ++要考虑定义已签名的溢出/下溢,因此是个谜。

2 个答案:

答案 0 :(得分:1)

您的示例可能确实具有n == INT_MAX的未定义行为,但不仅仅是因为未定义的有符号整数溢出(它可能不在Microsoft编译器上)。相反,您可能正在调用未定义的越界指针算法。

答案 1 :(得分:1)

在2016年(VS2015 Update 3)中发现了一个有趣的花絮:

他们谈论了他们想要引入VS2015的新SSA优化器:

  

C ++团队博客-引入了新的高级Visual C ++代码优化器

     

... ... ...

     

从历史上看,Visual C ++并未没有 利用这一事实,   C和C ++标准考虑了符号溢出的结果   操作未定义。其他编译器对此非常激进   方面,这促使人们决定实施某些模式   利用未定义的整数溢出行为。我们实施了   我们认为是安全的,没有施加任何不必要的   生成的代码中存在安全风险。

因此,您已经拥有了它。我读为:“我们从不编程任何额外的位来使用此UB”,但是从VS2015 / Update3开始,我们将拥有一些。

我应该注意,即使在此之前,我也要格外警惕,因为对于64位代码和32位变量,如果编译器/优化器只是将32位带符号的int放入64位寄存器中,则无论如何。 (如"How not to code: Undefined behavior is closer than you think"中所示-不幸的是,从博客文章中尚不清楚他是使用VS2015还是更新3。)

因此,我对整个事件的看法是,即使过去的优化程序版本没有利用 special 的事实,MSVC始终将其视为UB。新的SAA优化器似乎可以肯定地做到这一点。 (测试–d2UndefIntOverflow–开关是否能正常工作会很有趣。)

相关问题