Si l’instruction semble être en cours d’évaluation même lorsque la condition est évaluée à false

Tard au travail hier soir, nous essayions de comprendre pourquoi quelque chose échouait. Une vérification de validation échouait alors qu’elle n’aurait pas dû l’être.

Nous avons fini par append une instruction print à ce code (désassemblé de Reflector afin de vérifier que le code était bien ce que nous avions écrit):

public static ssortingng Redacted(ssortingng name, DateTime lastModified) { long ticks = lastModified.Ticks; if ((ticks != (ticks - (ticks % 10000L))) && (lastModified != DateTime.MaxValue)) { Log.Debug(ssortingng.Format("Last Modified Date = '{0}'. Ticks = '{1}'. TicksCalc = '{2}'", lastModified.ToSsortingng("dd/MM/yyyy hh:mm:ss.fff"), ticks, ticks - (ticks % 10000L))); 

Il a imprimé (reformaté):

 Last Modified Date = '22/03/2011 12:16:22.000'. Ticks = '634363497820000000'. TicksCalc = '634363497820000000' 

Mais la condition est que ” ticks ” (ce qui correspond aux ticks imprimés ci-dessus) ne soit pas égal à ” (ticks - (ticks % 10000)) ” (ce qui correspond à TicksCalc)! 634363497820000000! = 634363497820000000 ?!

Afin de déterminer ce qui se passe ici, nous avons ajouté deux autres déclarations:

 long ticks = lastModified.Ticks; /* Added following two lines: */ long num2 = ticks - (ticks % 10000L); Log.Debug((ticks == num2).ToSsortingng()); /* */ if ((ticks != (ticks - (ticks % 10000L))) && (lastModified != DateTime.MaxValue)) { Log.Debug(ssortingng.Format("Last Modified Date = '{0}'. Ticks = '{1}'. TicksCalc = '{2}'", lastModified.ToSsortingng("dd/MM/yyyy hh:mm:ss.fff"), ticks, ticks - (ticks % 10000L))); 

Comme il se doit, celui-ci est imprimé true (lors du test avec la même valeur) et n’écrit pas la deuxième ligne.

Se sentant un peu perdus, nous avons à nouveau retiré les deux lignes, recompilé et rediffusé. Le comportement d’origine s’est répété.

Ce matin, j’ai enregistré une vidéo .

La vidéo montre tout d’abord qu’il faut bash un sharepoint rupture dans la méthode à l’aide du code «cassé», puis le reconstruire et le réexécuter à l’aide du code «de travail». Notez que même si le débogueur affiche que la condition if évaluée à false , le corps est toujours entré.

J’ai déjà vu des choses comme celle-ci se produire quand elles étaient observées par le débogueur, car le débogueur forçait certaines choses à être évaluées, mais cela se produit que le débogueur soit utilisé ou non.

De plus, cela ne se produit qu’en mode Release (c’est-à-dire avec l’optimisation JIT activée).

Voici les méthodes désassemblées pour les deux versions: travail , pas travail . Je ne sais pas vraiment lire assemblé, alors je les publie ici dans l’espoir d’être élucidées.

J’espère que la réponse n’est pas une chose évidente que j’ai complètement oubliée …!

Edit: Voici le IL. Je ne pense pas qu’il y a quelque chose qui cloche avec cela car il décomstack le C # correct:

  • Ne fonctionne pas
  • Travail

Mise à jour :

Confirmé comme un bogue par Microsoft, à corriger dans la prochaine version .

J’ai un peu expérimenté le code simplifié: http://nopaste.info/2c99a0e028_nl.html

La variation la plus intéressante est:

 static readonly long variableZero=0; const long constZero=0; public static void Broken2( long ticks2) { long ticks = ticks2+variableZero; if (ticks != (ticks - (ticks % 10000L))) { ssortingng.Format("Last Modified Date = '{0}'. Ticks = '{1}'. TicksCalc = '{2}'", "n/A", ticks, ticks - (ticks % 10000L)).Dump(); } } 

Si je remplace variableZero par constantZero cela fonctionne.


Je suis donc à peu près sûr que c’est un problème de gigue ou de compilateur.

J’ai déposé un rapport de bug sur MS Connect: https://connect.microsoft.com/VisualStudio/feedback/details/671105/jitter-or-c-comstackr-bug#details


Mise à jour : le comportement étrange ne se produit que si aucun débogueur n’est attaché. c’est-à-dire lorsque l’optimisation Jit est activée. Je suis donc à peu près sûr que c’est un virus de gigue.

Et pour les personnes sans linq-pad, il existe maintenant un projet de console C # simple: http://nopaste.info/00a0e37328_nl.html

Découvrez ce fil.

Si déclaration étrange dans Visual Studio 2008

Cela revient à ceci, vous ne pouvez pas faire confiance au débogueur tout le temps.

Pour “réparer” cette instruction if, ajoutez-y une instruction else {} vide. Le débogueur fonctionnera comme prévu.

Cela ressemble en effet à un – ahem – jitterbug. Pouvez-vous définir un sharepoint rupture sur la déclaration “if” et nous montrer une capture d’écran de la vue de désassemblage après avoir été détectée?

J’ai eu quelque chose de similaire il y a un moment. Dans mon cas, cela avait à voir avec le fait que je comparais 2 valeurs entières, une valeur étant en réalité une référence à un entier en boîte et l’autre une valeur primitive réelle.

Le fait est que si vous imprimez la valeur du nombre entier encadré et de la primitive, elles se ressemblent, mais les comparer est une autre chose. Vous obtiendrez une comparaison de référence au lieu d’une comparaison de valeur.

La réponse est facile:

 long ticks = lastModified.Ticks; long num2 = ticks - (ticks % 10000L); if ((ticks != num2) && (lastModified != DateTime.MaxValue)) { do your thing here! } 

C’est fou. Avez-vous essayé, sans raison valable, de réorganiser la déclaration if?

 if (lastModified != DateTime.MaxValue && ticks != (ticks - (ticks % 10000L)) 

De plus, si cela ne fonctionne pas (comme cela ne devrait pas être le cas, considérant que cela ne devrait pas être un problème au départ), pouvez-vous afficher le code IL actuel du code sous la forme problématique?

Une autre chose, la vérification des ticks ne pourrait-elle pas être simplifiée comme suit:

 (ticks % 10000L) != 0