2015-07-22 20 views
35

Po aktualizacji do .net 4.6 odkryliśmy błąd, w którym RyuJit generuje niepoprawne wyniki, mogliśmy na razie obejść ten problem, dodając useLegacyJit enabled = "true" do pliku app.config.RyuJit produkuje niepoprawne wyniki

Jak mogę debugować kod maszynowy wygenerowany przez następujące elementy?

Utworzony nowy projekt konsoli w VS 2015 RTM, ustawiony na Release, Dowolny CPU, niezaznaczony Woliera 32-bitowy, uruchomiony z dołączonym debugerem i bez niego daje taki sam wynik.

using System; 
using System.Runtime.CompilerServices; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine(Calculate()); 
      Console.WriteLine(Calculate()); 

      Console.ReadLine(); 
     } 

     [MethodImpl(MethodImplOptions.AggressiveInlining)] 
     public static Value Calculate() 
     { 
      bool? _0 = (bool?)null; 
      bool? _1 = (bool?)true; 
      if (!Value.IsPresent<bool>(_1)) 
      { 
       return default(Value); 
      } 

      bool? result = null; 
      result = (_1.Value ? new bool?(false) : result); 
      if (_0.HasValue && _0.Value) 
      { 
      } 
      return new Value(result); 
     } 

     public struct Value 
     { 
      bool? _value; 

      public Value(bool? value) 
      { 
       _value = value; 
      } 

      public static bool IsPresent<T>(bool? _) 
      { 
       return _.HasValue; 
      } 

      public override string ToString() 
      { 
       return _value.ToString(); 
      } 
     } 
    } 
} 

Należy produkować: fałszywy fałszywy

lecz produkuje: Prawdziwa fałszywy

Kluczową częścią przykładem jest

result = true ? false : result; 

który powinien zawsze wracają false, ale jak widać na wyjściu, zwraca True po raz pierwszy t metoda jest uruchomiona, a inna odpowiedź po drugim uruchomieniu metody. Usunięcie kilku kolejnych linii z metody Calculate() spowoduje, że powróci ona zawsze True, ale podany przykład jest najbliższy mojemu powieleniu do naszego rzeczywistego scenariusza produkcji.

+5

Tak, jest to błąd optymalizacji inline. Pierwszy wbudowany Calculate() ma złą instrukcję. Wygląda mi na to, że gdzieś wewnątrz optymalizatora jest '!', Którego tam nie powinno być. Nic nie możemy zrobić, aby naprawić ten błąd oczywiście, możesz zgłosić to na connect.microsoft.com. Po prostu zwolnij metodę MethodImplOptions.AggressiveInlining przez pewien czas, co jest mało prawdopodobne, aby zostało szeroko przetestowane. –

+0

Rzeczywisty kod produkcyjny nie ma atrybutu AggressiveInlining, ale jest to jedyny sposób, w jaki mogę odtworzyć zachowanie w tym małym przykładzie. Kod produkcyjny jest częściowo generowany maszynowo, dlatego przykładowy kod wygląda nieco dziwnie. Właśnie zgłosiłem to na https://connect.microsoft.com/VisualStudio/feedback/details/1578173 – BrandonAGr

+0

@BandandAGr Ten błąd jest spowodowany podczas wstawiania? Korzystanie z 'MethodImplOptions.NoInlining' jest możliwym obejściem? – Andre

Odpowiedz

27

Dziękuję za program izolowanych repro i mogę potwierdzić, że to rzeczywiście błąd RyuJIT w optymalizatorze, który został ujawniony z powodu inline. Zrobiłem poprawkę do kompilatora i zastanowiłem się nad szczegółami wdrożenia. Nie zamieniać SO w narzędzie do śledzenia błędów i szybszy zwrot: [email protected]

+3

Mam zbudować uproszczoną wersję kodu źródłowego, można go znaleźć w repozytorium coreclr: https : //github.com/dotnet/coreclr/issues/1299 – AndreyAkinshin

+1

@HansPassant Tak nie zamierzał tego jako raportu o błędzie, ukrytym pytaniem było, jak znaleźć kod maszynowy, który jest wykonywany. Uproszczony przykład stworzony przez Andreya sprawił, że bardzo łatwo było po prostu obejrzeć demontaż w visual studio, oczywiście nadal nie jest łatwo uświadomić sobie, jakie rejestry przechowują, ale udało mi się przejść przez to – BrandonAGr

+0

@schellap Czy ta poprawka również naprawia - https : //connect.microsoft.com/VisualStudio/Feedback/Details/1602437? –

Powiązane problemy