2015-11-04 21 views
2

我们刚刚从VS2010移到VS2013,我发现了一个奇怪的错误,我不知道它可能是由于编译器。VS2013:float和/ EHa +/fp的编译器bug:strict?

编译的命令行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

代码在我眼中显得很好。我会去编译器的bug。保持删除位以最小化代码,并报告错误。你可以从'foo'和'height'中使用字符串,并简化'IsEqual'。 –

+1

'''''绑定到'std :: string&'是未定义的行为,删除那个位并确认错误仍然发生 –

+0

@MooingDuck错误仍然存​​在 – BenjaminB

回答

4

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

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

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

您可以通过显式声明的变量要对齐重击它的脑袋:

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

和代码优化现在wisens达:

001E16B3 and   esp,0FFFFFFF0h 

迄今为止,最令人惊叹的解决方法是:

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

而优化器现在决定删除不必要的I sEqual()调用,从而消除了对齐要求。呵呵。优化器错误有这样的行为的强烈习惯。

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

+0

非常感谢您汉斯确实是非常详细的分析! FIY我们在这里提起微软的一个bug报告:https://connect.microsoft.com/VisualStudio/feedback/details/1984067 –