VS2013:浮点数和/ EHa + / fp:strict的编译器错误?

时间:2015-11-04 16:10:22

标签: c++ visual-studio floating-point compiler-bug msvc12

我们刚刚从VS2010迁移到VS2013,我发现了一个奇怪的错误,我想知道这可能是由于编译器造成的。

使用命令行cl ConsoleApplication1.cpp /EHa /fp:strict /O2编译,以下程序给出: 0xC0000005: Access violation reading location 0xFFFFFFFF.

仅在编译为32位(非64位)

时才会发生这种情况
#include <iostream>
#include <cmath>


class Vector2D
{
public:
  double x;
  double y;

  Vector2D() : x(0), y(0) {}
  Vector2D(double _x, double _y) : x(_x), y(_y) {}

  double Width() { return x; }
  double Height() { return y; }

};


bool IsEqual(const double & a, const double & b)
{
  if (a == b)
    return true;

  double tolerance = pow(10., -5);
  if (::fabs(a) < tolerance / 2.)
  {
    return ::fabs(b) < tolerance / 2.;
  }
  double diff = ::fabs((b - a) / a);
  return (diff < tolerance);
}

bool IsEqual(Vector2D & a, Vector2D & b)
{
  return IsEqual(a.Width(), b.Width()) && IsEqual(a.Height(), b.Height());
}

std::string GetMsg()
{
  return std::string("");
}

int main(int argc, char* argv[])
{
  Vector2D v1;
  Vector2D v2;

  v1 = Vector2D(1, 0);
  // This innocent call will cause an access violation
  // the access violation occurs *only* if fp:strict and /EHa switches are used
  GetMsg(), IsEqual(v1, v2);

  return 0;
}

我是否快速指责编译器?

1 个答案:

答案 0 :(得分:4)

这是一个自动矢量化错误,它死于访问本地Vector2D变量的UNPCKLPS指令,它没有正确对齐。基本错误在函数的序言中:

t

AND指令错误,它将堆栈对齐为8而不是16.不足以提供SSE2代码所需的对齐保证。这个bug最强大的候选者是/ EHa,它可以防止IsEqual()被优化掉。也许是因为优化器不能通过抛出SEH异常来假设它可能没有副作用。现在强制对齐要求。

你可以通过明确声明要对齐的变量来解决问题:

int main(int argc, char* argv[]) {
013A16B0  push        ebp  
013A16B1  mov         ebp,esp  
013A16B3  and         esp,0FFFFFFF8h  

代码优化器现在最终可以实现:

__declspec(align(16)) Vector2D v1;
__declspec(align(16)) Vector2D v2;

到目前为止,最令人惊叹的解决方法是:

001E16B3  and         esp,0FFFFFFF0h 

优化器现在决定删除不必要的IsEqual()调用,从而消除了对齐要求。呵呵。优化器错误有一种强烈的习惯,就像这样表现得很糟糕。

这个错误在VS2015中不会发生,无论它是否真正被解决都很难说,因为它生成了一个非常不同的序言,似乎假设main()函数已经输入了对齐的堆栈。如果你想从马的嘴里听到它,可以在connect.microsoft.com上提交bug。