Ответ 1
Вы обнаружили ошибку генерации кода в джиттере .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-разрядное целое. Вспомогательная функция getter массива возвращала 0x0000000FF, равную State.BUG, и ее необходимо преобразовать в -1 (0xFFFFFFFF) до того, как значение будет сравниваться. Инструкция MOVSX представляет собой команду Sign eXtension.
То же самое происходит и в 013F04CC, но на этот раз существует команда no MOVSX для того же преобразования. Что там, где фишки падают, команда CMP сравнивает 0xFFFFFFFF с 0x000000FF, и это ложь. Таким образом, это ошибка пропуска, генератор кода не смог снова запустить MOVSX для выполнения одного и того же преобразования sbyte в int.
Что особенно необычно в этой ошибке, так это то, что это правильно работает при включении оптимизатора, теперь он знает, что использовать MOVSX в обоих случаях.
Вероятная причина, по которой эта ошибка не была обнаружена так долго, - это использование sbyte в качестве базового типа перечисления. Довольно редко. Использование многомерного массива также полезно, комбинация является фатальной.
В противном случае довольно критическая ошибка, я бы сказал. Насколько широко распространено это может быть трудно догадаться, у меня есть только 4.6.1 x86 джиттера для тестирования. X64 и джиттер 3.5 x86 генерируют совершенно другой код и избегают этой ошибки. Временным решением для продолжения является удаление sbyte в качестве базового типа enum и его значение по умолчанию - int, поэтому расширение знака не требуется.
Вы можете отправить сообщение об ошибке на connect.microsoft.com, чтобы связать его с этим Q + A, должно быть достаточно, чтобы сообщить им все, что им нужно знать. Дайте мне знать, если вы не хотите тратить время, и я позабочусь об этом.