Znalazłeś błąd generowania kodu w jitterze .NET 4 x86. Jest to bardzo nietypowe, zawodzi tylko wtedy, gdy kod nie jest zoptymalizowany. Kod maszynowy wygląda następująco:
State a = s[0, 0];
013F04A9 push 0 ; index 2 = 0
013F04AB mov ecx,dword ptr [ebp-40h] ; s[] reference
013F04AE xor edx,edx ; index 1 = 0
013F04B0 call 013F0058 ; eax = s[0, 0]
013F04B5 mov dword ptr [ebp-4Ch],eax ; $temp1 = eax
013F04B8 movsx eax,byte ptr [ebp-4Ch] ; convert sbyte to int
013F04BC mov dword ptr [ebp-44h],eax ; a = s[0, 0]
Console.WriteLine(a == s[0, 0]); // False
013F04BF mov eax,dword ptr [ebp-44h] ; a
013F04C2 mov dword ptr [ebp-50h],eax ; $temp2 = a
013F04C5 push 0 ; index 2 = 0
013F04C7 mov ecx,dword ptr [ebp-40h] ; s[] reference
013F04CA xor edx,edx ; index 1 = 0
013F04CC call 013F0058 ; eax = s[0, 0]
013F04D1 mov dword ptr [ebp-54h],eax ; $temp3 = eax
; <=== Bug here!
013F04D4 mov eax,dword ptr [ebp-50h] ; a == s[0, 0]
013F04D7 cmp eax,dword ptr [ebp-54h]
013F04DA sete cl
013F04DD movzx ecx,cl
013F04E0 call 731C28F4
Trudna sprawa z wieloma elementami tymczasowymi i powielaniem kodu, to normalne w przypadku niezoptymalizowanego kodu. Godna uwagi jest instrukcja pod numerem 013F04B8, czyli miejsce, w którym zachodzi konieczna konwersja z bajtu na 32-bitową liczbę całkowitą. Funkcja pomocnicza pobierająca tablicę zwróciła wartość 0x0000000FF, równą State.BUG, która musi zostać przekonwertowana na -1 (0xFFFFFFFF), zanim wartość będzie mogła zostać porównana. Instrukcja MOVSX jest instrukcją Sign eXtension.
To samo dzieje się ponownie w 013F04CC, ale tym razem nie ma instrukcji MOVSX, która wykonałaby taką samą konwersję. Tam właśnie spadają chipy, instrukcja CMP porównuje 0xFFFFFFFF z 0x000000FF i to jest fałsz. Jest to więc błąd pominięcia, generator kodu nie wyemitował ponownie MOVSX, aby wykonać tę samą konwersję sbyte na int.
Szczególnie niezwykłe w tym błędzie jest to, że działa on poprawnie po włączeniu optymalizatora, teraz wie, że używa MOVSX w obu przypadkach.
Prawdopodobnym powodem, dla którego ten błąd pozostawał niewykryty przez tak długi czas, jest użycie sbyte jako podstawowego typu wyliczenia. Dość rzadkie. Korzystanie z wielowymiarowej tablicy ma również znaczenie instrumentalne, połączenie jest fatalne.
W przeciwnym razie powiedziałbym, że jest to dość krytyczny błąd. Trudno zgadnąć, jak powszechne może to być, do przetestowania mam tylko jitter 4.6.1 x86. Jitter x64 i 3.5 x86 generują bardzo różny kod i pozwalają uniknąć tego błędu. Tymczasowym obejściem, aby kontynuować, jest usunięcie sbyte jako podstawowego typu wyliczenia i pozostawienie go domyślnym, int , więc nie jest potrzebne żadne rozszerzenie znaku.
Możesz zgłosić błąd pod adresem connect.microsoft.com, łącze do tego pytania i odpowiedzi powinno wystarczyć, aby przekazać im wszystko, co powinni wiedzieć. Daj mi znać, jeśli nie chcesz tracić czasu, a ja się tym zajmę.