releaseHandleFailed MDA

Asystent releaseHandleFailed zarządzanego debugowania (MDA) jest aktywowany w celu powiadamiania deweloperów, gdy ReleaseHandle metoda klasy pochodzącej z SafeHandle klasy lub CriticalHandle zwraca wartość false.

Objawy

Przecieki zasobów lub pamięci. ReleaseHandle Jeśli metoda klasy pochodnej lub SafeHandleCriticalHandle kończy się niepowodzeniem, zasób hermetyzowany przez klasę może nie zostać zwolniony lub oczyszczony.

Przyczyna

Użytkownicy muszą podać implementację ReleaseHandle metody, jeśli tworzą klasy pochodzące z SafeHandle lub CriticalHandle; w związku z tym okoliczności są specyficzne dla poszczególnych zasobów. Jednak wymagania są następujące:

  • SafeHandle typy i CriticalHandle reprezentują otoki wokół ważnych zasobów procesów. Przeciek pamięci sprawi, że proces będzie bezużyteczny w czasie.

  • Metoda ReleaseHandle nie może wykonać jej funkcji. Gdy proces uzyska taki zasób, ReleaseHandle jest jedynym sposobem jego wydania. W związku z tym awaria oznacza przecieki zasobów.

  • Wszelkie błędy, które występują podczas wykonywania ReleaseHandle, utrudniając wydanie zasobu, jest usterką w implementacji ReleaseHandle samej metody. Jest to odpowiedzialność programisty, aby upewnić się, że kontrakt jest spełniony, nawet jeśli kod wywołuje kod utworzony przez inną osobę w celu wykonania jego funkcji.

Rozwiązanie

Kod używający określonego SafeHandle typu (lub CriticalHandle), który zgłosił powiadomienie MDA, należy przejrzeć, szukając miejsc, w których nieprzetworzona wartość dojścia jest wyodrębniona z SafeHandle elementu i skopiowana gdzie indziej. Jest to zwykła przyczyna błędów w ramach SafeHandle implementacji lub CriticalHandle , ponieważ użycie nieprzetworzonej wartości dojścia nie jest już śledzone przez środowisko uruchomieniowe. Jeśli nieprzetworzona kopia dojścia zostanie później zamknięta, może to spowodować niepowodzenie późniejszego ReleaseHandle wywołania, ponieważ próba zamknięcia jest podejmowana na tym samym dojściu, co jest teraz nieprawidłowe.

Istnieje wiele sposobów, w których może wystąpić niepoprawna obsługa duplikowania:

  • Wyszukaj wywołania DangerousGetHandle metody . Wywołania tej metody powinny być niezwykle rzadkie, a wszystkie, które można znaleźć, powinny być otoczone wywołaniami metod DangerousAddRef i DangerousRelease . Te ostatnie metody określają region kodu, w którym można bezpiecznie używać nieprzetworzonej wartości dojścia. Poza tym regionem lub jeśli liczba odwołań nigdy nie jest zwiększana w pierwszej kolejności, wartość uchwytu może zostać unieważniona w dowolnym momencie przez wywołanie metody Dispose lub Close w innym wątku. Po śledzeniu wszystkich zastosowań należy postępować zgodnie ze ścieżką, którą przyjmuje nieprzetworzony uchwyt, aby upewnić się, że nie zostanie przekazany do określonego DangerousGetHandle składnika, który ostatecznie wywoła CloseHandle metodę natywną niskiego poziomu lub inną natywną metodę niskiego poziomu, która zwolni dojście.

  • Upewnij się, że kod używany do inicjowania SafeHandle obiektu przy użyciu prawidłowej wartości dojścia pierwotnego jest właścicielem dojścia. Jeśli utworzysz SafeHandle wokół uchwytu kod nie jest właścicielem bez ustawienia parametru ownsHandlefalse w konstruktorze podstawowym, zarówno właściciel SafeHandle uchwytu rzeczywistego, jak i rzeczywistego uchwytu może spróbować zamknąć uchwyt, co prowadzi do błędu, ReleaseHandle jeśli SafeHandle przegra wyścig.

  • Gdy element SafeHandle jest marshalled między domenami aplikacji, upewnij SafeHandle się, że używane wyprowadzenie zostało oznaczone jako możliwe do serializacji. W rzadkich przypadkach, w których klasa pochodząca z SafeHandle klasy została wykonana z możliwością serializacji, powinna zaimplementować ISerializable interfejs lub użyć jednej z innych technik do ręcznego sterowania procesem serializacji i deserializacji. Jest to wymagane, ponieważ domyślną akcją serializacji jest utworzenie bitowego klonu otaczającej nieprzetworzonej wartości uchwytu, co powoduje, że dwa SafeHandle wystąpienia myślą, że są właścicielami tego samego uchwytu. Obaj spróbują wywołać ReleaseHandle to samo dojście w pewnym momencie. SafeHandle Drugie wykonanie tej czynności zakończy się niepowodzeniem. Prawidłowym sposobem działania podczas serializacji elementu SafeHandle jest wywołanie DuplicateHandle funkcji lub podobnej funkcji dla natywnego typu uchwytu w celu utworzenia odrębnej kopii dojścia prawnego. Jeśli typ uchwytu nie obsługuje tego typu, SafeHandle nie można go serializować.

  • Może być możliwe śledzenie, gdzie uchwyt jest zamykany wcześnie, co prowadzi do błędu, gdy ReleaseHandle metoda zostanie ostatecznie wywołana, umieszczając punkt przerwania debugera w natywnej procedurze używanej do zwolnienia uchwytu CloseHandle , na przykład funkcji. Może to nie być możliwe w przypadku scenariuszy przeciążeń, a nawet średniej wielkości testów funkcjonalnych ze względu na duży ruch, z jakim często borykają się takie procedury. Może to pomóc instrumentować kod, który wywołuje natywną metodę wydania, w celu przechwycenia tożsamości obiektu wywołującego lub ewentualnie pełnego śledzenia stosu oraz wartości zwalnianego dojścia. Wartość dojścia można porównać z wartością zgłoszoną przez tę usługę MDA.

  • Należy pamiętać, że niektóre natywne typy dojścia, takie jak wszystkie uchwyty Win32, które można zwolnić za pośrednictwem CloseHandle funkcji, współdzielą tę samą przestrzeń nazw dojścia. Błędne wydanie jednego typu dojścia może powodować problemy z innym. Na przykład przypadkowe zamknięcie dojścia zdarzenia Win32 dwa razy może prowadzić do przedwczesnego zamknięcia niezwiązanego z plikiem. Dzieje się tak, gdy dojście zostanie zwolnione, a wartość dojścia stanie się dostępna do użycia do śledzenia innego zasobu, potencjalnie innego typu. Jeśli tak się stanie i następuje błędne drugie wydanie, uchwyt niepowiązanego wątku może zostać unieważniony.

Wpływ na środowisko uruchomieniowe

To MDA nie ma wpływu na CLR.

Dane wyjściowe

Komunikat wskazujący, że element SafeHandle lub CriticalHandle nie może prawidłowo zwolnić dojścia. Na przykład:

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

Konfigurowanie

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

Przykład

Poniżej przedstawiono przykładowy kod, który może aktywować usługę 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);  
}  

Zobacz też