2012-03-26 11 views
18

Sto riscontrando una situazione in cui una chiamata PInvoke a CloseHandle sta lanciando un SEHException in un'applicazione .NET 4 quando viene eseguita con un debugger. A differenza di others who have encountered similar issues migrating from 3.5 to 4, non sono particolarmente disturbato dal comportamento e ho già individuato il problema (una libreria di terze parti che chiama lo CloseHandle due volte sullo stesso handle). Tuttavia, sono perplesso sul motivo per cui questo comportamento non si verifica in un'applicazione .NET 3.5.Perché la gestione delle eccezioni da CloseHandle è diversa tra .NET 4 e 3.5?

Il seguente esempio piccolo ma completo illustrato il comportamento che sto vivendo (testato sia su XP SP3 e Windows 7 x64, sempre compilato come 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); 
} 

Quando viene eseguito come un'applicazione .NET 4, un SEHException viene lanciato al secondo CloseHandle. comportamento Come per la documentation for CloseHandle, questo è previsto:

Se l'applicazione è in esecuzione in un debugger, la funzione un'eccezione se riceve un valore maniglia che non è valido o un valore pseudo-handle . Ciò può accadere se si chiude un handle due volte o se si chiama CloseHandle su un handle restituito dalla funzione FindFirstFile anziché chiamare la funzione FindClose.

Tuttavia, se compilato come un'applicazione .NET 3.5 (o CLR 2.0), non viene generata un'eccezione alla seconda CloseHandle chiamata e il messaggio "No exception" viene stampato.

In base a this article, il CLR aggiornato rilasciato per .NET 4 presenta un comportamento predefinito diverso con eccezioni di basso livello che possono potenzialmente danneggiare lo stato del processo. Tuttavia, per quanto posso capire da quell'articolo, non c'è nulla di menzionato nel precedente comportamento CLR che possa far ignorare completamente l'eccezione.

Perché un'applicazione .NET 3.5 (o CLR 2.0) non presenta il comportamento documentato di CloseHandle presente in .NET 4?

+2

Io per parte sono contento che MS abbia apportato alcuni miglioramenti in questa arena. Ho faticato con i problemi qui da anni: http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataproviders/thread/b5b7a179-3737-4380-b6cf-843f3e71b317/ – Brannon

+0

Forse in pre. NET 4 erano catturare e ignorare silenziosamente tali eccezioni –

+0

Che è esattamente quello che mi interessa scoprire - perché potrebbe essere il caso :) – jeffora

risposta

9

Windows genera l'eccezione SEH solo quando vede che è collegato un debugger. A debugger nativo. C'è stato un cambiamento nel debugger gestito di .NET 4 che ora fa vedere a Windows un tale debugger. Non riesco a trovare nessun link decente che documenta i dettagli esatti di questo nuovo comportamento, mi dispiace.

Modifica: ne ho trovato uno decente. Proiettile 8 in fondo this blog post:

Sotto il cofano ci stiamo costruita sul debug gasdotto nativa In modalità v2-compat, ICD continua a possedere la pipeline per il processo di destinazione (dato che era il modello V2), ma quella pipeline non è più una raccolta di oggetti IPC condivisi con il processo di destinazione, ma è invece la stessa pipeline utilizzata da un debugger nativo. Nello specifico, ci colleghiamo a un processo chiamando kernel32! DebugActiveProcess e otteniamo i nostri eventi gestiti (cose che risultano in chiamate a ICorDebugManagedCallback) usando kernel32! WaitForDebugEvent. Ciò significa anche che kernel32! IsDebuggerPresent ora restituisce true quando si esegue il debug solo gestito. Questo ha anche il bell'effetto collaterale di evitare il problema con fare il debug gestito solo quando un debugger del kernel è abilitato (il sistema operativo presuppone che qualsiasi istruzione di breakpoint che si verifica quando un debugger non è collegato dovrebbe causare un'interruzione nel debugger del kernel) .

Questo non è solo un cosmetico fix btw, sia pure che gli attacchi manico riciclare è una cosa che mantiene i dipendenti Microsoft sveglio la notte. La versione .NET di CLR è costruita con la versione CRT che verifica la presenza di buffer overflow. Quando viene rilevato uno, il CRT termina immediatamente il programma. Nessuna AppDomain.UnhandledException, si tratta di un arresto anomalo immediato sul desktop. Questo codice tuttavia fa la stessa cosa che fa Windows, controlla un debugger nativo e genera un punto di interruzione quando uno è collegato. Quindi era abbastanza importante che il debugger gestito iniziasse ad apparire come un nativo, l'unico modo per diagnosticare realmente l'arresto anomalo.

+0

Questo spiegherebbe anche perché improvvisamente inizia a rompere in .NET 3.5 quando "Debug Native Code" è selezionato nelle proprietà del progetto (che ho scoperto l'altra sera quando ho cercato di dare un'occhiata di nuovo in questo). Grazie! – jeffora

+0

Sì, l'attivazione del supporto di debug non gestito nelle versioni precedenti rende il debugger chiamato WaitForDebugEvent(). –

1

Nessuna risposta "buona" a questo .. 3.5 aveva un bug nel SEH risolto in 4.0 .. Stava mangiando l'eccezione. Ho avuto un problema simile e abbiamo aperto un ticket con MSFT su di esso - la loro risposta era "bugfix".

+0

Hai aperto una richiesta di connessione? Se sì, puoi pubblicare un link ad esso? –

+0

@JohnSaunders - Hans Passant dice anche che c'era un bug, il che significa che c'era un bug, il collegamento al ticket non provava nulla. –

+0

Non disponiamo di Connect, abbiamo appena aperto un ticket di assistenza one-off. Sembra che Hans abbia fornito dettagli su cosa fosse sotto quella fix .. – XeroxDucati

Problemi correlati