.NET异常处理程序导致Visual C ++ 6.0异常上的堆栈溢出

问题描述 投票:4回答:1

我有一个用C ++ 6.0编写的旧应用程序的插件。文件以下列方式连接:

  1. 开头:C ++ 6.0 .exe(第三方应用程序)
  2. load:C ++ 6.0 simple loader .dll(官方的应用程序插件)
  3. load:C ++ 10.0 simple loader .dll(托管C ++ / CLI)
  4. 加载以下之一:包含插件的C#.NET 4.0程序集
  5. loads:C ++ 6.0 .dll,它为C#插件提供API以与应用程序通信

问题是一旦.NET 4.0加载到C ++ 6.0应用程序中,下次它抛出本机异常时,.NET使用向量异常句柄来处理异常并且失败很大。使得它非常糟糕的部分是向量异常处理程序本身抛出异常,然后它尝试处理,然后失败,并且它会陷入无限循环,直到它获得堆栈溢出异常。

这是堆栈跟踪的样子:

// The next 7 lines repeat until the stack overflows
clr.dll!CreateHistoryReader()
clr.dll!CreateHistoryReader()
clr.dll!GetMetaDataInternalInterfaceFromPublic()
ntdll.dll!_RtlpCallVectoredHandlers@12()
ntdll.dll!_RtlCallVectoredExceptionHanders@8()
ntdll.dll!_RtlDispatchException@8()
ntdll.dll!_KiUserExceptionDispatcher@8()
// Below is an example exception that causes this:
KernelBase.dll!RaiseException()
rpcrt4.dll!RpcRaiseException()
rpcrt4.dll!I_RpcTransConnectionFreePacket()
rpcrt4.dll!I_RpcBindingInqCurrentModifiedId()
rpcrt4.dll!NdrConformantStringMemorySize()
rpcrt4.dll!NdrComplexStructMarshall()
rpcrt4.dll!SimpleTypeMemorySize()
rpcrt4.dll!NdrClientCall2()
ole32.dll!ServerRegisterClsid(void* hRpc, void* phProcess, _RegInput* pregin, _RegOutput** ppregout unligned long* prpcstat
ole32.dll!CRpcResolver::NotifyStarted(_RegInput* pRegIn, _RegOutput** ppRegOut)
ole32.dll!CClassCache::ResumeProcessClassObjects()

只有两种方法可以解决这个问题,而且两者都不是很好:

我发现有一个简单的程序,如果我在自己的线程上完全隔离.NET,非.NET线程永远不会遇到这个问题。这在实践中不起作用,因为插件API需要对.NET插件进行同步回调。

我想到的另一个是迭代内存中的每个地址,直到对“RemoveVectoredExceptionHandler(HANDLE)”的调用成功并删除.NET的向量异常处理程序。 (我可以通过暂时注册我自己的VEH来加速搜索,并使用它的句柄作为起始点)。这往往会打破本机代码的调试。

有没有更好的方法来处理这个?

c++ .net exception-handling stack-overflow vc6
1个回答
2
投票

自从我报告此问题以来,CLR似乎已经改变了行为。由于CLR现在是开源的,因此可以看到幕后发生了什么。

CLR安装自己的向量异常处理程序。在向量异常处理期间,它会进行堆栈检查以确保有足够的空间,除非它是堆栈溢出异常。堆栈空间检查出错了,它认为它没有空间,因此它抛出堆栈溢出异常以展开堆栈足以进行实际工作。

我能够通过安装2个向量的异常处理程序来欺骗.NET而不会崩溃应用程序,一个在前和后一个。如果它是导致崩溃的异常类型,我在第一个处理程序中将异常代码更改为STACKOVERFLOW,并在第二个处理程序中将其更改回来。这样CLR认为它是堆栈溢出异常并且不会尝试进行堆栈探测。

© www.soinside.com 2019 - 2024. All rights reserved.