with start spec guia c# c#-4.0 jit

c# - start - Posible problema.NET x86 JIT?



guia de c# (1)

El siguiente código se comporta de manera diferente cuando se genera en modo de lanzamiento (o depuración con optimizaciones activadas) y se ejecuta sin el depurador de Visual Studio conectado.

También parece replicarse solo si se usa x86 JITter. Lo probé en una máquina x86 y también en WOW64 en una máquina x64 (estableciendo el objetivo de la plataforma en x86).

Solo he intentado esto con .NET 4.0.

Cuando se ejecuta fuera del depurador en la Versión I, veo:

Value is 4

Cuando se ejecuta dentro del depurador, la porción e.Value.Length de la llamada WriteLine arroja NullReferenceException , que es lo que esperaba que sucediera.

El código:

namespace Test { class UsingReleasable<T> { public UsingReleasable(T obj) { m_obj = obj; } public T Release() { T tmp = m_obj; m_obj = default(T); return tmp; } public T Value { get { return m_obj; } } T m_obj; } class Program { static void Main(string[] args) { var e = new UsingReleasable<string>("test"); e.Release(); System.Console.WriteLine("Value is {0}", e.Value.Length); } } }

Mi observación del código generado por JIT me hace pensar que es un error en esa pieza, pero quería verificarlo aquí antes de enviar esto a MS Connect.


Puedo reproducir tu comportamiento:

R:/>csc /platform:x86 releasable.cs Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1 Copyright (C) Microsoft Corporation. All rights reserved. R:/>releasable Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object. at Test.Program.Main(String[] args) R:/>csc /o+ /platform:x86 releasable.cs Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1 Copyright (C) Microsoft Corporation. All rights reserved. R:/>releasable Value is 4 R:/>csc /platform:anycpu releasable.cs Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1 Copyright (C) Microsoft Corporation. All rights reserved. R:/>releasable Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object. at Test.Program.Main(String[] args) R:/>csc /o+ /platform:anycpu releasable.cs Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1 Copyright (C) Microsoft Corporation. All rights reserved. R:/>releasable Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object. at Test.Program.Main(String[] args)

La opción /checked compilada del compilador no hace diferencia. Tampoco lo hace la generación de depuración de datos /debug+ . Y el problema persiste cuando se llama a Console.ReadLine() (para dar la oportunidad de adjuntar el depurador y ver el código optimizado).

Hice una pequeña modificación en Main para permitir la depuración del código optimizado:

static void Main(string[] args) { var e = new UsingReleasable<string>("test"); System.Console.WriteLine("attach now"); System.Console.ReadLine(); e.Release(); System.Console.WriteLine("Value is {0}", e.Value.Length); }

Y el desmontaje real:

--- r:/releasable.cs ----------------------------------------------------------- var e = new UsingReleasable<string>("test"); 00000000 push ebp 00000001 mov ebp,esp 00000003 push edi 00000004 push esi 00000005 mov ecx,1839B0h 0000000a call FFF81FB0 0000000f mov esi,eax 00000011 mov eax,dword ptr ds:[03772030h] 00000017 lea edx,[esi+4] 0000001a call 60452F70 System.Console.WriteLine("attach now"); 0000001f call 5E927060 00000024 mov ecx,eax 00000026 mov edx,dword ptr ds:[03772034h] 0000002c mov eax,dword ptr [ecx] 0000002e mov eax,dword ptr [eax+3Ch] 00000031 call dword ptr [eax+10h] 00000034 call 5EEF9A40 00000039 mov ecx,eax 0000003b mov eax,dword ptr [ecx] 0000003d mov eax,dword ptr [eax+2Ch] 00000040 call dword ptr [eax+1Ch] e.Release(); 00000043 mov edi,dword ptr [esi+4] ; edi = e.Value 00000046 lea esi,[esi+4] ; esi = &e.Value 00000049 xor edx,edx ; edx = null 0000004b mov dword ptr [esi],edx ; *esi = edx (e.Value = null) 0000004d mov ecx,5EBE28F8h 00000052 call FFF81FB0 00000057 mov edx,eax 00000059 mov eax,dword ptr [edi+4] ; this sets EAX to 4 0000005c mov dword ptr [edx+4],eax 0000005f mov esi,edx 00000061 call 5E927060 00000066 push esi 00000067 mov ecx,eax 00000069 mov edx,dword ptr ds:[03772038h] 0000006f mov eax,dword ptr [ecx] 00000071 mov eax,dword ptr [eax+3Ch] 00000074 call dword ptr [eax+18h] ; this results in the output "Value is 4/n" 00000077 pop esi } 00000078 pop edi 00000079 pop ebp 0000007a ret

Cuando el programa se inicia bajo el depurador, este código se genera en su lugar (y produce una NullReferenceException :

--- r:/releasable.cs ----------------------------------------------------------- var e = new UsingReleasable<string>("test"); 00000000 push ebp 00000001 mov ebp,esp 00000003 sub esp,24h 00000006 mov dword ptr [ebp-4],ecx 00000009 cmp dword ptr ds:[001E313Ch],0 00000010 je 00000017 00000012 call 606B6807 00000017 xor edx,edx 00000019 mov dword ptr [ebp-0Ch],edx 0000001c mov ecx,1E39B0h 00000021 call FFF91FB0 00000026 mov dword ptr [ebp-10h],eax 00000029 mov edx,dword ptr ds:[032E2030h] 0000002f mov ecx,dword ptr [ebp-10h] 00000032 call dword ptr ds:[001E3990h] 00000038 mov eax,dword ptr [ebp-10h] 0000003b mov dword ptr [ebp-0Ch],eax System.Console.WriteLine("attach now"); 0000003e mov ecx,dword ptr ds:[032E2034h] 00000044 call 5E8D703C System.Console.ReadLine(); 00000049 call 5EEAA728 0000004e nop e.Release(); 0000004f mov ecx,dword ptr [ebp-0Ch] 00000052 cmp dword ptr [ecx],ecx 00000054 call dword ptr ds:[001E3994h] 0000005a nop System.Console.WriteLine("Value is {0}", e.Value.Length); 0000005b mov eax,dword ptr ds:[032E2038h] 00000061 mov dword ptr [ebp-14h],eax 00000064 mov ecx,dword ptr [ebp-0Ch] 00000067 cmp dword ptr [ecx],ecx 00000069 call dword ptr ds:[001E3998h] 0000006f mov dword ptr [ebp-18h],eax 00000072 mov ecx,dword ptr [ebp-18h] 00000075 cmp dword ptr [ecx],ecx ; access violation here 00000077 call 608CBA5B 0000007c mov dword ptr [ebp-8],eax 0000007f mov ecx,5EBE28F8h 00000084 call FFF91FB0 00000089 mov dword ptr [ebp-1Ch],eax 0000008c mov eax,dword ptr [ebp-14h] 0000008f mov dword ptr [ebp-20h],eax 00000092 mov eax,dword ptr [ebp-1Ch] 00000095 mov edx,dword ptr [ebp-8] 00000098 mov dword ptr [eax+4],edx 0000009b mov eax,dword ptr [ebp-1Ch] 0000009e mov dword ptr [ebp-24h],eax 000000a1 mov ecx,dword ptr [ebp-20h] 000000a4 mov edx,dword ptr [ebp-24h] 000000a7 call 5E8CD460 } 000000ac nop 000000ad mov esp,ebp 000000af pop ebp 000000b0 ret

Creo que he comentado todas las líneas de código relevantes en la versión incorrecta. El registro claro de edi se usa para mantener un puntero a e.Value , que consiste muy probablemente en un puntero al contenido (en el desplazamiento 0) y una longitud (en el desplazamiento 4) de la tabla v (en el desplazamiento 0), longitud (en offset 4), seguido inmediatamente por el contenido. Lamentablemente, e.Value (la cadena "test" ) se copia en edi antes de que e.Value se e.Value , por lo que se recupera la longitud utilizando el puntero de cadena incorrecto. ¡Ay!

Error presentado en Connect (por favor, ¡voto favorable!): X86 JIT reordena incorrectamente la carga de campo de tipo genérico con asignación a valores predeterminados (T)