releaseHandleFailed MDA

Note

Artikel ini khusus untuk .NET Framework. Ini tidak berlaku untuk implementasi .NET yang lebih baru, termasuk .NET 6 dan versi yang lebih baru.

Asisten penelusuran kesalahan terkelola releaseHandleFailed (MDA) diaktifkan adalah untuk memberi tahu pengembang ketika ReleaseHandle metode kelas yang berasal dari SafeHandle atau CriticalHandle mengembalikan false.

Gejala

Kebocoran sumber daya atau memori. ReleaseHandle Jika metode kelas yang berasal dari SafeHandle atau CriticalHandle gagal, sumber daya yang dienkapsulasi oleh kelas mungkin belum dirilis atau dibersihkan.

Penyebab

Pengguna harus memberikan implementasi ReleaseHandle metode jika mereka membuat kelas yang berasal dari SafeHandle atau CriticalHandle; dengan demikian, keadaan khusus untuk sumber daya individu. Namun, persyaratannya adalah sebagai berikut:

  • SafeHandle dan CriticalHandle jenis mewakili pembungkus di sekitar sumber daya proses vital. Kebocoran memori akan membuat proses tidak dapat digunakan dari waktu ke waktu.

  • Metode ReleaseHandle tidak boleh gagal melakukan fungsinya. Setelah proses memperoleh sumber daya seperti itu, ReleaseHandle adalah satu-satunya cara untuk merilisnya. Oleh karena itu, kegagalan menyiratkan kebocoran sumber daya.

  • Setiap kegagalan yang terjadi selama eksekusi ReleaseHandle, menghambat rilis sumber daya, adalah bug dalam implementasi metode itu ReleaseHandle sendiri. Programmer bertanggung jawab untuk memastikan bahwa kontrak terpenuhi, bahkan jika kode tersebut memanggil kode yang ditulis oleh orang lain untuk melakukan fungsinya.

Resolution

Kode yang menggunakan jenis spesifik SafeHandle (atau CriticalHandle) yang menaikkan pemberitahuan MDA harus ditinjau, mencari tempat di mana nilai handel mentah diekstrak dari SafeHandle dan disalin di tempat lain. Ini adalah penyebab kegagalan yang biasa dalam SafeHandle atau CriticalHandle implementasi, karena penggunaan nilai handle mentah kemudian tidak lagi dilacak oleh runtime. Jika salinan handel mentah kemudian ditutup, itu dapat menyebabkan panggilan kemudian ReleaseHandle gagal karena penutupan dicoba pada handel yang sama, yang sekarang tidak valid.

Ada sejumlah cara di mana duplikasi penanganan yang salah dapat terjadi:

  • Cari panggilan ke metode .DangerousGetHandle Panggilan ke metode ini harus sangat jarang, dan apa pun yang Anda temukan harus dikelilingi oleh panggilan ke DangerousAddRef metode dan DangerousRelease . Metode terakhir ini menentukan wilayah kode di mana nilai handel mentah dapat digunakan dengan aman. Di luar wilayah ini, atau jika jumlah referensi tidak pernah bertambah di tempat pertama, nilai handel dapat dibatalkan kapan saja dengan panggilan ke Dispose atau Close pada utas lain. Setelah semua penggunaan DangerousGetHandle dilacak, Anda harus mengikuti jalur yang diperlukan handel mentah untuk memastikan tidak diserahkan ke beberapa komponen yang akhirnya akan memanggil CloseHandle atau metode asli tingkat rendah lainnya yang akan melepaskan handel.

  • Pastikan bahwa kode yang digunakan untuk menginisialisasi SafeHandle dengan nilai handel mentah yang valid memiliki handel. Jika Anda membentuk SafeHandle di sekitar handel yang tidak dimiliki kode Anda tanpa mengatur ownsHandle parameter ke false di konstruktor dasar, maka SafeHandle pemilik handel dan nyata dapat mencoba menutup handel, yang mengarah ke kesalahan ReleaseHandle jika SafeHandle kehilangan balapan.

  • SafeHandle Ketika marshalled antara domain aplikasi, konfirmasikan SafeHandle bahwa derivasi yang digunakan telah ditandai sebagai dapat diserialisasikan. Dalam kasus yang jarang terjadi di mana kelas yang berasal SafeHandle telah dibuat dapat diserialisasikan, kelas harus mengimplementasikan ISerializable antarmuka atau menggunakan salah satu teknik lain untuk mengontrol proses serialisasi dan deserialisasi secara manual. Ini diperlukan karena tindakan serialisasi default adalah membuat klon bitwise dari nilai handel mentah yang diapit, yang mengakibatkan dua SafeHandle instans berpikir mereka memiliki handel yang sama. Keduanya akan mencoba memanggil ReleaseHandle handel yang sama di beberapa titik. Yang kedua SafeHandle untuk melakukan ini akan gagal. Tindakan yang benar saat menserialisasikan adalah SafeHandle memanggil DuplicateHandle fungsi atau fungsi serupa untuk jenis handel asli Anda untuk membuat salinan penanganan hukum yang berbeda. Jika jenis handel Anda tidak mendukung ini, maka SafeHandle jenis pembungkusannya tidak dapat diserialisasikan.

  • Mungkin untuk melacak di mana handel ditutup lebih awal, yang menyebabkan kegagalan ketika ReleaseHandle metode akhirnya dipanggil, dengan menempatkan titik henti debugger pada rutinitas asli yang digunakan untuk melepaskan handel, misalnya CloseHandle fungsi. Hal ini mungkin tidak dimungkinkan untuk skenario stres atau bahkan tes fungsional berukuran sedang karena padatnya lalu lintas rutinitas seperti yang sering ditangani. Ini dapat membantu melengkapi kode yang memanggil metode rilis asli, untuk menangkap identitas pemanggil, atau mungkin pelacakan tumpukan penuh, dan nilai handel yang dirilis. Nilai handle dapat dibandingkan dengan nilai yang dilaporkan oleh MDA ini.

  • Perhatikan bahwa beberapa jenis handel asli, seperti semua handel Win32 yang dapat dirilis melalui CloseHandle fungsi, berbagi namespace handel yang sama. Rilis yang salah dari satu jenis handel dapat menyebabkan masalah dengan yang lain. Misalnya, secara tidak sengaja menutup handel peristiwa Win32 dua kali dapat menyebabkan handel file yang tampaknya tidak terkait ditutup sebelum waktunya. Ini terjadi ketika handel dirilis dan nilai handel menjadi tersedia untuk digunakan untuk melacak sumber daya lain, berpotensi dari jenis lain. Jika ini terjadi dan diikuti oleh rilis kedua yang salah, handel utas yang tidak terkait mungkin tidak valid.

Efek pada Runtime

MDA ini tidak berpengaruh pada CLR.

Hasil

Pesan yang menunjukkan bahwa atau SafeHandle gagal CriticalHandle melepaskan handel dengan benar. Contohnya:

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

Konfigurasi

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

Example

Berikut ini adalah contoh kode yang dapat mengaktifkan 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);
}

Baca juga