2015-06-05 120 views
4

我有一个用C++ 6.0编写的旧应用程序的插件。这些文件被连接在以下方式:.NET异常处理程序导致Visual C++ 6.0异常的堆栈溢出

  1. 始于:C++ 6.0 .exe文件(第三方应用程序)
  2. 负荷:C++ 6.0简单装载机.dll文件(正式应用插件)
  3. 负载: C++ 10.0简单装载机的.dll(托管C++/CLI)
  4. 负载中的一个:C#的.NET 4.0组件,其包含插件
  5. 载荷: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() 
[email protected]() 
[email protected]() 
[email protected]() 
[email protected]() 
// 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() 

只有真正2种方式来解决这个问题也不是很大:

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

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

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

回答

2

自从我报告这个问题以来,CLR似乎改变了行为。由于CLR现在是开源的,所以可以看到底下发生了什么。

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

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