2015-11-04 1 views
2

Nous venons de passer de VS2010 à VS2013 et j'ai trouvé un bug étrange et je me demande si c'est dû au compilateur.VS2013: bug du compilateur avec float et/EHa +/fp: strict?

Compilé avec la ligne de commande cl ConsoleApplication1.cpp /EHa /fp:strict /O2 le programme suivant donne: 0xC0000005: Access violation reading location 0xFFFFFFFF.

Cela se produit uniquement lors de la compilation 32 bits (non 64 bits)

#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; 
} 

Suis-je en train d'accuser le compilateur rapidement?

+1

Le code apparaît bien à mes yeux. J'irais avec un bug de compilateur. Continuez à supprimer les bits pour minimiser votre code et signaler le bug. Vous pouvez probabiliser la chaîne de 'foo', et' height', et simplifier légèrement 'IsEqual'. –

+1

'' "' 'lier à un' std :: string & 'comportement non défini, supprimer ce bit et confirmer que le bogue se produit encore –

+0

@MooingDuck le bogue se produit toujours – BenjaminB

Répondre

4

Ceci est un bogue de vectorisation automatique, il meurt sur une instruction UNPCKLPS qui accède à la variable Vector2D locale, il n'est pas aligné correctement. bug de base est dans le prologue de la fonction:

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

L'instruction AND est mauvaise, il aligne la pile à 8 au lieu de 16. Pas assez bon pour fournir la garantie d'alignement que le code exige SSE2. Le meilleur candidat pour ce bogue est/EHa, ce qui empêche IsEqual() d'être optimisé. Peut-être parce que l'optimiseur ne peut pas supposer qu'il pourrait ne pas avoir d'effet secondaire en lançant une exception SEH. Maintenant, imposant l'exigence d'alignement.

Vous pouvez frapper sur la tête en déclarant explicitement les variables à aligner:

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

Et l'optimiseur de code wisens maintenant à:

001E16B3 and   esp,0FFFFFFF0h 

loin la solution la plus étonnante est :

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

Et l'optimiseur décide maintenant de supprimer le I inutile appel sEqual(), supprimant ainsi l'exigence d'alignement. Hehe. Les bugs de l'optimiseur ont une forte habitude de se comporter comme ça. Ce bug ne se produit pas dans VS2015, il est difficile de dire s'il a vraiment été adressé car il génère un prologue très différent qui semble supposer que la fonction main() est déjà entrée avec une pile alignée. Vous pouvez déposer le bogue sur connect.microsoft.com si vous voulez l'entendre de la bouche du cheval.

+0

Merci beaucoup Hans pour l'analyse très détaillée en effet! FIY nous avons déposé un rapport de bogue chez microsoft ici: https://connect.microsoft.com/VisualStudio/feedback/details/1984067 –