Sdílet prostřednictvím


releaseHandleFailed – pomocník spravovaného ladění (MDA)

Poznámka:

Tento článek je specifický pro rozhraní .NET Framework. Nevztahuje se na novější implementace .NET, včetně .NET 6 a novějších verzí.

Pomocník releaseHandleFailed pro spravované ladění (MDA) je aktivován, je upozornit vývojáře, když ReleaseHandle metoda třídy odvozená z SafeHandle nebo CriticalHandle vrací false.

Příznaky

Nevracení prostředků nebo paměti ReleaseHandle Pokud metoda třídy odvozená z SafeHandle nebo CriticalHandle selže, pak prostředek zapouzdřený třídou nebyl uvolněn nebo vyčištěn.

Příčina

Uživatelé musí poskytnout implementaci ReleaseHandle metody, pokud vytvářejí třídy, které jsou odvozeny z SafeHandle , CriticalHandlea proto jsou okolnosti specifické pro jednotlivé prostředky. Požadavky jsou však následující:

  • SafeHandle a CriticalHandle typy představují obálky kolem důležitých procesních prostředků. Nevracení paměti by v průběhu času zneužitelného procesu.

  • Metoda ReleaseHandle nesmí selhat provést svou funkci. Jakmile tento proces takový prostředek získá, je jediným způsobem, ReleaseHandle jak ho uvolnit. Proto selhání znamená únik prostředků.

  • Jakékoli selhání, ke kterému dochází během provádění ReleaseHandle, impeding uvolnění prostředku, je chyba v implementaci ReleaseHandle samotné metody. Je zodpovědností programátora zajistit, aby smlouva byla splněna, i když tento kód volá kód vytvořený někým jiným, aby provedl jeho funkci.

Rozlišení

Je třeba zkontrolovat kód, který používá konkrétní SafeHandle (nebo CriticalHandle) typ, který vyvolal oznámení MDA, a hledat místa, kde se nezpracovaná hodnota popisovače extrahuje z SafeHandle a zkopíruje jinde. Jedná se o obvyklou příčinu selhání v rámci SafeHandle implementací, CriticalHandle protože použití nezpracované hodnoty popisovače už modul runtime nesleduje. Pokud je nezpracovaná kopie popisovače následně uzavřena, může dojít k selhání pozdějšího ReleaseHandle volání, protože zavření se pokusí na stejném popisovači, což je nyní neplatné.

Existuje řada způsobů, jak může dojít k nesprávnému zpracování duplicit:

  • Vyhledejte volání metody DangerousGetHandle . Volání této metody by měla být mimořádně vzácná a všechny nalezené metody by měly být obklopeny voláními DangerousAddRef metod a DangerousRelease metod. Tyto druhé metody určují oblast kódu, ve které může být hodnota nezpracovaného popisovače bezpečně použita. Mimo tuto oblast nebo pokud se počet odkazů nikdy nezvýšil na prvním místě, je možné hodnotu popisovače kdykoli zneplatnit voláním Dispose nebo Close v jiném vlákně. Jakmile budou všechny použití DangerousGetHandle sledovány, měli byste postupovat podle cesty, kterou nezpracovaný popisovač vezme, aby se zajistilo, že se nepředá některé komponentě, která nakonec zavolá CloseHandle nebo jinou nativní metodu nízké úrovně, která uvolní popisovač.

  • Ujistěte se, že kód, který se používá k inicializaci SafeHandle s platnou hodnotou nezpracovaného popisovače, vlastní popisovač. Pokud vytvoříte SafeHandle popisovač, který váš kód nevlastní bez nastavení ownsHandle parametru false v základním konstruktoru, pak se SafeHandle vlastník i skutečný popisovač může pokusit zavřít popisovač, což vede k chybě v ReleaseHandle případě ztráty závodu SafeHandle .

  • SafeHandle Pokud je mezi doménami aplikace zařazován, ověřte, že SafeHandle použité odvození bylo označeno jako serializovatelné. Ve výjimečných případech, kdy byla třída odvozena ze SafeHandle serializovatelné, by měla implementovat ISerializable rozhraní nebo použít jednu z dalších technik pro řízení serializace a deserializační proces ručně. To je povinné, protože výchozí akcí serializace je vytvoření bitové klony uzavřené nezpracované hodnoty popisovače, což vede ke dvěma SafeHandle instancím, které si myslí, že vlastní stejný popisovač. Oba se pokusí zavolat ReleaseHandle na stejný popisovač v určitém okamžiku. SafeHandle Druhý postup se nezdaří. Správný postup při serializaci SafeHandle je volání DuplicateHandle funkce nebo podobné funkce pro váš nativní typ popisovače, aby se zkopírovala odlišná právní popisovač. Pokud typ popisovače tuto možnost nepodporuje, SafeHandle nelze jej zabalit jako serializovatelný.

  • Může být možné sledovat, kde je popisovač uzavřen dříve, což vede k selhání, když ReleaseHandle je metoda nakonec volána, umístěním zarážky ladicího programu na nativní rutinu použitou k uvolnění popisovače, například CloseHandle funkce. To nemusí být možné pro stresové scénáře nebo dokonce středně velké funkční testy kvůli náročnému provozu, se kterými se tyto rutiny často zabývají. Může pomoct instrumentovat kód, který volá nativní metodu vydání, aby zachytil identitu volajícího, nebo případně úplné trasování zásobníku a hodnotu popisovače, který se vydává. Hodnotu popisovače lze porovnat s hodnotou hlášenou touto autoritou MDA.

  • Všimněte si, že některé nativní typy popisovačů, jako jsou všechny popisovače Win32, které lze vydat prostřednictvím CloseHandle funkce, sdílejí stejný obor názvů popisovače. Chybné uvolnění jednoho typu popisovače může způsobit problémy s jiným. Například náhodné zavření obslužného rutiny události Win32 dvakrát může vést k zřejmě nesouvisejícímu popisovači souboru, který je předčasně zavřený. K tomu dochází, když se popisovač uvolní a hodnota popisovače bude k dispozici pro sledování jiného prostředku, potenciálně jiného typu. Pokud k tomu dojde a následuje chybná druhá verze, může být popisovač nesouvisejícího vlákna neplatný.

Vliv na modul runtime

Tento mdA nemá žádný vliv na CLR.

Výstup

Zpráva s oznámenímCriticalHandle, že SafeHandle popisovač se nepodařilo správně uvolnit nebo se nezdařilo. Příklad:

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

Konfigurace

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

Příklad

Následuje příklad kódu, který může aktivovat 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);
}

Viz také