c# compiler-optimization

c# - El error solo ocurre cuando la optimización de compilación está habilitada



compiler-optimization (5)

Encontré un error en el código que solo se reproduce cuando el código se genera con las optimizaciones habilitadas. He creado una aplicación de consola que replica la lógica para probar (código a continuación). Verá que cuando la optimización está habilitada, ''valor'' se vuelve nulo después de la ejecución de esta lógica no válida:

if ((value == null || value == new string[0]) == false)

La solución es directa y está comentada debajo del código ofensivo. Pero ... me preocupa más que haya encontrado un error en el ensamblador o que alguien más tenga una explicación de por qué el valor se establece en nulo.

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace memory_testing { class Program { sta tic void Main(string[] args) { while(true) { Console.Write("Press any key to start..."); Console.ReadKey(); Console.WriteLine(); PrintManagerUser c = new PrintManagerUser(); c.MyProperty = new string[1]; } } } public class PrintManager { public void Print(string key, object value) { Console.WriteLine("Key is: " + key); Console.WriteLine("Value is: " + value); } } public class PrintManagerUser { public string[] MyProperty { get { return new string[100]; } set { Console.WriteLine("Pre-check Value is: " + value); if ((value == null || value == new string[0]) == false) { Console.WriteLine("Post-check Value is: " + value); new PrintManager().Print("blah", value); } //if (value != null && value.Length > 0) //{ // new PrintManager().Print("blah", value); //} } } } }

La salida normal debería ser:

Pre-check Value is: System.String[] Post-check Value is: System.String[] Key is: blah Value is: System.String[]

La salida con errores es:

Pre-check Value is: System.String[] Post-check Value is: Key is: blah Value is:

My Env es una máquina virtual que ejecuta Windows Server 2003 R2 con .NET 3.5 SP1. Usando el sistema de equipo VS2008.

Gracias,

Brian


Ciertamente se parece a un error, ¿se reproduce cuando intercambias los operandos del operador de esta manera?

if (false == (null == value || new string[0] == value))


Este error parece haberse corregido en .NET 4 (beta 2). Aquí está el desmontaje x86 optimizado para el bit nobugz resaltado, arriba:

Console.WriteLine("Post-check Value is: " + value); 00000056 mov ecx,dword ptr ds:[033C2090h] 0000005c mov edx,dword ptr [ebp-8] 0000005f call 65D8FE10

El programa también muestra la salida esperada en modos optimizados y no optimizados.


Estoy en x64 y no pude reproducir el problema al principio. Luego especifiqué el objetivo como x86 y me sucedió a mí. De vuelta a x64, y se fue. No estoy seguro de lo que esto significa, exactamente, pero he ido y venido varias veces ahora.


Sí, su expresión confunde fatalmente el optimizador JIT. El código máquina generado se ve así:

if ((value == null || value == new string[0]) == false) 00000027 test esi,esi ; value == null? 00000029 je 00000075 0000002b xor edx,edx ; new string[0] 0000002d mov ecx,6D913BD2h 00000032 call FFD20BC8 00000037 cmp eax,esi ; (value == new string[0]) == false? 00000039 je 00000075 { Console.WriteLine("Post-check Value is: " + value); 0000003b mov ecx,dword ptr ds:[03532090h] ; "Post-check value is: " 00000041 xor edx,edx ; BUGBUG not null! 00000043 call 6D70B7E8 ; String.Concat() 00000048 mov esi,eax ; 0000004a call 6D72BE08 ; get Console.Out 0000004f mov ecx,eax 00000051 mov edx,esi 00000053 mov eax,dword ptr [ecx] 00000055 call dword ptr [eax+000000D8h] ; Console.WriteLine()

El error ocurre en la dirección 41, el optimizador ha concluido que el valor siempre será nulo, por lo que pasa directamente un nulo a String.Concat ().

A modo de comparación, este es el código que se genera cuando la optimización de JIT está desactivada:

Console.WriteLine("Post-check Value is: " + value); 00000056 mov ecx,dword ptr ds:[03342090h] 0000005c mov edx,dword ptr [ebp-8] 0000005f call 6D77B790

El código se movió, pero tenga en cuenta que en la dirección 5c ahora usa la variable local (valor) en lugar de nulo.

Puede informar este error en connect.microsoft.com. La solución es simple:

if (value != null) { Console.WriteLine("Post-check Value is: " + value); new PrintManager().Print("blah", value); }


value == new string[0]

Lo anterior me parece una declaración extraña. Está comparando dos matrices de cadenas con una declaración equals. Eso solo resultará verdadero si ambos apuntan a la misma matriz, lo cual es bastante improbable. Esto todavía no explica por qué este código se comporta de manera diferente en una versión optimizada.