2015-06-05 178 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認爲這是一個堆棧溢出異常,並不會嘗試進行堆棧探測。