38 votes

C # 'est' une vérification de type sur struct - odd. Comportement d'optimisation .NET 4.0 x86

Mise à jour: j'ai déposé un rapport de bug avec Microsoft Connect, merci de voter pour elle!

Mise à jour 2: Microsoft ont marqué le rapport de bogue fixe

Posté par Microsoft sur le 18/08/2010 à 17:25

Ce bug sera corrigé dans une future version du moteur d'exécution. Je suis peur il est trop tôt pour dire si c' sera dans un service pack ou la prochaine version majeure.

Depuis la mise à jour VS2010 je suis certains un comportement très étrange avec le " est " mot-clé.

Le programme ci-dessous (test.cs) sorties Vrai lorsqu'il est compilé en mode debug (x86) et False lorsqu'il est compilé avec les optimisations sur (x86). La compilation de toutes les combinaisons en x 64 ou AnyCPU donne le résultat attendu, c'est Vrai.

Toutes les combinaisons de la compilation sous .NET 3.5 donner le résultat attendu, c'est Vrai.

Je suis en utilisant le fichier de commandes ci-dessous (runtest.chauve-souris) pour compiler et tester le code à l'aide de différentes combinaisons de compilateur .NET framework.

  • Quelqu'un d'autre a vu ce genre de problèmes .NET 4.0?
  • Tout le monde veut le voir le même comportement que moi sur leur ordinateur lors de l'exécution de runtests.chauve-souris?
  • #@$@#$??
  • Est-il un correctif pour cela?

test.cs

using System;

public class Program
{
    public static bool IsGuid(object item)
    {
        return item is Guid;
    } 

    public static void Main()
    {
        Console.Write(IsGuid(Guid.NewGuid()));
    }
}

runtest.chauve-souris

@echo off

rem Usage:
rem   runtest         -- runs with csc.exe x86 .NET 4.0
rem   runtest 64      -- runs with csc.exe x64 .NET 4.0
rem   runtest v3.5    -- runs with csc.exe x86 .NET 3.5
rem   runtest v3.5 64 -- runs with csc.exe x64 .NET 3.5

set version=v4.0.30319
set platform=Framework

for %%a in (%*) do (
  if "%%a" == "64" (set platform=Framework64)
  if "%%a" == "v3.5" (set version=v3.5)
)

echo Compiler: %platform%\%version%\csc.exe
set csc="C:\Windows\Microsoft.NET\%platform%\%version%\csc.exe"

set make=%csc% /nologo /nowarn:1607 test.cs
rem CS1607: Referenced assembly targets a different processor
rem This happens if you compile for x64 using csc32, or x86 using csc64

%make% /platform:x86
test.exe
echo  =^> x86

%make% /platform:x86 /optimize
test.exe
echo  =^> x86 (Optimized)

%make% /platform:x86 /debug
test.exe
echo  =^> x86 (Debug)

%make% /platform:x86 /debug /optimize
test.exe
echo  =^> x86 (Debug + Optimized)

%make% /platform:x64
test.exe
echo  =^> x64

%make% /platform:x64 /optimize
test.exe
echo  =^> x64 (Optimized)

%make% /platform:x64 /debug
test.exe
echo  =^> x64 (Debug)

%make% /platform:x64 /debug /optimize
test.exe
echo  =^> x64 (Debug + Optimized)

%make% /platform:AnyCPU
test.exe
echo  =^> AnyCPU

%make% /platform:AnyCPU /optimize
test.exe
echo  =^> AnyCPU (Optimized)

%make% /platform:AnyCPU /debug
test.exe
echo  =^> AnyCPU (Debug)

%make% /platform:AnyCPU /debug /optimize
test.exe
echo  =^> AnyCPU (Debug + Optimized)

Des Résultats De Test

Lors de l'exécution de la runtest.chauve-souris-je obtenir les résultats suivants sur mon Win7 x64 installer.

> runtest 32 v4.0
Compiler: Framework\v4.0.30319\csc.exe
False => x86
False => x86 (Optimized)
True => x86 (Debug)
False => x86 (Debug + Optimized)
True => x64
True => x64 (Optimized)
True => x64 (Debug)
True => x64 (Debug + Optimized)
True => AnyCPU
True => AnyCPU (Optimized)
True => AnyCPU (Debug)
True => AnyCPU (Debug + Optimized)

> runtest 64 v4.0
Compiler: Framework64\v4.0.30319\csc.exe
False => x86
False => x86 (Optimized)
True => x86 (Debug)
False => x86 (Debug + Optimized)
True => x64
True => x64 (Optimized)
True => x64 (Debug)
True => x64 (Debug + Optimized)
True => AnyCPU
True => AnyCPU (Optimized)
True => AnyCPU (Debug)
True => AnyCPU (Debug + Optimized)

> runtest 32 v3.5
Compiler: Framework\v3.5\csc.exe
True => x86
True => x86 (Optimized)
True => x86 (Debug)
True => x86 (Debug + Optimized)
True => x64
True => x64 (Optimized)
True => x64 (Debug)
True => x64 (Debug + Optimized)
True => AnyCPU
True => AnyCPU (Optimized)
True => AnyCPU (Debug)
True => AnyCPU (Debug + Optimized)

> runtest 64 v3.5
Compiler: Framework64\v3.5\csc.exe
True => x86
True => x86 (Optimized)
True => x86 (Debug)
True => x86 (Debug + Optimized)
True => x64
True => x64 (Optimized)
True => x64 (Debug)
True => x64 (Debug + Optimized)
True => AnyCPU
True => AnyCPU (Optimized)
True => AnyCPU (Debug)
True => AnyCPU (Debug + Optimized)

tl;dr

9voto

Hans Passant Points 475940

J'ai travaillé un exemple similaire qui échoue de la même façon:

using System;
using System.Runtime.CompilerServices;

public class Program {
  static void Main() {
    Console.Write(Verify(Test.Create()));
    Console.ReadLine();
  }
  //[MethodImpl(MethodImplOptions.NoInlining)]
  static bool Verify(IDisposable item) {
    return item is Test;
  }
  struct Test : IDisposable {
    public void Dispose() { }
    public static Test Create() { return new Test(); }
  }
}

C'est un JIT, l'optimiseur de bug. N'arrive pas à mettre le doigt dessus, il optimise le code lourdement. Mais il me semble qu'il est en difficulté lorsqu'il optimise la boxe conversion. Joli bug grave, franchement.


Ce bogue a été corrigé, je n'ai plus de repro il. Ma version actuelle de clrjit.dll est 4.0.30319.237 datée du 17 Mai 2011. Je ne peux pas dire exactement ce que la mise à jour est réparé. J'ai eu une mise à jour de sécurité sur Août 5th 2011 mis à jour clrjit.dll la révision 235 avec une date de Avr 12, que le plus tôt serait.

6voto

João Angelo Points 24422

Pour répondre à votre dernière question, vous pouvez ajouter l' MethodImpl d'attribut avec l'option MethodImplOptions.NoInlining votre IsGuid méthode comme une solution de contournement pour résoudre le problème.

Je viens de faire un simple test de la commutation entre Debug et Release de configuration pour x86 sur le .NET 4.0 et cela semble résoudre le problème. Je n'ai pas encore fait votre runtests.bat bien.

Vous devez également soumettre une question à vous Connecter si l'on n'est pas encore soumise et lien à partir de votre question.

4voto

Mark Synowiec Points 3069

C'est pas cool. Je pense que vous devriez déposer un bogue. (connect.microsoft.com)

En outre, cela semble fonctionner (je n'ai testé que pour votre cas d'échec cependant):

     public static bool IsGuid(object item)
    {
        return item.GetType() == typeof(Guid);
    }
 

3voto

Daniel Renshaw Points 12272

D'autres que quelques-uns des opr, réflecteur indictes les seules différences sont dans la IsGuid méthode:

DEBUG:

.method public hidebysig static bool IsGuid(object item) cil managed
{
    .maxstack 2
    .locals init (
        [0] bool CS$1$0000)
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: isinst [mscorlib]System.Guid
    L_0007: ldnull 
    L_0008: cgt.un 
    L_000a: stloc.0 
    L_000b: br.s L_000d
    L_000d: ldloc.0 
    L_000e: ret 
}

LIBÉRATION:

.method public hidebysig static bool IsGuid(object item) cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: isinst [mscorlib]System.Guid
    L_0006: ldnull 
    L_0007: cgt.un 
    L_0009: ret 
}

Je ne suis pas couramment suffisant pour expliquer ces différences, mais c'est un wiki de la communauté de réponse, peut-être quelqu'un peut nous éclairer?

La modification de la méthode pour le rendre générique fonctionne autour de cette (possible bug?)

public static bool IsGuid<T>(T item)
{
    return item is Guid;
}

Comme la forçant dans un local varible (mais il doit être utilisé dans la méthode pour éviter les optimisations de coups de pied):

public static bool IsGuid(object item)
{
    bool a = item is Guid;
    a.ToString();
    return a;
}

2voto

Stephen Cleary Points 91731

Voici mes résultats sur XP SP3 (x86):

 >runtest
Compiler: Framework\v4.0.30319\csc.exe
False => x86
False => x86 (Optimized)
True => x86 (Debug)
False => x86 (Debug + Optimized)
False => AnyCPU
False => AnyCPU (Optimized)
True => AnyCPU (Debug)
False => AnyCPU (Debug + Optimized)

>runtest v3.5
Compiler: Framework\v3.5\csc.exe
True => x86
True => x86 (Optimized)
True => x86 (Debug)
True => x86 (Debug + Optimized)
True => AnyCPU
True => AnyCPU (Optimized)
True => AnyCPU (Debug)
True => AnyCPU (Debug + Optimized)
 

Le point intéressant à propos de ce résultat est que la cible .NET 4 échoue sur AnyCPU (sous x86) mais fonctionne sur AnyCPU (sous x64).

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