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