MDA de reentrada
Nota:
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 Asistente para la depuración administrada (MDA) reentrancy
se activa cuando se realiza un intento de realizar la transición de código nativo a código administrado en casos donde no se realizó un cambio anterior desde código administrado a código nativo a través de una transición ordenada.
Síntomas
El montón de objetos está dañado o se producen otros errores graves al realizar la transición de código nativo a código administrado.
Los subprocesos que cambian entre código nativo y administrado en cualquier dirección deben realizar una transición ordenada. Pero ciertos puntos de extensibilidad de bajo nivel en el sistema operativo, por ejemplo el controlador de excepciones orientado, permiten pasar de código administrado a código nativo sin realizar una transición ordenada. Estos modificadores están bajo el control del sistema operativo, en lugar de bajo el control de Common Language Runtime (CLR). Cualquier código nativo que se ejecute dentro de estos puntos de extensibilidad debe evitar realizar llamadas a código administrado.
Causa
Se ha activado un punto de extensibilidad de bajo nivel del sistema operativo, como el controlador de excepciones orientado, mientras se ejecuta código administrado. El código de aplicación que se invoca a través de ese punto de extensibilidad está intentando devolver la llamada al código administrado.
Este problema siempre está causado por código de aplicación.
Solución
Examine el seguimiento de la pila para el subproceso que ha activado este MDA. El subproceso está intentando llamar de forma no autorizada al código administrado. El seguimiento de la pila debe mostrar el código de aplicación que usa este punto de extensibilidad, el código del sistema operativo que proporciona este punto de extensibilidad y el código administrado que el punto de extensibilidad ha interrumpido.
Por ejemplo, verá que el MDA se activa en un intento de llamar a código administrado desde dentro de un controlador de excepciones orientado. En la pila verá el código de control de excepciones del sistema operativo y algún código administrado que desencadena una excepción como DivideByZeroException o AccessViolationException.
En este ejemplo, la solución correcta consiste en implementar el controlador de excepciones orientado completamente en código no administrado.
Efecto en el Runtime
Este MDA no tiene ningún efecto en el CLR.
Output
El MDA informa de que se ha intentado una reentrada ilegal. Examine la pila del subproceso para determinar por qué sucede esto y cómo corregir el problema. A continuación se incluye la salida del ejemplo.
Additional Information: Attempting to call into managed code without
transitioning out first. Do not attempt to run managed code inside
low-level native extensibility points. Managed Debugging Assistant
'Reentrancy' has detected a problem in 'D:\ConsoleApplication1\
ConsoleApplication1\bin\Debug\ConsoleApplication1.vshost.exe'.
Configuración
<mdaConfig>
<assistants>
<reentrancy />
</assistants>
</mdaConfig>
Ejemplo
El siguiente código de ejemplo hace que se inicie una excepción AccessViolationException. En versiones de Windows que admiten el control de excepciones orientado, esto hará que se llame al controlador de excepciones orientado. Si el MDA reentrancy
está habilitado, se activará durante el intento de llamada a MyHandler
desde el código de soporte de control de excepciones orientado del sistema operativo.
using System;
public delegate int ExceptionHandler(IntPtr ptrExceptionInfo);
public class Reenter
{
public static ExceptionHandler keepAlive;
[System.Runtime.InteropServices.DllImport("kernel32", ExactSpelling=true,
CharSet=System.Runtime.InteropServices.CharSet.Auto)]
public static extern IntPtr AddVectoredExceptionHandler(int bFirst,
ExceptionHandler handler);
static int MyHandler(IntPtr ptrExceptionInfo)
{
// EXCEPTION_CONTINUE_SEARCH
return 0;
}
void Run() {}
static void Main()
{
keepAlive = new ExceptionHandler(Reenter.MyHandler);
IntPtr ret = AddVectoredExceptionHandler(1, keepAlive);
try
{
// Dispatch on null should AV.
Reenter r = null;
r.Run();
}
catch { }
}
}