Handle protetti e finalizzazione critica

Aggiornamento: novembre 2007

Nelle versioni di .NET Framework precedenti alla 2.0 tutti gli handle del sistema operativo possono essere incapsulati solo nell'oggetto wrapper gestito IntPtr. Benché in questo modo sia possibile interagire agevolmente con il codice nativo, esiste il rischio di perdita degli handle per le eccezioni asincrone, ad esempio un thread che si interrompe in modo imprevisto o un overflow dello stack. Queste eccezioni asincrone rappresentano un ostacolo per la pulizia delle risorse del sistema operativo e possono verificarsi praticamente ovunque nel programma. Nella maggior parte dei casi si verificano in applicazioni in cui viene utilizzato un host che esegue codice gestito, ad esempio Microsoft SQL Server.

In alcune circostanze gli oggetti finalizzabili possono essere recuperati dalla Garbage Collection durante l'esecuzione di un metodo nell'ambito di un chiamata pInvoke. Se un finalizzatore libera l'handle passato alla chiamata pInvoke, è possibile che l'handle venga danneggiato. L'handle può anche essere recuperato mentre il metodo è bloccato durante una chiamata pInvoke, ad esempio durante la lettura di un file.

Ancora più importante, poiché gli handle vengono riciclati frequentemente in Windows, è possibile che un handle venga riciclato e punti a un'altra risorsa contenente dati sensibili. Questo comportamento è noto come attacco basato sul riciclaggio e può danneggiare potenzialmente i dati e rappresentare una minaccia alla sicurezza.

A partire da .NET Framework 2.0, la classe SafeHandle semplifica molti di questi problemi di durata degli oggetti e viene integrata con pInvoke in modo da evitare perdite delle risorse del sistema operativo. La classe SafeHandle risolve i problemi di durata degli oggetti assegnando e rilasciando handle senza interruzione. In essa è contenuto un finalizzatore critico che verifica che l'handle sia chiuso e ne garantisce l'esecuzione durante gli scaricamenti AppDomain, anche nei casi in cui si presuppone che la chiamata pInvoke sia in uno stato danneggiato.

Poiché la classe SafeHandle eredita dalla classe CriticalFinalizerObject, tutti i finalizzatori non critici vengono chiamati prima di eventuali finalizzatori critici. I finalizzatori vengono chiamati su oggetti non più attivi durante lo stesso passaggio della Garbage Collection. Un oggetto FileStream ad esempio può eseguire un finalizzatore normale per rimuovere i dati memorizzati nel buffer senza il rischio che l'handle vada perduto o venga riciclato. Questo ordinamento tra finalizzatori critici e non critici non è stato ideato per un utilizzo generale. Lo scopo principale è quello di fornire assistenza nella migrazione di librerie esistenti consentendo a tali librerie di utilizzare la classe SafeHandle senza modificare la semantica. Il finalizzatore critico e gli oggetti da esso chiamati, ad esempio il metodo SafeHandle.ReleaseHandle(), devono inoltre essere contenuti in un'area di esecuzione vincolata. In questo modo vengono imposti vincoli sul codice che è possibile scrivere nell'ambito del grafico chiamate del finalizzatore.

A partire da .NET Framework versione 2.0, le operazioni pInvoke incrementano automaticamente il numero dei riferimenti degli handle incapsulati da una classe SafeHandle e riducono tale numero dopo il completamento. In questo modo si evita che l'handle venga riciclato o chiuso in modo imprevisto.

È possibile specificare la proprietà dell'handle sottostante durante la costruzione di oggetti SafeHandle. In questo modo è possibile definire se l'oggetto SafeHandle rilascerà l'handle dopo l'eliminazione. Questa soluzione si rivela utile per gli handle con requisiti di durata particolari o per l'utilizzo di un handle la cui durata è controllata da altri fattori.

Nello spazio dei nomi Microsoft.Win32.SafeHandles sono contenute classi che derivano dalla classe SafeHandle per fornire funzionalità che supportano handle di file e del sistema operativo. Nella tabella riportata di seguito vengono riepilogate le classi di handle protetti di .NET Framework.

Classe

Descrizione

SafeHandle

Esegue il wrapping di un handle per operazioni pInvoke garantendo la finalizzazione senza interruzione. La classe deve essere ereditata.

SafeFileHandle

Fornisce l'accesso a handle di file non gestiti.

SafeWaitHandle

Fornisce l'accesso a handle di attesa non gestiti.

SafeHandleMinusOneIsInvalid

e

SafeHandleZeroOrMinusOneIsInvalid

Consente di creare una classe di handle protetti personalizzata.

Aggiunte alla community

Mostra: