Considerar:
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
}
}
Como isso pode ser explicado? Ocorre em compilações de depuração no Visual Studio 2015 ao executar no x86 JIT. Uma versão compilada ou em execução no JIT x64 imprime True conforme o esperado.
Para reproduzir a partir da linha de comando:
csc Test.cs /platform:x86 /debug
( /debug:pdbonly
, /debug:portable
e /debug:full
também reproduzir.)
c#
multidimensional-array
enumeration
shingo
fonte
fonte
ildasm
e, em seguida,ilasm
"correções" que .../debug=IMPL
bandeira a deixa quebrada;/debug=OPT
"corrige" isso.Respostas:
Você encontrou um bug de geração de código no jitter do .NET 4 x86. É muito incomum, só falha quando o código não é otimizado. O código da máquina fica assim:
Um caso difícil com muitos temporários e duplicação de código, isso é normal para código não otimizado. A instrução em 013F04B8 é notável; é aí que ocorre a conversão necessária de sbyte para um número inteiro de 32 bits. A função auxiliar do getter da matriz retornou 0x0000000FF, igual a State.BUG, e precisa ser convertida em -1 (0xFFFFFFFF) antes que o valor possa ser comparado. A instrução MOVSX é uma instrução Sign eXtension.
A mesma coisa acontece novamente em 013F04CC, mas desta vez não há instruções MOVSX para fazer a mesma conversão. É aí que os chips caem, a instrução CMP compara 0xFFFFFFFF com 0x000000FF e isso é falso. Portanto, este é um erro de omissão, o gerador de código falhou ao emitir o MOVSX novamente para executar a mesma conversão de sbyte em int.
O que é particularmente incomum nesse bug é que ele funciona corretamente quando você ativa o otimizador, que agora sabe usar o MOVSX nos dois casos.
O motivo provável pelo qual esse bug ficou sem ser detectado por tanto tempo é o uso de sbyte como o tipo base do enum. Muito raro de se fazer. O uso de uma matriz multidimensional também é fundamental, a combinação é fatal.
Caso contrário, um bug bastante crítico, eu diria. É difícil adivinhar quão difundida pode ser, só tenho o jitter 4.6.1 x86 para testar. O jitter x64 e o jitter 3,5 x86 geram códigos muito diferentes e evitam esse bug. A solução temporária para continuar é remover sbyte como o tipo base de enum e deixá-lo como padrão, int , para que nenhuma extensão de sinal seja necessária.
Você pode registrar o bug em connect.microsoft.com, vincular a este Q + A deve ser suficiente para dizer a eles tudo o que eles precisam saber. Deixe-me saber se você não quiser reservar um tempo e eu cuido disso.
fonte
byte
vez desbyte
deve ser bom também e pode ser preferível se o código real for usado com um ORM, onde você não deseja que seus sinalizadores no banco de dados ocupem espaço extra.Vamos considerar a declaração do OP:
Como o bug ocorre apenas quando
BUG
é negativo (de -128 a -1) e State é um enum de byte assinado , comecei a supor que havia um problema de conversão em algum lugar.Se você executar isso:
ele produzirá:
Por um motivo que eu ignoro (a partir de agora)
s[0, 0]
é convertido em um byte antes da avaliação e é por isso que afirmaa == s[0,0]
ser falso.fonte