35 votes

Visual Studio 2015 Update 3 - Bogue du compilateur C ++?

Nous observons un étrange cas où, dans VS2015 Update3 compilateur va omettre la partie du code pour aucune raison évidente.

Nous avons constaté que

  • Ce qui se passe dans VS2015 Update3 (Aide|a Propos dit 14.0.25431.01 mise à Jour 3, cl.exe version 19.00.24215.1)
  • Cela ne se produit pas dans VS2015 Update2 (Aide|a Propos dit 14.0.25123.00 mise à Jour 2, cl.exe version 19.00.23918)
  • Cela se produit uniquement lorsque l'optimisation est activée (par exemple, dans la Version par défaut de la configuration)
  • Qui se passe dans les versions x86 et x64
  • Se produit lorsque l'extrait de code est inséré dans nouvelle marque "Win32 Console Application" (je veux dire, pas de fantaisie, options de ligne de commande requis)

Nous avons réussi à réduire le coupable code de cet extrait:

#include <stdio.h>
#include <tchar.h>
#include <stdlib.h>

int _tmain(int, _TCHAR*[])
{
    volatile int someVar = 1;

    const int indexOffset = someVar ? 0 : 1;    // Loop omitted
    // const int indexOffset = !someVar;        // Loop omitted
    // const int indexOffset = 0;               // Good
    // const int indexOffset = 1;               // Good
    // const int indexOffset = someVar;         // Good
    // const int indexOffset = someVar + 1;     // Good

    for (int i = 1 - indexOffset; i < 2 - indexOffset; ++i)
    {
        printf("Test passed\n");
    }

    return 0;
}

Pour les lignes qui disent "Boucle omis", l'ensemble du corps de boucle est omis par le compilateur. Pourquoi? À ma connaissance, il n'existe pas de comportement indéfini impliqués.


Le démontage de la première Boucle "omis":

int _tmain(int, _TCHAR*[])
{
01151010  push        ebp  
01151011  mov         ebp,esp  
01151013  push        ecx  
    volatile int someVar = 1;
01151014  mov         dword ptr [ebp-4],1  

    const int indexOffset = someVar ? 0 : 1;    // Loop omitted
0115101B  mov         eax,dword ptr [someVar]  
    // const int indexOffset = !someVar;        // Loop omitted
    // const int indexOffset = 0;               // Good
    // const int indexOffset = 1;               // Good
    // const int indexOffset = someVar;         // Good
    // const int indexOffset = someVar + 1;     // Good

    for (int i = 1 - indexOffset; i < 2 - indexOffset; ++i)
    {
        printf("Test passed\n");
    }

    system("pause");
0115101E  push        offset string "pause" (011520F8h)  
01151023  call        dword ptr [__imp__system (0115205Ch)]  
01151029  add         esp,4  
    return 0;
0115102C  xor         eax,eax  
}
0115102E  mov         esp,ebp  
01151030  pop         ebp  
01151031  ret

Projet de Test: http://dropmefiles.com/S7mwT


Essayer en ligne!

  • Aller à http://webcompiler.cloudapp.net/
  • Mettre un exemple de code de l'éditeur
  • Mettre /O2 de Additional compiler flags
  • Vérifiez Run executable after compilation

Rapport de Bug: https://developercommunity.visualstudio.com/content/problem/71906/compiler-optimization-code-generation-bug.html

24voto

Casey Points 18217

Oui, c'est un bug. Plus précisément, c'est un bug dans la nouvelle SSA optimiseur introduit dans VS2015 mise à Jour 3. Les sans-papiers option de ligne de commande -d2SSAOptimizer- indique au compilateur backend à utiliser l'ancien optimiseur au lieu de cela, ce qui provoque le bug de ne pas manifester.

Pour info, vous pouvez réduire votre repro à:

int main()
{
    volatile int someVar = 1;

    const int indexOffset = someVar ? 0 : 1;

    for (int i = 1 - indexOffset; i < 2 - indexOffset; ++i)
    {
        return 0;
    }
    return 1;
}

qui va aider le compilateur développeurs de localiser le problème plus rapidement.


Plus de Codeguard (j'ai décidé que Casey's réponse devrait être LA réponse): J'ai reçu la réponse de Microsoft (Gratien Lup, auteur de blog Introduisant une nouvelle avancée de code Visual C++ optimizer):

Oui, c'est effectivement un bug dans le SSA Optimiseur de lui-même - l'habitude de la plupart bugs signalés comme étant dans la nouvelle optimizer sont dans d'autres parties, parfois, exposée aujourd'hui au bout de 20 ans.

C'est dans un petit opt. qui essaie de supprimer une comparaison à la recherche comme (une - Const1) CMP (a - Const2), si il n'y a pas de débordement. Le problème, c'est que votre code a (1 - indexOffset) CMP (2 - indexOffset) et de la soustraction. n'est pas commutative, bien sûr - mais l'optimiseur de code ne tient pas compte que et les poignées (1 - indexOffset) comme si c'est (indexOffset - 1).

Un correctif pour ce problème sera publié dans la prochaine grande mise à jour pour VS2017. Jusqu'alors, la désactivation de la SSA Optimiseur serait un décent solution de contournement. La désactivation des optimisations pour seulement cette fonction peut être une une meilleure approche si il ne ralentit pas trop de choses. Cela peut être fait avec #pragma optimiser("", off): https://msdn.microsoft.com/en-us/library/chh3fb0k.aspx

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X