2010-01-25 17 views
44

Kodda, yalnızca en iyileştirmeler etkinleştirilmiş olarak oluşturulduğunda oluşturulan bir hatayla karşılaştım. Test için mantığı kopyalayan bir konsol uygulaması yaptım (aşağıdaki kod). Sen optimizasyon etkin olduğunda 'değer' Bu geçersiz mantık yürütme sonrasında boş olur görürsünüz:Yalnızca derleme optimizasyonu etkinleştirildiğinde hata oluşuyor

if ((value == null || value == new string[0]) == false) 

düzeltme oldukça basittir ve kusurlu kod aşağıda belirtilmiş olan. Ama ... Ben daha çok ben assembler bir hata ile karşılaşmış olabilir veya belki de başkasının değer null değerine ayarlanmış bir açıklama vardır endişe duyuyorum.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace memory_testing 
{ 
    class Program 
    { 
     sta tic void Main(string[] args) 
     { 
      while(true) 
      { 
       Console.Write("Press any key to start..."); 
       Console.ReadKey(); 
       Console.WriteLine(); 
       PrintManagerUser c = new PrintManagerUser(); 
       c.MyProperty = new string[1]; 
      } 
     } 
    } 

    public class PrintManager 
    { 
     public void Print(string key, object value) 
     { 
      Console.WriteLine("Key is: " + key); 
      Console.WriteLine("Value is: " + value); 
     } 
    } 

    public class PrintManagerUser 
    { 
     public string[] MyProperty 
     { 
      get { return new string[100]; } 
      set 
      { 
       Console.WriteLine("Pre-check Value is: " + value); 
       if ((value == null || value == new string[0]) == false) 
       { 
        Console.WriteLine("Post-check Value is: " + value); 
        new PrintManager().Print("blah", value); 
       } 
       //if (value != null && value.Length > 0) 
       //{ 
       // new PrintManager().Print("blah", value); 
       //} 
      } 
     } 
    } 
} 

normal çıkış olmalıdır:

Pre-check Value is: System.String[] 
Post-check Value is: System.String[] 
Key is: blah 
Value is: System.String[] 

arabası çıktısı:

Pre-check Value is: System.String[] 
Post-check Value is: 
Key is: blah 
Value is: 

My Env bir VM çalıştıran Windows Server 2003 R2 .NET 3.5 SP1 ile . VS2008 Takım Sistemini Kullanma.

sayesinde

Brian

+12

Açıkçası, optimize edici, '== false' kullanarak uygulamak yerine size kızgın! operatöre ifade. – iandisme

+0

Ooh, bu * ilginç *. Reflektöre giriyor ... –

+0

Haha bmancini

cevap

45

Evet, ifadeniz JIT iyileştiricisini hatalı bir şekilde karıştırıyor. oluşturulan makine kodu aşağıdaki gibidir:

   if ((value == null || value == new string[0]) == false) 
00000027 test  esi,esi    ; value == null? 
00000029 je   00000075 
0000002b xor   edx,edx    ; new string[0] 
0000002d mov   ecx,6D913BD2h 
00000032 call  FFD20BC8 
00000037 cmp   eax,esi    ; (value == new string[0]) == false? 
00000039 je   00000075 
       { 
        Console.WriteLine("Post-check Value is: " + value); 
0000003b mov   ecx,dword ptr ds:[03532090h] ; "Post-check value is: " 
00000041 xor   edx,edx    ; BUGBUG not null! 
00000043 call  6D70B7E8    ; String.Concat() 
00000048 mov   esi,eax    ; 
0000004a call  6D72BE08    ; get Console.Out 
0000004f mov   ecx,eax 
00000051 mov   edx,esi 
00000053 mov   eax,dword ptr [ecx] 
00000055 call  dword ptr [eax+000000D8h]  ; Console.WriteLine() 

hata adresi 41 meydana gelir, iyileştirici doğrudan() String.Concat bir boş geçer, böylece değeri her zaman boş olacaktır sonucuna varmıştır. yerine

    Console.WriteLine("Post-check Value is: " + value); 
00000056 mov   ecx,dword ptr ds:[03342090h] 
0000005c mov   edx,dword ptr [ebp-8] 
0000005f call  6D77B790 

kod taşındı, ama şimdi yerel değişken (değer) kullanır 5c adresinde unutmayın yapın:

Karşılaştırma için

, bu JIT optimizasyon kapatıldığında Oluşturulan koddur boş.

Bu hatayı connect.microsoft.com adresinden bildirebilirsiniz. geçici çözüm basit:

if (value != null) 
    { 
    Console.WriteLine("Post-check Value is: " + value); 
    new PrintManager().Print("blah", value); 
    } 
+2

Neler olup bittiğine dair büyük bir açıklama için teşekkürler. – bmancini

+6

Bu, Şimdiye kadar gördüğüm en etkileyici cevaptır ... Ya da belki sadece kolayca etkilendim ... – Ben

+0

"if (! String.IsNullOrEmpty (value))" yerine OP yerine Boş bir dizgeyle de karşılaştırılıyor. –

1

Ben x64 çıkıyorum ve ilk başta sorunu yeniden olamazdı. Sonra hedefi x86 olarak belirledim ve bana oldu. X64'e geri döndü ve gitti. Bunun tam olarak ne anlama geldiğinden emin değilim, ama şimdi birkaç kez geri gittim.

+0

Ben de x64 yaşıyorum ve bunu optimizasyon = true ve target = x86 ile yeniden üretemiyorum. – nos

2
value == new string[0] 

Yukarıdakiler bana garip bir açıklama gibi görünüyor. İki dizi diziyi eşittir ifadesiyle karşılaştırıyorsunuz. Bu, her ikisi de aynı diziye işaret ediyorlarsa doğru olur, ki bu oldukça olası değildir. Bu, bu kodun neden optimize edilmiş bir sürümde farklı davrandığını açıklamıyor.

+0

Bunun için bir operatör aşırı yükü enjekte etmenin herhangi bir yolunu düşünün, ama bu kesinlikle% 100 gerçek harika mıdır? Bu arada, düşündüğüm şey, yani +1 –

0

Kesinlikle bir hata gibi görünen, böyle operatör işlenen takas zaman yeniden geliyor?

if (false == (null == value || new string[0] == value)) 
3

Bu hata, .NET 4'te (beta 2) giderilmiş gibi görünüyor.Burada bit nobugz için optimize x86 sökme yukarıda vurgulanan:

    Console.WriteLine("Post-check Value is: " + value); 
00000056 mov   ecx,dword ptr ds:[033C2090h] 
0000005c mov   edx,dword ptr [ebp-8] 
0000005f call  65D8FE10 

programı da hem optimize edilmiş ve optimize edilmemiş modlarda beklenen çıktıyı görüntüler.