Compartir a través de


Identificadores seguros y finalización crítica

Antes de la versión 2.0 de .NET Framework, los identificadores del sistema operativo sólo se podían encapsular en el objeto contenedor administrado IntPtr. Aunque era una manera cómoda de interoperar con código nativo, las excepciones asincrónicas podían perder identificadores, por ejemplo, un subproceso que se anulase inesperadamente o un desbordamiento de pila. Estas excepciones asincrónicas son un obstáculo para la limpieza de los recursos del sistema operativo y se pueden producir casi en cualquier parte del programa. Tienen tendencia a producirse en aplicaciones que utilizan un host que está ejecutando código administrado, como Microsoft SQL Server.

En algunas circunstancias, una recolección de elementos no utilizados podía reclamar objetos finalizables al ejecutar un método dentro de una llamada de invocación de plataforma. Si un finalizador liberaba el identificador pasado a esa llamada de invocación de plataforma, se podía llegar a dañar el identificador. También se podía reclamar el identificador mientras el método estaba bloqueado durante una llamada de invocación de plataforma, por ejemplo, al leer un archivo.

De manera más crítica, como Windows recicla agresivamente los identificadores, se podía reciclar un identificador y señalar a otro recurso que podría contener datos confidenciales. Esto se conoce como un ataque de reciclaje; puede dañar potencialmente los datos y constituir una amenaza para la seguridad.

A partir de .NET Framework 2.0, la clase SafeHandle simplifica algunos de estos problemas de duración de objetos y se integra en la invocación de plataforma para que no se pierdan los recursos de ese sistema operativo. La clase SafeHandle resuelve los problemas de duración de objetos asignando y liberando identificadores sin interrupción. Contiene un finalizador crítico que asegura el cierre del identificador y cuya ejecución está garantizada durante las descargas de AppDomain, incluso en los casos en los que se supone que la llamada de invocación de plataforma está dañada.

Como SafeHandle hereda de CriticalFinalizerObject, se llama primero a todos los finalizadores no críticos antes que a los críticos. Se llama a los finalizadores en objetos que ya no están activos durante el mismo paso de recolección de elementos no utilizados. Por ejemplo, un objeto FileStream puede ejecutar un finalizador normal para vaciar los datos existentes en el búfer sin riesgo de que se pierda o se recicle el identificador. Esta clasificación muy poco sólida entre finalizadores críticos y no críticos no está prevista para un uso general. Existe principalmente para ayudar en la migración de bibliotecas existentes al permitir a esas bibliotecas utilizar SafeHandle sin modificar su semántica. Además, el finalizador crítico y todo lo que llame, como el método SafeHandle.ReleaseHandle(), deben estar en un área de ejecución restringida. Esto impone restricciones sobre qué código se puede escribir dentro del gráfico de llamadas del finalizador.

A partir de la versión 2.0 de .NET Framework, las operaciones de invocación de plataforma incrementan automáticamente el recuento de referencias de identificadores encapsulados por SafeHandle y los reducen tras su finalización. Esto garantiza que el identificador no se recicle ni se cierre inesperadamente.

Puede especificar la propiedad del identificador subyacente al construir objetos SafeHandle. Esto controla si el objeto SafeHandle libera el identificador una vez desechado el objeto. Es útil para identificadores con requisitos de duración específicos o para utilizar un identificador cuya duración está controlada por otra persona.

Clases de identificadores seguras

La clase SafeHandle del espacio de nombres System.Runtime.InteropServices es una clase contenedora abstracta para los identificadores del sistema operativo. Es difícil derivar de esta clase. En su lugar, use las clases derivadas del espacio de nombres Microsoft.Win32.SafeHandles que proporcionan controladores seguros para lo siguiente:

  • Archivos y canalizaciones.

  • Vistas de memoria.

  • Construcciones de criptografía.

  • Claves del Registro.

  • Identificadores de espera.

Vea también

Referencia

SafeHandle

CriticalHandle

CriticalFinalizerObject