reentrância MDA
Nota
Este artigo é específico do .NET Framework. Ele não se aplica a implementações mais recentes do .NET, incluindo o .NET 6 e versões posteriores.
O reentrancy
assistente de depuração gerenciado (MDA) é ativado quando é feita uma tentativa de transição de código nativo para gerenciado nos casos em que uma mudança anterior de código gerenciado para código nativo não foi executada por meio de uma transição ordenada.
Sintomas
O heap de objeto está corrompido ou outros erros graves estão ocorrendo durante a transição de código nativo para gerenciado.
Os threads que alternam entre código nativo e gerenciado em qualquer direção devem executar uma transição ordenada. No entanto, certos pontos de extensibilidade de baixo nível no sistema operacional, como o manipulador de exceções vetoriais, permitem alternar de código gerenciado para código nativo sem executar uma transição ordenada. Esses switches estão sob controle do sistema operacional, em vez de sob controle CLR (Common Language Runtime). Qualquer código nativo que seja executado dentro desses pontos de extensibilidade deve evitar chamar de volta para o código gerenciado.
Motivo
Um ponto de extensibilidade do sistema operacional de baixo nível, como o manipulador de exceção vetorial, foi ativado durante a execução do código gerenciado. O código do aplicativo que é invocado através desse ponto de extensibilidade está tentando chamar de volta para o código gerenciado.
Esse problema é sempre causado pelo código do aplicativo.
Resolução
Examine o rastreamento de pilha para o thread que ativou este MDA. O thread está tentando chamar ilegalmente o código gerenciado. O rastreamento de pilha deve revelar o código do aplicativo usando esse ponto de extensibilidade, o código do sistema operacional que fornece esse ponto de extensibilidade e o código gerenciado que foi interrompido pelo ponto de extensibilidade.
Por exemplo, você verá o MDA ativado em uma tentativa de chamar o código gerenciado de dentro de um manipulador de exceção vetorial. Na pilha, você verá o código de tratamento de exceções do sistema operacional e algum código gerenciado acionando uma exceção, como um DivideByZeroException ou um AccessViolationException.
Neste exemplo, a resolução correta é implementar o manipulador de exceção vetorial completamente em código não gerenciado.
Efeito no tempo de execução
Este MDA não tem efeito sobre o CLR.
Saída
O MDA informa que está a ser tentada uma reentrância ilegal. Examine a pilha do thread para determinar por que isso está acontecendo e como corrigir o problema. A seguir está a saída de exemplo.
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'.
Configuração
<mdaConfig>
<assistants>
<reentrancy />
</assistants>
</mdaConfig>
Exemplo
O exemplo de código a seguir faz com que um AccessViolationException seja lançado. Em versões do Windows que oferecem suporte ao tratamento de exceções vetoriais, isso fará com que o manipulador de exceções vetoriais gerenciado seja chamado. Se o reentrancy
MDA estiver habilitado, o MDA será ativado durante a tentativa de chamada para MyHandler
a partir do código de suporte de tratamento de exceções vetoriais do sistema operacional.
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 { }
}
}