【问题标题】:VS2013 : compiler bug with float and /EHa + /fp:strict?VS2013:带有浮点数和 /EHa + /fp:strict 的编译器错误?
【发布时间】:2015-11-04 16:10:22
【问题描述】:

我们刚从 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;
}

我是在指责编译器快吗?

【问题讨论】:

  • 代码在我看来很好。我会选择编译器错误。继续删除位以最小化您的代码,并报告错误。您可能会从foo 和height 中删除字符串,并稍微简化IsEqual。
  • "" 绑定到 std::string&amp; 是未定义的行为,删除该位并确认错误仍然存​​在
  • @MooingDuck 问题依旧
  • 不,不要停止调用height和width,只删除一个。你可能只需要一个来复制。这会重现吗? ideone.com/qhum2q 尝试找出Minimal Verifiable Example。
  • 这个 bug 出现在 VS2013 而不是 VS2015。

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


【解决方案1】:

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

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

AND 指令错误,它将堆栈对齐到 8 而不是 16。不足以提供 SSE2 代码所需的对齐保证。此错误的最强候选者是 /EHa,它会阻止 IsEqual() 被优化掉。可能是因为优化器无法假设它可能不会通过抛出 SEH 异常而产生副作用。现在施加对齐要求。

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

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

代码优化器现在可以达到:

001E16B3  and         esp,0FFFFFFF0h 

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

__declspec(noinline)
bool IsEqual(Vector2D & a, Vector2D & b) {
    // etc..
}

优化器现在决定移除不必要的 IsEqual() 调用,从而移除对齐要求。呵呵。优化器错误有这样的行为怪癖。

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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2022-12-18
  • 2014-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-16
  • 1970-01-01
相关资源
最近更新 更多