.NET 4 x86ジッタにコード生成のバグが見つかりました。これは非常に珍しいもので、コードが最適化されていない場合にのみ失敗します。マシンコードは次のようになります。
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
多くの一時的なものとコードの重複を伴う大騒ぎは、最適化されていないコードでは普通です。013F04B8の命令は注目に値します。つまり、sbyteから32ビット整数への必要な変換が行われます。配列ゲッターヘルパー関数は、State.BUGに等しい0x0000000FFを返し、値を比較する前に-1(0xFFFFFFFF)に変換する必要があります。MOVSX命令はSign eXtension命令です。
013F04CCでも同じことが起こりますが、今回は同じ変換を行うMOVSX命令はありません。それはチップが落ちるところです、CMP命令は0xFFFFFFFFを0x000000FFと比較し、それは偽です。したがって、これは省略のエラーです。コードジェネレーターは、同じsbyteからintへの変換を実行するために再度MOVSXを発行できませんでした。
このバグについて特に異常なのは、オプティマイザを有効にすると正しく機能することです。これで、両方のケースでMOVSXを使用することが認識されます。
このバグが長い間検出されなかった理由としては、列挙型の基本型としてのsbyteの使用が考えられます。かなりまれです。多次元配列を使用することも同様に重要であり、その組み合わせは致命的です。
それ以外の場合はかなり重大なバグだと思います。それがどれほど広範囲に及ぶかは推測するのが難しいかもしれませんが、テストするのは4.6.1 x86ジッタのみです。x64と3.5 x86ジッタは非常に異なるコードを生成し、このバグを回避します。続行するための一時的な回避策は、列挙型の基本型としてsbyteを削除し、それをデフォルトのintにすることですにすることです。そのため、符号拡張は必要ありません。
connect.microsoft.comでバグを報告することができます。このQ + Aにリンクすることで、彼らが知る必要のあるすべてを伝えることができます。時間をかけたくない場合はお知らせください。面倒を見てくれます。