Рассматривать:
using System;
public class Test
{
enum State : sbyte { OK = 0, BUG = -1 }
static void Main(string[] args)
{
var s = new State[1, 1];
s[0, 0] = State.BUG;
State a = s[0, 0];
Console.WriteLine(a == s[0, 0]); // False
}
}
Как это можно объяснить? Это происходит в отладочных сборках в Visual Studio 2015 при запуске в x86 JIT. Выпуск сборки или запуска в x64 JIT печатает True, как и ожидалось.
Воспроизвести из командной строки:
csc Test.cs /platform:x86 /debug
( /debug:pdbonly
, /debug:portable
А /debug:full
также воспроизводить.)
ildasm
а затем егоilasm
«исправление» .../debug=IMPL
флаг листья сокрушен;/debug=OPT
"исправляет" это.Ответы:
Вы нашли ошибку генерации кода в джиттере .NET 4 x86. Это очень необычный вариант, он дает сбой только тогда, когда код не оптимизирован. Машинный код выглядит так:
Дела с большим количеством временных и дублирующих кодов, это нормально для неоптимизированного кода. Команда на 013F04B8 заслуживает внимания, именно здесь происходит необходимое преобразование из sbyte в 32-разрядное целое число. Вспомогательная функция получения массива вернула 0x0000000FF, равный State.BUG, и его необходимо преобразовать в -1 (0xFFFFFFFF), прежде чем можно будет сравнить значение. Инструкция MOVSX является инструкцией Sign eXtension.
То же самое происходит снова в 013F04CC, но на этот раз нет инструкции MOVSX для того же преобразования. Вот где чипы падают, инструкция CMP сравнивает 0xFFFFFFFF с 0x000000FF, и это ложно. Так что это ошибка пропуска, генератор кода не смог снова сгенерировать MOVSX для выполнения того же преобразования sbyte в int.
Что особенно необычно в этой ошибке, так это то, что она работает правильно, когда вы включаете оптимизатор, теперь он знает, что нужно использовать MOVSX в обоих случаях.
Вероятная причина, по которой эта ошибка так долго не обнаруживалась, - использование sbyte в качестве базового типа перечисления. Довольно редко, чтобы сделать. Также полезно использовать многомерный массив, комбинация фатальна.
В противном случае я бы сказал, что это довольно критическая ошибка. Трудно догадаться, насколько широко это может быть, у меня есть только джиттер 4.6.1 x86 для тестирования. X64 и 3.5 x86 jitter генерируют совершенно другой код и избегают этой ошибки. Временный обходной путь для продолжения работы состоит в том, чтобы удалить sbyte в качестве базового типа enum и оставить его по умолчанию int , поэтому расширение знака не требуется.
Вы можете отправить сообщение об ошибке по адресу connect.microsoft.com, ссылки на этот вопрос достаточно для того, чтобы рассказать им все, что им нужно знать. Дайте мне знать, если вы не хотите уделять время, и я позабочусь об этом.
источник
byte
вместоsbyte
должно быть тоже хорошо и может быть предпочтительным, если реальный код используется, например, с ORM, где вы не хотите, чтобы ваши флаги в базе данных занимали дополнительное место.Давайте рассмотрим декларацию OP:
Так как ошибка возникает только тогда, когда
BUG
она отрицательна (от -128 до -1) и State является перечислением подписанного байта, я начал предполагать, что где-то была проблема приведения.Если вы запустите это:
это выведет:
По причине, которую я игнорирую (на данный момент)
s[0, 0]
преобразуется в байт перед оценкой, и поэтому он утверждает, чтоa == s[0,0]
это неверно.источник