2012-03-26 7 views
18

Me encuentro con una situación donde una llamada de PInvoke al CloseHandle está lanzando un SEHException en una aplicación .NET 4 cuando se ejecuta bajo un depurador. A diferencia de others who have encountered similar issues migrating from 3.5 to 4, no estoy particularmente molesto por el comportamiento, y ya he localizado el problema (una biblioteca de terceros llamando al CloseHandle dos veces en el mismo identificador). Sin embargo, estoy perplejo de por qué este comportamiento no ocurre en una aplicación .NET 3.5.¿Por qué el manejo de excepciones de CloseHandle es diferente entre .NET 4 y 3.5?

El siguiente ejemplo pequeño pero completo demuestra el comportamiento que estoy experimentando (probado en tanto XP SP3 y Windows 7 x64, siempre compilada como x86):

class Program 
{ 
    static void Main(string[] args) 
    { 
     try 
     { 
      var hFileMapping = CreateFileMapping(new IntPtr(-1), IntPtr.Zero, 0x04 /* read write */, 0, 0x1000, null); 
      CloseHandle(hFileMapping); 
      CloseHandle(hFileMapping); 
      Console.WriteLine("No exception"); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex); 
     } 

     Console.ReadKey(); 
    } 

    [DllImport("kernel32", SetLastError = true)] 
    static extern IntPtr CreateFileMapping(IntPtr hFile, IntPtr lpAttributes, int flProtect, int dwMaximumSizeHigh, int dwMaximumSizeLow, string lpName); 

    [DllImport("kernel32", SetLastError = true)] 
    static extern bool CloseHandle(IntPtr handle); 
} 

Cuando se ejecuta como una aplicación .NET 4, un SEHException se arroja en el segundo CloseHandle. el comportamiento según el documentation for CloseHandle, se espera:

Si la aplicación se ejecuta bajo un depurador, la función lanzar una excepción si recibe o bien un valor identificador que no es válido o un valor pseudo-mango . Esto puede suceder si cierra un identificador dos veces, o si llama a CloseHandle en un identificador devuelto por la función FindFirstFile en lugar de llamar a la función FindClose.

Sin embargo, cuando se compila como una aplicación de .NET 3.5 (o CLR 2.0), no es una excepción es lanzada en el segundo CloseHandle llamada, y el mensaje "No exception" se imprime.

De acuerdo con this article, el CLR actualizado publicado para .NET 4 tiene un comportamiento predeterminado diferente con excepciones de bajo nivel que tienen el potencial de dañar el estado del proceso. Sin embargo, por lo que puedo entender de ese artículo, no se menciona nada del comportamiento anterior de CLR que haría que la excepción se ignore por completo.

¿Por qué una aplicación .NET 3.5 (o CLR 2.0) no muestra el comportamiento documentado de CloseHandle que está presente en .NET 4?

+2

Me alegro de que MS haya realizado algunas mejoras en este campo. Luché con los problemas aquí durante años: http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataproviders/thread/b5b7a179-3737-4380-b6cf-843f3e71b317/ – Brannon

+0

Tal vez en pre .NET 4 eran simplemente captando silenciosamente e ignorando esas excepciones –

+0

que es precisamente lo que estoy interesado en averiguar - por qué podría ser el caso :) – jeffora

Respuesta

9

Windows solo genera la excepción SEH cuando ve que hay un depurador conectado. Un depurador nativo. Hubo un cambio en el depurador administrado .NET 4 que ahora hace que Windows vea dicho depurador. No puedo encontrar ningún enlace decente que documente los detalles exactos de este nuevo comportamiento, lo siento.

Editar: Encontré una decente. 8 bala en la parte inferior de this blog post:

Bajo el capó nos basamos en la tubería de depuración nativa En el modo v2-compat, CIE continúa siendo el propietario de la tubería para el proceso de destino (ya que ese era el modelo V2), pero esa interconexión ya no es una colección de objetos IPC compartidos con el proceso objetivo, sino que es la misma interconexión que usa un depurador nativo. Específicamente, nos conectamos a un proceso llamando a kernel32! DebugActiveProcess, y obtenemos nuestros eventos gestionados (cosas que dan como resultado llamadas a ICorDebugManagedCallback) usando kernel32! WaitForDebugEvent. Esto también significa que kernel32! IsDebuggerPresent ahora devuelve verdadero cuando se realiza una depuración solo de administración. Esto también tiene el agradable efecto secundario de evitar el problema con la depuración solo administrada cuando se habilita un depurador de kernel (el OS supone que cualquier instrucción de punto de interrupción que ocurra cuando un depurador no está conectado debería causar un corte en el depurador de kernel) .

Esto no es solo una corrección cosmética por cierto, aunque manejar ataques de reciclaje es algo que mantiene a los empleados de Microsoft despiertos por la noche. La versión .NET 4 del CLR está construida con la versión CRT que verifica los desbordamientos del búfer. Cuando se detecta uno, el CRT termina inmediatamente el programa. Sin AppDomain.UnhandledException, se produce un bloqueo inmediato en el escritorio. Sin embargo, este código hace lo mismo que Windows, busca un depurador nativo y genera un punto de interrupción cuando uno está conectado. Por lo tanto, era muy importante que el depurador administrado comenzara a verse como uno nativo, la única forma de realmente diagnosticar el bloqueo.

+0

Eso también explicaría por qué de repente comienza a aparecer en .NET 3.5 cuando se selecciona "Código nativo de depuración" en las propiedades del proyecto (que descubrí la otra noche cuando intento echar un vistazo a esto de nuevo). ¡Gracias! – jeffora

+0

Sí, al activar el soporte de depuración no administrado en versiones anteriores hace que la llamada al depurador WaitForDebugEvent(). –

1

No hay una respuesta 'buena' a esto ... 3.5 tenía un error en el SEH que se arregló en 4.0 .. Estaba comiendo la excepción. Tuve un problema similar y abrimos un boleto con MSFT, su respuesta fue 'corrección de errores'.

+0

¿Has abierto una solicitud de conexión? Si es así, ¿puedes publicar un enlace? –

+0

@JohnSaunders - Hans Passant también dice que hubo un error, lo que significa que hubo un error, vincularlo al ticket no probaría nada. –

+0

No tenemos Connect, acabo de abrir un boleto de soporte único. Parece que Hans proporcionó detalles sobre la corrección que estaba debajo también ... – XeroxDucati

Cuestiones relacionadas