releaseHandleFailed MDA

Note

Este artículo es específico de .NET Framework. No se aplica a implementaciones más recientes de .NET, incluidas .NET 6 y versiones posteriores.

El releaseHandleFailed asistente de depuración administrada (MDA) se activa es notificar a los desarrolladores cuando el ReleaseHandle método de una clase derivada de SafeHandle o CriticalHandle devuelve false.

Síntomas

Pérdidas de recursos o memoria. Si el ReleaseHandle método de la clase que deriva de SafeHandle o CriticalHandle produce un error, es posible que el recurso encapsulado por la clase no se haya liberado o limpiado.

Causa

Los usuarios deben proporcionar la implementación del ReleaseHandle método si crean clases que derivan de SafeHandle o CriticalHandle; por lo tanto, las circunstancias son específicas del recurso individual. Sin embargo, los requisitos son los siguientes:

  • SafeHandle y CriticalHandle los tipos representan contenedores en torno a los recursos de proceso vitales. Una pérdida de memoria haría que el proceso fuera inutilizable a lo largo del tiempo.

  • El ReleaseHandle método no debe producir un error para realizar su función. Una vez que el proceso adquiere este recurso, ReleaseHandle es la única manera de liberarlo. Por lo tanto, el error implica pérdidas de recursos.

  • Cualquier error que se produzca durante la ejecución de ReleaseHandle, lo que impedía la liberación del recurso, es un error en la implementación del ReleaseHandle propio método. Es responsabilidad del programador asegurarse de que el contrato se cumple, incluso si ese código llama al código creado por otra persona para realizar su función.

Resolución

El código que usa el tipo específico SafeHandle (o CriticalHandle) que generó la notificación de MDA debe revisarse, buscando lugares donde se extrae el valor de identificador sin procesar de SafeHandle y se copia en otro lugar. Esta es la causa habitual de errores dentro SafeHandle de las implementaciones o CriticalHandle , ya que el tiempo de ejecución ya no realiza el seguimiento del uso del valor de identificador sin procesar. Si la copia del identificador sin procesar se cierra posteriormente, puede provocar un error en una llamada posterior ReleaseHandle porque el cierre se intenta en el mismo identificador, que ahora no es válido.

Hay varias maneras en las que puede producirse una duplicación de identificador incorrecta:

  • Busque llamadas al DangerousGetHandle método . Las llamadas a este método deben ser muy raras y las que encuentre deben estar rodeadas de llamadas a los DangerousAddRef métodos y DangerousRelease . Estos últimos métodos especifican la región del código en la que se puede usar el valor de identificador sin procesar de forma segura. Fuera de esta región, o si el recuento de referencias nunca se incrementa en primer lugar, el valor de identificador se puede invalidar en cualquier momento mediante una llamada a Dispose o Close en otro subproceso. Una vez que se haya realizado un seguimiento de todos los usos de DangerousGetHandle , debe seguir la ruta de acceso que toma el identificador sin procesar para asegurarse de que no se entregue a algún componente que finalmente llamará CloseHandle a u otro método nativo de bajo nivel que liberará el identificador.

  • Asegúrese de que el código que se usa para inicializar con SafeHandle un valor de identificador sin procesar válido posee el identificador. Si forma un SafeHandle identificador alrededor de un identificador, el código no es el propietario sin establecer el ownsHandle parámetro false en en el constructor base, tanto el SafeHandle propietario del identificador como el real pueden intentar cerrar el identificador, lo que provoca un error en ReleaseHandle si SafeHandle pierde la carrera.

  • Cuando se serializó un objeto SafeHandle entre dominios de aplicación, confirme que la SafeHandle derivación que se usa se ha marcado como serializable. En los casos poco frecuentes en los que una clase derivada de SafeHandle se ha serializado, debe implementar la ISerializable interfaz o usar una de las otras técnicas para controlar manualmente el proceso de serialización y deserialización. Esto es necesario porque la acción de serialización predeterminada consiste en crear un clon bit a bit del valor de identificador sin procesar incluido, lo que da lugar a dos SafeHandle instancias que piensan que poseen el mismo identificador. Ambos intentarán llamar ReleaseHandle al mismo identificador en algún momento. Se producirá un error en el segundo SafeHandle para hacerlo. El curso de acción correcto al serializar un SafeHandle es llamar a la DuplicateHandle función o una función similar para el tipo de identificador nativo para realizar una copia de identificador legal distinta. Si el tipo de identificador no admite esto, el ajuste de SafeHandle tipos no se puede serializar.

  • Puede ser posible realizar un seguimiento de dónde se cierra un identificador al principio, lo que provoca un error cuando ReleaseHandle finalmente se llama al método, colocando un punto de interrupción del depurador en la rutina nativa que se usa para liberar el identificador, por ejemplo, la CloseHandle función . Esto puede no ser posible para escenarios de estrés o incluso pruebas funcionales de tamaño medio debido al tráfico pesado con las que estas rutinas suelen tratar. Puede ayudar a instrumentar el código que llama al método de versión nativa, con el fin de capturar la identidad del autor de la llamada, o posiblemente un seguimiento de pila completo, y el valor del identificador que se está liberando. El valor de identificador se puede comparar con el valor notificado por este MDA.

  • Tenga en cuenta que algunos tipos de identificador nativos, como todos los identificadores win32 que se pueden liberar a través de la CloseHandle función, comparten el mismo espacio de nombres de identificador. Una liberación errónea de un tipo de identificador puede causar problemas con otro. Por ejemplo, si se cierra accidentalmente un identificador de eventos Win32 dos veces, es posible que un identificador de archivo aparentemente no relacionado se cierre prematuramente. Esto sucede cuando se libera el identificador y el valor del identificador está disponible para su uso para realizar un seguimiento de otro recurso, potencialmente de otro tipo. Si esto sucede y va seguido de una segunda versión errónea, el identificador de un subproceso no relacionado podría invalidarse.

Efecto en el tiempo de ejecución

Este MDA no tiene ningún efecto en clR.

Output

Mensaje que indica que o SafeHandle no CriticalHandle se pudo liberar correctamente el identificador. Por ejemplo:

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

Configuration

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

Example

A continuación se muestra un ejemplo de código que puede activar el 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);
}

Consulte también