Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Note
Questo articolo è specifico per .NET Framework. Non si applica alle implementazioni più recenti di .NET, tra cui .NET 6 e versioni successive.
L'assistente releaseHandleFailed al debug gestito viene attivato per notificare agli sviluppatori quando il ReleaseHandle metodo di una classe derivata da SafeHandle o CriticalHandle restituisce false.
Symptoms
Perdite di risorse o di memoria. Se il ReleaseHandle metodo della classe derivata da SafeHandle o CriticalHandle ha esito negativo, la risorsa incapsulata dalla classe potrebbe non essere stata rilasciata o pulita.
Cause
Gli utenti devono fornire l'implementazione del ReleaseHandle metodo se creano classi che derivano da SafeHandle o CriticalHandle, pertanto le circostanze sono specifiche della singola risorsa. Tuttavia, i requisiti sono i seguenti:
SafeHandle i tipi e CriticalHandle rappresentano wrapper per le risorse di processo vitali. Una perdita di memoria renderebbe il processo inutilizzabile nel tempo.
Il ReleaseHandle metodo non deve non riuscire a eseguire la relativa funzione. Dopo che il processo acquisisce tale risorsa, ReleaseHandle è l'unico modo per rilasciarlo. Pertanto, l'errore implica perdite di risorse.
Qualsiasi errore che si verifica durante l'esecuzione di ReleaseHandle, impedendo il rilascio della risorsa, è un bug nell'implementazione del ReleaseHandle metodo stesso. È responsabilità del programmatore assicurarsi che il contratto venga soddisfatto, anche se tale codice chiama il codice creato da un altro utente per eseguire la sua funzione.
Risoluzione
Il codice che usa il tipo specifico SafeHandle (o CriticalHandle) che ha generato la notifica MDA deve essere esaminato, cercando le posizioni in cui il valore dell'handle SafeHandle non elaborato viene estratto da e copiato altrove. Questa è la causa consueta di errori all'interno SafeHandle o CriticalHandle alle implementazioni, perché l'utilizzo del valore dell'handle non elaborato non viene più rilevato dal runtime. Se la copia dell'handle non elaborato viene successivamente chiusa, può causare l'esito negativo di una chiamata successiva ReleaseHandle perché la chiusura viene tentata sullo stesso handle, che ora non è valida.
Esistono diversi modi in cui può verificarsi la duplicazione di handle non corretta:
Cercare le chiamate al DangerousGetHandle metodo . Le chiamate a questo metodo devono essere estremamente rare e tutte le chiamate ai DangerousAddRef metodi e DangerousRelease . Questi ultimi metodi specificano l'area di codice in cui il valore dell'handle non elaborato può essere usato in modo sicuro. All'esterno di questa area o se il conteggio dei riferimenti non viene mai incrementato al primo posto, il valore dell'handle può essere invalidato in qualsiasi momento da una chiamata a Dispose o Close su un altro thread. Dopo che tutti gli usi di DangerousGetHandle sono stati rilevati, è necessario seguire il percorso usato dall'handle non elaborato per assicurarsi che non venga passato a un componente che alla fine chiamerà o un altro metodo nativo di basso livello che rilascerà
CloseHandlel'handle.Assicurarsi che il codice usato per inizializzare SafeHandle con un handle non elaborato valido sia proprietario dell'handle. Se si forma un oggetto intorno a un SafeHandle handle il codice non è proprietario senza impostare il
ownsHandleparametro sufalsenel costruttore di base, sia il SafeHandle proprietario dell'handle reale che quello reale possono tentare di chiudere l'handle, causando un errore in ReleaseHandle se perde SafeHandle la gara.Quando un SafeHandle oggetto viene sottoposto a marshalling tra domini applicazione, verificare che la SafeHandle derivazione usata sia stata contrassegnata come serializzabile. Nei rari casi in cui una classe derivata da SafeHandle è stata resa serializzabile, deve implementare l'interfaccia ISerializable o usare una delle altre tecniche per controllare manualmente il processo di serializzazione e deserializzazione. Questa operazione è necessaria perché l'azione di serializzazione predefinita consiste nel creare un clone bit per bit del valore dell'handle non elaborato racchiuso, generando due SafeHandle istanze che pensano di essere proprietari dello stesso handle. Entrambi tenteranno di chiamare ReleaseHandle sullo stesso handle a un certo punto. Il secondo SafeHandle a tale scopo avrà esito negativo. L'azione corretta quando si serializza un SafeHandle oggetto consiste nel chiamare la
DuplicateHandlefunzione o una funzione simile per il tipo di handle nativo per creare una copia di handle legale distinta. Se il tipo di handle non supporta questa operazione, il wrapping del SafeHandle tipo non può essere reso serializzabile.Può essere possibile tenere traccia della chiusura anticipata di un handle, causando un errore quando il ReleaseHandle metodo viene infine chiamato, inserendo un punto di interruzione del debugger nella routine nativa usata per rilasciare l'handle, ad esempio la
CloseHandlefunzione . Questo potrebbe non essere possibile per scenari di stress o anche test funzionali di medie dimensioni a causa del traffico pesante che spesso si occupano di tali routine. Può essere utile instrumentare il codice che chiama il metodo di rilascio nativo, per acquisire l'identità del chiamante o eventualmente un'analisi dello stack completo e il valore dell'handle rilasciato. Il valore dell'handle può essere confrontato con il valore segnalato da questo assistente al debug gestito.Si noti che alcuni tipi di handle nativi, ad esempio tutti gli handle Win32 che possono essere rilasciati tramite la
CloseHandlefunzione, condividono lo stesso spazio dei nomi handle. Una versione errata di un tipo di handle può causare problemi con un altro. Ad esempio, la chiusura accidentale di un handle di eventi Win32 due volte può causare la chiusura prematura di un handle di file apparentemente non correlato. Ciò si verifica quando l'handle viene rilasciato e il valore dell'handle diventa disponibile per l'uso per tenere traccia di un'altra risorsa, potenzialmente di un altro tipo. Se ciò si verifica e viene seguito da una seconda versione errata, l'handle di un thread non correlato potrebbe essere invalidato.
Effetto sul runtime
Questo assistente al debug gestito non ha alcun effetto su CLR.
Risultato
Messaggio che indica che un SafeHandle oggetto o non CriticalHandle è riuscito a rilasciare correttamente l'handle. Per esempio:
"A SafeHandle or CriticalHandle of type 'MyBrokenSafeHandle'
failed to properly release the handle with value 0x0000BEEF. This
usually indicates that the handle was released incorrectly via
another means (such as extracting the handle using DangerousGetHandle
and closing it directly or building another SafeHandle around it."
Configuration
<mdaConfig>
<assistants>
<releaseHandleFailed/>
</assistants>
</mdaConfig>
Example
Di seguito è riportato un esempio di codice che può attivare l'assistente al debug gestito releaseHandleFailed .
bool ReleaseHandle()
{
// Calling the Win32 CloseHandle function to release the
// native handle wrapped by this SafeHandle. This method returns
// false on failure, but should only fail if the input is invalid
// (which should not happen here). The method specifically must not
// fail simply because of lack of resources or other transient
// failures beyond the user’s control. That would make it unacceptable
// to call CloseHandle as part of the implementation of this method.
return CloseHandle(handle);
}