regiones de ejecución restringidas
Una región de ejecución restringida (CER) es parte de un mecanismo para crear código administrado de confianza. Una CER define un área en la que Common Language Runtime (CLR) no puede producir excepciones fuera de banda que eviten que el código del área se ejecute en su totalidad. Dentro de esa región, el código de usuario no puede ejecutar código que pueda producir excepciones fuera de banda. El método PrepareConstrainedRegions debe ir inmediatamente antes del bloque try
y marca los bloques catch
, finally
y fault
como regiones de ejecución restringidas. Una vez marcada como región restringida, el código solo debe llamar a otro código con contratos de fiabilidad estables y no debe asignar ni realizar llamadas virtuales a métodos no preparados o no confiables a menos que esté preparado para controlar errores. CLR retrasa las anulaciones de subprocesos del código que se está ejecutando en una CER.
Importante
CER solo se admite en .NET Framework. Este artículo no se aplica a .NET Core ni .NET 5 o versiones posteriores.
Las regiones de ejecución restringidas se usan de diferentes formas en CLR además de en un bloque anotado try
, en concreto, finalizadores críticos que se ejecutan en clases derivadas de la clase CriticalFinalizerObject y código ejecutado mediante el método ExecuteCodeWithGuaranteedCleanup.
Preparación anticipada de CER
CLR prepara las CER de antemano para evitar situaciones de memoria insuficiente. La preparación anticipada es necesaria para que CLR no provoque una situación de memoria insuficiente durante la compilación Just-In-Time o la carga de tipos.
Es necesario que el desarrollador indique que una región de código es una CER:
La región CER de nivel superior y los métodos del gráfico de llamadas completo que tienen el atributo ReliabilityContractAttribute aplicado se preparan de antemano. ReliabilityContractAttribute solo puede declarar garantías de Success o MayFail.
No es posible realizar la preparación anticipada de las llamadas que no se pueden determinar de forma estática, como la distribución virtual. En estos casos use el método PrepareMethod. Cuando se usa el método ExecuteCodeWithGuaranteedCleanup, se debe aplicar el atributo PrePrepareMethodAttribute al código de limpieza.
Restricciones
Los usuarios están limitados con respecto al tipo de código que pueden escribir en una CER. El código no puede producir una excepción fuera de banda, como la que podrían ocasionar las siguientes operaciones:
Asignación explícita.
Conversión boxing.
Adquisición de un bloqueo.
Llamada a métodos no preparados de forma virtual.
Llamada a métodos con un contrato de fiabilidad débil o inexistente.
En la versión 2.0 de .NET Framework, estas restricciones son directrices. Los diagnósticos se proporcionan a través de herramientas de análisis de código.
Contratos de fiabilidad
ReliabilityContractAttribute es un atributo personalizado que documenta las garantías de fiabilidad y el estado de daños de un método determinado.
Garantías de fiabilidad
Las garantías de fiabilidad, representadas por valores de enumeración Cer, indican el grado de fiabilidad de un método determinado:
MayFail. En condiciones excepcionales, se puede producir un error en el método. En este caso, el método informa al método de la llamada de si esta se ha realizado correctamente o no. El método debe estar incluido en una CER para garantizar que puede notificar el valor devuelto.
None. El método, tipo o ensamblado no tiene ningún concepto de una CER y lo más probable es que no sea seguro llamar desde dentro de una CER sin mitigación significativa de daños de estado. No se aprovecha de las garantías de la CER. Esto implica lo siguiente:
En condiciones excepcionales, se puede producir un error en el método.
El método podría o no informar de que se ha producido un error.
El método no se escribe para usar una CER, el escenario más probable.
Si un método, tipo o ensamblado no se identifica explícitamente como correcto, se identifica implícitamente como None.
Success. En condiciones excepcionales, se garantiza que el método será correcto. Para lograr este nivel de fiabilidad, siempre debería crear una CER alrededor del método al que se llama, incluso cuando se llama desde dentro de una región no CER. Un método es correcto si logra lo que pretendía, aunque la corrección se puede ver de forma subjetiva. Por ejemplo, marcar Count con
ReliabilityContractAttribute(Cer.Success)
implica que cuando se ejecuta en una CER, siempre devuelve un recuento del número de elementos de ArrayList y que nunca puede dejar los campos internos en un estado indeterminado. Pero el método CompareExchange también está marcado como correcto, con la asunción de que correcto puede significar que el valor no se ha podido reemplazar por un nuevo valor a causa de una condición de carrera. El punto clave es que el método se comporta de la manera en que se ha documentado que lo hará y no es necesario escribir código de la CER para esperar ningún comportamiento inusual más allá del aspecto que tendría un código correcto pero no confiable.
Niveles de daños
Los niveles de daños, representados por valores de enumeración Consistency, indican cuánto podría estar dañado en un entorno determinado:
MayCorruptAppDomain. En condiciones excepcionales, Common Language Runtime (CLR) no ofrece ninguna garantía con respecto a la coherencia del estado en el dominio de aplicación actual.
MayCorruptInstance. En condiciones excepcionales, se garantiza que el método limita los daños de estado a la instancia actual.
MayCorruptProcess. En condiciones excepcionales, CLR no ofrece ninguna garantía con respecto a la coherencia del estado; es decir, la condición podría dañar el proceso.
WillNotCorruptState. En condiciones excepcionales, se garantiza que el método no dañe el estado.
try/catch/finally de fiabilidad
try/catch/finally
de fiabilidad es un mecanismo de control de excepciones con el mismo nivel de garantías de previsibilidad que la versión no administrada. El bloque catch/finally
es la CER. Los métodos del bloque necesitan preparación anticipada y deben ser no interrumpibles.
En la versión 2.0 de .NET Framework, el código informa al tiempo de ejecución de que un elemento try es de confianza mediante una llamada al elemento PrepareConstrainedRegions inmediatamente anterior a un bloque try. PrepareConstrainedRegions es miembro de RuntimeHelpers, una clase de soporte del compilador. Llame a PrepareConstrainedRegions directamente pendiente de disponibilidad mediante compiladores.
Regiones no interrumpibles
Una región no interrumpible agrupa un conjunto de instrucciones en una CER.
En .NET Framework versión 2.0, pendiente de disponibilidad mediante compatibilidad del compilador, el código de usuario crea regiones no interrumpibles con un elemento try/catch/finally de confianza que contiene un bloque try/catch vacío precedido por una llamada al método PrepareConstrainedRegions.
Critical Finalizer Object
Un elemento CriticalFinalizerObject garantiza que la recolección de elementos no utilizados va a ejecutar el finalizador. Tras la asignación, el finalizador y su gráfico de llamadas se preparan de antemano. El método finalizador se ejecuta en una CER y debe obedecer todas las restricciones de las CER y los finalizadores.
Se garantiza que el finalizador de todos los tipos que heredan de SafeHandle y CriticalHandle se ejecuta dentro de una CER. Implemente ReleaseHandle en clases derivadas SafeHandle para ejecutar cualquier código necesario para liberar el controlador.
Código no permitido en las CER
En las CER no se permiten las operaciones siguientes:
Asignaciones explícitas.
Adquisición de un bloqueo.
Conversión boxing.
Acceso a una matriz multidimensional.
Llamadas a métodos mediante reflexión.
Comprobaciones de seguridad. No se realizan peticiones, solo peticiones de vínculos.
Obtención o establecimiento de campos en un servidor proxy transparente.
Serialización.
Punteros de función y delegados.