2015-11-04 40 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 –