releaseHandleFailed (MDA)releaseHandleFailed MDA

L'Assistant Débogage managé (MDA) releaseHandleFailed est activé pour avertir les développeurs que la méthode ReleaseHandle d'une classe dérivée de SafeHandle ou de CriticalHandle retourne la valeur false.The releaseHandleFailed managed debugging assistant (MDA) is activated is to notify developers when the ReleaseHandle method of a class derived from SafeHandle or CriticalHandle returns false.

SymptômesSymptoms

Fuites de ressources ou de mémoire.Resource or memory leaks. Si la méthode ReleaseHandle de la classe dérivée de SafeHandle ou de CriticalHandle échoue, il est possible que la ressource encapsulée par la classe n'ait pas pu être libérée ou nettoyée.If the ReleaseHandle method of the class deriving from SafeHandle or CriticalHandle fails, then the resource encapsulated by the class might not have been released or cleaned up.

CauseCause

Les utilisateurs doivent fournir l'implémentation de la méthode ReleaseHandle s'ils créent des classes qui dérivent de SafeHandle ou de CriticalHandle. Les circonstances sont donc spécifiques à chaque ressource.Users must provide the implementation of the ReleaseHandle method if they create classes that derive from SafeHandle or CriticalHandle; thus, the circumstances are specific to the individual resource. Toutefois, il existe certaines exigences :However, the requirements are as follows:

  • Les types SafeHandle et CriticalHandle représentent des wrappers autour de ressources de processus essentielles.SafeHandle and CriticalHandle types represent wrappers around vital process resources. Une fuite de mémoire finirait par rendre le processus inutilisable.A memory leak would make the process unusable over time.

  • La méthode ReleaseHandle ne doit pas échouer dans l'exécution de sa fonction.The ReleaseHandle method must not fail to perform its function. Une ressource acquise par le processus ne peut être libérée qu’avec la méthode ReleaseHandle.Once the process acquires such a resource, ReleaseHandle is the only way to release it. C'est pourquoi un échec de la méthode entraîne une fuite de ressource.Therefore, failure implies resource leaks.

  • Un échec survenant pendant l’exécution de la méthode ReleaseHandle empêche la libération de la ressource, et constitue un bogue dans l’implémentation de la méthode ReleaseHandle elle-même.Any failure that does occur during the execution of ReleaseHandle, impeding the release of the resource, is a bug in the implementation of the ReleaseHandle method itself. C'est au programmeur qu'il revient de s'assurer que le contrat est respecté, même si ce code appelle du code créé par un autre utilisateur pour exécuter sa fonction.It is the responsibility of the programmer to ensure that the contract is fulfilled, even if that code calls code authored by someone else to perform its function.

Résolution :Resolution

Passez en revue le code utilisant le type SafeHandle (ou CriticalHandle) spécifique qui a déclenché la notification de l’Assistant Débogage managé et recherchez les endroits où la valeur du handle brut est extraite de SafeHandle et copiée ailleurs.The code that uses the specific SafeHandle (or CriticalHandle) type that raised the MDA notification should be reviewed, looking for places where the raw handle value is extracted from the SafeHandle and copied elsewhere. C'est la cause de la plupart des échecs dans les implémentations de SafeHandle ou de CriticalHandle, car le runtime n'effectue plus de suivi de l'utilisation de la valeur du handle brut.This is the usual cause of failures within SafeHandle or CriticalHandle implementations, because the usage of the raw handle value is then no longer tracked by the runtime. Si la copie du handle brut est fermée par la suite, cela peut provoquer l'échec d'un appel ultérieur à ReleaseHandle, car c'est le même handle, désormais non valide, qui fait l'objet d'une tentative de fermeture.If the raw handle copy is subsequently closed, it can cause a later ReleaseHandle call to fail because the close is attempted on the same handle, which is now invalid.

Une duplication de handle incorrecte peut se produire dans plusieurs cas :There are a number of ways in which incorrect handle duplication can occur:

  • Recherchez d'éventuels appels à la méthode DangerousGetHandle.Look for calls to the DangerousGetHandle method. Les appels à cette méthode doivent être extrêmement rares et, s'il y en a, ils doivent être entourés d'appels aux méthodes DangerousAddRef et DangerousRelease.Calls to this method should be exceedingly rare, and any that you find should be surrounded by calls to the DangerousAddRef and DangerousRelease methods. Ces dernières spécifient la partie du code où la valeur du handle brut peut être utilisée en toute sécurité.These latter methods specify the region of code in which the raw handle value may be safely used. En dehors de cette partie, ou si le nombre de références n'est jamais incrémenté initialement, la valeur du handle peut être invalidée à tout moment par un appel à Dispose ou Close sur un autre thread.Outside this region, or if the reference count is never incremented in the first place, the handle value can be invalidated at any time by a call to Dispose or Close on another thread. Dès que toutes les utilisations de DangerousGetHandle ont été localisées, vous devez suivre le chemin d’accès emprunté par le handle brut pour vous assurer qu’il n’est pas remis à un composant quelconque qui finira par appeler CloseHandle ou une autre méthode native de niveau inférieur qui libérera le handle.Once all uses of DangerousGetHandle have been tracked down, you should follow the path the raw handle takes to ensure it is not handed off to some component that will eventually call CloseHandle or another low-level native method that will release the handle.

  • Assurez-vous que le code utilisé pour initialiser SafeHandle avec une valeur de handle brut valide est propriétaire du handle.Ensure that the code that is used to initialize the SafeHandle with a valid raw handle value owns the handle. Si vous formez SafeHandle autour d'un handle non détenu par votre code sans affecter au paramètre ownsHandle la valeur false dans le constructeur de base, alors SafeHandle et le véritable propriétaire du handle peuvent tenter de fermer le handle, ce qui se traduit par une erreur dans ReleaseHandle si SafeHandle n'y accède pas en premier.If you form a SafeHandle around a handle your code does not own without setting the ownsHandle parameter to false in the base constructor, then both the SafeHandle and the real handle owner can try to close the handle, leading to an error in ReleaseHandle if the SafeHandle loses the race.

  • Si SafeHandle est marshalé entre des domaines d’application, vérifiez si la dérivation de SafeHandle utilisée a été marquée comme étant sérialisable.When a SafeHandle is marshaled between application domains, confirm the SafeHandle derivation being used has been marked as serializable. Dans les rares cas où une classe dérivée de SafeHandle est devenue sérialisable, elle doit implémenter l’interface ISerializable ou utiliser l’une des autres techniques permettant de contrôler manuellement le processus de sérialisation et de désérialisation.In the rare cases where a class derived from SafeHandle has been made serializable, it should implement the ISerializable interface or use one of the other techniques for controlling the serialization and deserialization process manually. C'est indispensable dans la mesure où l'action de sérialisation par défaut consiste à créer un clone de bits de la valeur du handle brut incluse et se traduit donc par la présence de deux instances de SafeHandle qui se considèrent toutes deux propriétaires du même handle.This is required because the default serialization action is to create a bitwise clone of the enclosed raw handle value, resulting in two SafeHandle instances thinking they own the same handle. Ces deux instances tenteront d'appeler ReleaseHandle sur le même handle à un moment donné.Both will try to call ReleaseHandle on the same handle at some point. Le deuxième SafeHandle à le faire échouera.The second SafeHandle to do this will fail. Quand vous sérialisez SafeHandle, la solution appropriée consiste à appeler la fonction DuplicateHandle ou une fonction similaire pour votre type de handle natif pour effectuer une copie de handle légale distincte.The correct course of action when serializing a SafeHandle is to call the DuplicateHandle function or a similar function for your native handle type to make a distinct legal handle copy. Si votre type de handle ne prend pas en charge cette opération, le type SafeHandle qui l'encapsule ne peut pas devenir sérialisable.If your handle type does not support this then the SafeHandle type wrapping it cannot be made serializable.

  • Il est parfois possible d’identifier la partie où un handle est fermé de façon anticipée (ce qui se traduit par un échec quand la méthode ReleaseHandle est finalement appelée). Pour cela, vous devez placer un point d’arrêt de débogueur sur la routine native utilisée pour libérer le handle, par exemple la fonction CloseHandle.It may be possible to track where a handle is being closed early, leading to a failure when the ReleaseHandle method is finally called, by placing a debugger breakpoint on the native routine used to release the handle, for example the CloseHandle function. Ce n'est pas toujours possible dans les scénarios de tests de contraintes, voire dans les tests fonctionnels de taille moyenne, en raison du trafic important généralement associé à de telles routines.This may not be possible for stress scenarios or even medium-sized functional tests due to the heavy traffic such routines often deal with. Il peut être utile d’instrumenter le code qui appelle la méthode de libération native, afin de capturer l’identité de l’appelant, ou éventuellement une trace de la pile complète, ainsi que la valeur du handle libéré.It may help to instrument the code that calls the native release method, in order to capture the identity of the caller, or possibly a full stack trace, and the value of the handle being released. La valeur du handle peut être comparée à la valeur transmise par cet Assistant Débogage managé.The handle value can be compared with the value reported by this MDA.

  • Notez que certains types de handle natifs, et notamment tous les handles Win32 qui peuvent être libérés via la fonction CloseHandle, partagent le même espace de noms de handles.Note that some native handle types, such as all the Win32 handles that can be released via the CloseHandle function, share the same handle namespace. Une mise en production incorrecte d’un type de handle peut provoquer des problèmes avec un autre.An erroneous release of one handle type can cause problems with another. Par exemple, fermer accidentellement deux fois un handle d'événement Win32 peut provoquer la fermeture prématurée d'un handle de fichier apparemment non lié.For instance, accidentally closing a Win32 event handle twice might lead to an apparently unrelated file handle being closed prematurely. Cela se produit quand le handle est libéré et que la valeur du handle redevient disponible pour le suivi d’une autre ressource, parfois d’un autre type.This happens when the handle is released and the handle value becomes available for use to track another resource, potentially of another type. Si cette libération est suivie d'une deuxième libération erronée, le handle d'un thread non lié risque d'être invalidé.If this happens and is followed by an erroneous second release, the handle of an unrelated thread might be invalidated.

Effet sur le runtimeEffect on the Runtime

Cet Assistant Débogage managé n'a aucun effet sur le CLR.This MDA has no effect on the CLR.

SortieOutput

Message indiquant qu’un SafeHandle ou un CriticalHandle n’a pas réussi à libérer correctement le handle.A message indicating that a SafeHandle or a CriticalHandle failed to properly release the handle. Par exemple :For example:

"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."  

ConfigurationConfiguration

<mdaConfig>  
  <assistants>  
    <releaseHandleFailed/>  
  </assistants>  
</mdaConfig>  

ExempleExample

L'exemple de code suivant peut activer l'Assistant Débogage managé releaseHandleFailed.The following is a code example that can activate the releaseHandleFailed MDA.

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);  
}  

Voir aussiSee also