releaseHandleFailed MDA
Kommentar
Den här artikeln är specifik för .NET Framework. Det gäller inte för nyare implementeringar av .NET, inklusive .NET 6 och senare versioner.
Den releaseHandleFailed
hanterade felsökningsassistenten (MDA) aktiveras är att meddela utvecklare när ReleaseHandle metoden för en klass som härleds från SafeHandle eller CriticalHandle returnerar false
.
Symtom
Resurs- eller minnesläckor. ReleaseHandle Om metoden för klassen som härleds från SafeHandle eller CriticalHandle misslyckas kanske resursen som kapslas in av klassen inte har släppts eller rensats.
Orsak
Användarna måste tillhandahålla implementeringen av ReleaseHandle metoden om de skapar klasser som härleds från SafeHandle eller CriticalHandle. Därför är omständigheterna specifika för den enskilda resursen. Kraven är dock följande:
SafeHandle och CriticalHandle typer representerar omslutningar kring viktiga processresurser. En minnesläcka skulle göra processen oanvändbar över tid.
Metoden ReleaseHandle får inte misslyckas med att utföra sin funktion. När processen har hämtat en sådan resurs ReleaseHandle är det enda sättet att frigöra den. Felet innebär därför resursläckor.
Alla fel som inträffar under körningen av ReleaseHandle, vilket hindrar versionen av resursen, är en bugg i implementeringen av ReleaseHandle själva metoden. Det är programmerarens ansvar att se till att avtalet uppfylls, även om koden anropar kod som någon annan har skapat för att utföra sin funktion.
Åtgärd
Den kod som använder den specifika SafeHandle (eller CriticalHandle) typ som utlöste MDA-meddelandet bör granskas och leta efter platser där raw-referensvärdet extraheras från SafeHandle och kopieras någon annanstans. Detta är den vanliga orsaken till fel inom SafeHandle eller CriticalHandle implementeringar, eftersom användningen av råreferensvärdet sedan inte längre spåras av körningen. Om den råa referenskopian därefter stängs kan det leda till att ett senare ReleaseHandle anrop misslyckas eftersom stängningen görs på samma handtag, vilket nu är ogiltigt.
Det finns ett antal sätt på vilka felaktig handtagsduplicering kan inträffa:
Leta efter anrop till DangerousGetHandle metoden. Anrop till den här metoden bör vara ytterst sällsynta, och alla som du hittar bör omges av anrop till DangerousAddRef metoderna och DangerousRelease . Dessa senare metoder anger den region med kod där råreferensvärdet kan användas på ett säkert sätt. Utanför den här regionen, eller om referensantalet aldrig ökar i första hand, kan referensvärdet när som helst ogiltigförklaras av ett anrop till Dispose eller Close på en annan tråd. När alla användningsområden DangerousGetHandle för har spårats bör du följa den sökväg som det råa handtaget tar för att se till att det inte överlämnas till någon komponent som så småningom anropar
CloseHandle
eller någon annan intern metod på låg nivå som släpper handtaget.Kontrollera att den kod som används för att initiera SafeHandle med ett giltigt raw handle-värde äger handtaget. Om du skapar en SafeHandle runt en referens som koden inte äger utan att ange parametern
ownsHandle
tillfalse
i baskonstruktorn, kan både den SafeHandle och den verkliga handtagets ägare försöka stänga handtaget, vilket leder till ett fel i ReleaseHandle om SafeHandle loppet förlorar.När en SafeHandle är mellan programdomäner bekräftar du att den SafeHandle härledning som används har markerats som serialiserbar. I de sällsynta fall där en klass som härletts från SafeHandle har gjorts serialiserbar bör den ISerializable implementera gränssnittet eller använda någon av de andra teknikerna för att styra serialiserings- och deserialiseringsprocessen manuellt. Detta krävs eftersom standard serialiseringsåtgärden är att skapa en bitvis klon av det omslutna råhandtagsvärdet, vilket resulterar i att två SafeHandle instanser tror att de äger samma handtag. Båda försöker anropa ReleaseHandle på samma handtag någon gång. Det andra SafeHandle att göra detta misslyckas. Rätt åtgärdssätt när du serialiserar en SafeHandle är att anropa
DuplicateHandle
funktionen eller en liknande funktion för din interna referenstyp för att göra en distinkt kopia av det juridiska handtaget. Om din referenstyp inte stöder detta kan inte typomslutningen SafeHandle göras serialiserbar.Det kan vara möjligt att spåra var ett handtag stängs tidigt, vilket leder till ett fel när ReleaseHandle metoden slutligen anropas, genom att placera en brytpunkt för felsökningsprogrammet på den interna rutin som används för att frigöra handtaget, till exempel
CloseHandle
funktionen. Detta kanske inte är möjligt för stressscenarier eller till och med medelstora funktionella tester på grund av den tunga trafik som sådana rutiner ofta hanterar. Det kan hjälpa till att instrumentera koden som anropar den interna versionsmetoden, för att fånga upp anroparens identitet eller eventuellt en fullständig stackspårning och värdet för handtaget som släpps. Referensvärdet kan jämföras med det värde som rapporteras av denna MDA.Observera att vissa interna referenstyper, till exempel alla Win32-referenser som kan släppas via
CloseHandle
funktionen, delar samma referensnamnområde. En felaktig version av en referenstyp kan orsaka problem med en annan. Till exempel kan oavsiktligt stänga ett Win32-händelsehandtag två gånger leda till att ett till synes orelaterat filhandtag stängs i förtid. Detta inträffar när handtaget släpps och referensvärdet blir tillgängligt för användning för att spåra en annan resurs, eventuellt av en annan typ. Om detta händer och följs av en felaktig andra version kan handtaget för en orelaterad tråd ogiltigförklaras.
Effekt på körningen
Denna MDA har ingen effekt på CLR.
Output
Ett meddelande som anger att en SafeHandle eller en CriticalHandle inte kunde släppa handtaget korrekt. Till exempel:
"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>
Exempel
Följande är ett kodexempel som kan aktivera 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);
}