releaseHandleFailed MDA

Note

Dieser Artikel ist spezifisch für .NET Framework. Sie gilt nicht für neuere Implementierungen von .NET, einschließlich .NET 6 und höherer Versionen.

Der releaseHandleFailed verwaltete Debugging-Assistent (Managed Debugging Assistant, MDA) wird aktiviert, um Entwickler zu benachrichtigen, wenn die ReleaseHandle Methode einer von oder CriticalHandle zurück falseabgeleiteten Klasse zurückgegeben wirdSafeHandle.

Symptome

Ressourcen- oder Speicherverluste. Wenn die ReleaseHandle Methode der Klasse, die von SafeHandle der Klasse abgeleitet wird oder CriticalHandle fehlschlägt, wurde die von der Klasse gekapselte Ressource möglicherweise nicht freigegeben oder bereinigt.

Ursache

Benutzer müssen die Implementierung der ReleaseHandle Methode bereitstellen, wenn sie Klassen erstellen, die von SafeHandle oder CriticalHandle; daher sind die Umstände für die einzelne Ressource spezifisch. Die Anforderungen sind jedoch wie folgt:

  • SafeHandle und CriticalHandle Typen stellen Wrapper um wichtige Prozessressourcen dar. Ein Speicherverlust würde den Prozess im Laufe der Zeit unbrauchbar machen.

  • Die ReleaseHandle Methode darf ihre Funktion nicht ausführen. Sobald der Prozess eine solche Ressource erwirbt, ist die einzige Möglichkeit, ReleaseHandle ihn freizugeben. Daher impliziert ein Fehler Ressourcenlecks.

  • Jeder Fehler, der während der Ausführung ReleaseHandleder Veröffentlichung der Ressource auftritt, ist ein Fehler bei der Implementierung der ReleaseHandle Methode selbst. Es liegt in der Verantwortung des Programmierers, sicherzustellen, dass der Vertrag erfüllt ist, auch wenn dieser Code code aufruft, der von einer anderen Person erstellt wurde, um seine Funktion auszuführen.

Auflösung

Der Code, der den spezifischen SafeHandle (oder CriticalHandle) Typ verwendet, der die MDA-Benachrichtigung ausgelöst hat, sollte überprüft werden, und sucht nach Orten, an denen der Unformatierte Handle-Wert aus dem SafeHandle andernfalls extrahiert und kopiert wird. Dies ist die übliche Ursache für Fehler innerhalb SafeHandle oder CriticalHandle Implementierungen, da die Verwendung des Unformatierten Handle-Werts dann nicht mehr von der Laufzeit nachverfolgt wird. Wenn die Kopie des unformatierten Handles anschließend geschlossen wird, kann ein späterer ReleaseHandle Aufruf fehlschlagen, da beim Schließen auf demselben Handle versucht wird, das jetzt ungültig ist.

Es gibt eine Reihe von Möglichkeiten, um die Duplizierung falsch zu behandeln:

  • Suchen Sie nach Aufrufen der DangerousGetHandle Methode. Aufrufe dieser Methode sollten äußerst selten sein, und alle, die Sie finden, sollten von Aufrufen der DangerousAddRef Methoden DangerousRelease umgeben sein. Diese beiden Methoden geben den Codebereich an, in dem der Unformatierte Handlewert möglicherweise sicher verwendet werden kann. Außerhalb dieses Bereichs oder wenn die Bezugsanzahl nie an erster Stelle erhöht wird, kann der Handle-Wert jederzeit durch einen Aufruf von Dispose oder Close in einem anderen Thread ungültig werden. Nachdem alle Verwendungen DangerousGetHandle nachverfolgt wurden, sollten Sie dem Pfad folgen, den der unformatierte Handle verwendet, um sicherzustellen, dass es nicht an eine Komponente übergeben wird, die schließlich aufruft CloseHandle oder eine andere systemeigene Methode auf niedriger Ebene, die das Handle freigeben wird.

  • Stellen Sie sicher, dass der Code, der zum Initialisieren des SafeHandle Codes mit einem gültigen unformatierten Handlewert verwendet wird, dem Handle gehört. Wenn Sie einen Umschlag bilden SafeHandle , besitzt Ihr Code nicht, ohne den ownsHandle Parameter im Basiskonstruktor festzulegen false , kann sowohl der SafeHandle besitzer des tatsächlichen Handles versuchen, den Handle zu schließen, was zu einem Fehler ReleaseHandle führt, wenn das SafeHandle Rennen verloren geht.

  • Wenn ein SafeHandle Marshall zwischen Anwendungsdomänen erfolgt, bestätigen Sie, dass die SafeHandle verwendete Ableitung als serialisierbar markiert wurde. In den seltenen Fällen, in denen eine von SafeHandle einer abgeleiteten Klasse serialisierbar gemacht wurde, sollte sie die ISerializable Schnittstelle implementieren oder eine der anderen Techniken zum manuellen Steuern der Serialisierung und Deserialisierung verwenden. Dies ist erforderlich, da die Standard serialisierungsaktion darin besteht, einen bitweisen Klon des eingeschlossenen Unformatierten Handlewerts zu erstellen, was dazu führt, dass zwei SafeHandle Instanzen denken, dass sie dasselbe Handle besitzen. Beide versuchen, an einem bestimmten Punkt den gleichen Handle anzurufen ReleaseHandle . Die zweite SafeHandle zu diesem Vorgang schlägt fehl. Der richtige Vorgangsverlauf beim Serialisieren ist SafeHandle das Aufrufen der DuplicateHandle Funktion oder einer ähnlichen Funktion für den systemeigenen Handletyp, um eine unterschiedliche Kopie des rechtsrechtlichen Handles zu erstellen. Wenn der Handletyp dies nicht unterstützt, kann der SafeHandle Typumbruch nicht serialisiert werden.

  • Es kann möglich sein, zu verfolgen, wo ein Handle frühzeitig geschlossen wird, was zu einem Fehler führt, wenn die ReleaseHandle Methode schließlich aufgerufen wird, indem ein Debugger-Haltepunkt in der systemeigenen Routine platziert wird, die zum Freigeben des Handles verwendet wird, z. B. die CloseHandle Funktion. Dies ist möglicherweise nicht möglich für Stressszenarien oder sogar mittelgroße Funktionstests aufgrund des schweren Verkehrs, mit denen solche Routinen häufig umgehen. Es kann hilfreich sein, den Code zu instrumentieren, der die systemeigene Releasemethode aufruft, um die Identität des Aufrufers oder möglicherweise eine vollständige Stapelablaufverfolgung und den Wert des losgelassenen Handles zu erfassen. Der Handlewert kann mit dem von dieser MDA gemeldeten Wert verglichen werden.

  • Beachten Sie, dass einige systemeigene Handletypen, z. B. alle Win32-Handles, die über die CloseHandle Funktion freigegeben werden können, denselben Handle-Namespace gemeinsam nutzen. Eine fehlerhafte Freigabe eines Handle-Typs kann Zu Problemen mit einem anderen führen. Das versehentliche Schließen eines Win32-Ereignishandles kann beispielsweise dazu führen, dass ein scheinbar nicht verknüpfter Dateihandle vorzeitig geschlossen wird. Dies geschieht, wenn das Handle freigegeben wird und der Handle-Wert für die Verwendung zur Nachverfolgung einer anderen Ressource verfügbar wird, möglicherweise von einem anderen Typ. Wenn dies geschieht und auf eine fehlerhafte zweite Version folgt, kann der Handle eines nicht verknüpften Threads ungültig werden.

Effekt auf die Laufzeit

Diese MDA hat keine Auswirkungen auf die CLR.

Output

Eine Meldung, die angibt, dass ein SafeHandle oder ein CriticalHandle Fehler beim ordnungsgemäßen Freigeben des Handles aufgetreten ist. Beispiel:

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

Konfiguration

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

Example

Es folgt ein Codebeispiel, das die releaseHandleFailed MDA aktivieren kann.

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

Siehe auch