【发布时间】:2015-06-05 16:54:55
【问题描述】:
我有一个用 C++ 6.0 编写的旧应用程序的插件。这些文件以下列方式连接:
- 开始于:C++ 6.0 .exe(第三方应用程序)
- 加载:C++ 6.0 简单加载器 .dll(正式为应用程序插件)
- 加载:C++ 10.0 简单加载程序 .dll(托管 C++/CLI)
- 加载以下之一:包含插件的 C# .NET 4.0 程序集
- 加载: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 visual-c++-6