C# 非托管代码调用托管函数时clr.dll中出现NullReference异常
我有一个托管应用程序,它调用非托管dll,非托管dll也会回调托管应用程序。问题在于非托管dll回调托管代码 有几个测试在我们的CI上间歇性崩溃,并显示消息“代理进程在测试运行时已停止。”。当测试崩溃时,它会创建一个转储文件。转储文件的本机调试会话中的Callstack告诉我们,当非托管dll试图调用托管代码中的函数时,clr.dll引发了异常。下面是调用堆栈,我编写的非托管dll位于底部C# 非托管代码调用托管函数时clr.dll中出现NullReference异常,c#,c++,.net,C#,C++,.net,我有一个托管应用程序,它调用非托管dll,非托管dll也会回调托管应用程序。问题在于非托管dll回调托管代码 有几个测试在我们的CI上间歇性崩溃,并显示消息“代理进程在测试运行时已停止。”。当测试崩溃时,它会创建一个转储文件。转储文件的本机调试会话中的Callstack告诉我们,当非托管dll试图调用托管代码中的函数时,clr.dll引发了异常。下面是调用堆栈,我编写的非托管dll位于底部 KERNELBASE.dll!RaiseException() Unknown clr.dll!Raise
KERNELBASE.dll!RaiseException() Unknown
clr.dll!RaiseTheExceptionInternalOnly() Unknown
clr.dll!RaiseTheException(class Object *,int,enum CorruptionSeverity) Unknown
clr.dll!RealCOMPlusThrow(class Object *,enum CorruptionSeverity) Unknown
clr.dll!Thread::RaiseCrossContextException(class Exception *,class ContextTransitionFrame *) Unknown
clr.dll!Thread::DoADCallBack(struct ADID,void (*)(void *),void *,int) Unknown
clr.dll!UM2MDoADCallBack() Unknown
clr.dll!UMThunkStub() Unknown
UnManaged.dll!UnManagedClass::CallbackIntoManagedCode(bool * idle) Line 735 C++
UnManaged.dll!UnManagedClass::WhileLoopRunningInSeparateThread() Line 225 C++
到目前为止,我的理论是,如果在包含回调的托管对象被GCed之后,非托管代码被回调回托管代码,那么这可能会发生。我确实发现了一些可能导致这种情况的比赛条件。但即使在修复了这些竞争条件之后,测试仍然会在转储文件中使用此调用堆栈崩溃
问题-
// Managed.cs
public class MyClass
{
private int UnmanagedCodeCallsMe(Int64 n, IntPtr c)
{
return n;
}
public delegate int CalledFromUnmanagedDelegate ( Int64 n, IntPtr c );
private CalledFromUnmanagedDelegate willBeCalledFromUnmanaged = new CalledFromUnmanagedDelegate(UnmanagedCodeCallsMe);
void StartUseOfCallback()
{
// Calls into unmanaged code to set callback
UnmanagedFunctionSetCallback(willBeCalledFromUnmanaged);
}
// It is possible that this function never gets called
void EndUseOfCallback ( )
{
UnmanagedFunctionFreeCallback(willBeCalledFromUnmanaged);
}
}
---------------------Over to unmanaged code ----------------
// Unmanaged.cpp
typedef int32 (*ManagedCallback)(int64, int32*);
public UnmanagedClass
{
public:
ManagedCallback CallManagedCode;
void FreeRunningWhileLoop()
{
while(true)
{
// Do something
int32 count;
CallManagedCode(0, *count);
// do domething
}
}
}
UnmanagedClass *globalObject;
extern "C" __declspec(dllexport) RegisterManagedFunction(ManagedCallback c)
{
globalObject->CallManagedCode = c;
}
也许,您没有向我们展示测试程序,所以这只是猜测。当MyClass对象被收集时,显示结束。在本机代码中使用全局变量,因此willBeCalledFromUnmanaged应该具有相应的生存期。它应该是
静态的
。使用C++/CLI控制台程序测试回调。使用此选项可以调试所有代码。