簡體   English   中英

如何構建一個捕獲所有異常的C ++ Dll包裝器?

[英]How to build a C++ Dll wrapper that catches all exceptions?

就像標題所說,我們正在尋找一種方法來捕獲一段C ++代碼中的所有異常,並將其包裝在一個DLL中。 這樣我們可以屏蔽使用此dll的應用程序,從此dll中發生的任何錯誤。

但是,在Windows下使用C ++似乎不太可行。

例:

void function()
{  
    try  
    {    
        std::list<int>::iterator fd_it;
        fd_it++;  
    } catch(...) {}
}

發生的異常不會被標准C ++ try / catch塊捕獲,也不會被_set_se_translator()設置的任何SEH轉換器函數_set_se_translator() 相反,DLL崩潰,並且使用DLL的程序被中止。 我們使用Visual C ++ 2005編譯,使用選項/ SHa。 有誰知道在C ++ / Win32中是否可以捕獲這些問題並制作一個rockolid DLL包裝器?

制作堅如磐石的DLL包裝器的唯一方法是將錯誤的DLL加載到另一個進程中,這樣如果它崩潰了,它就不會讓你的主進程失效。

捕獲所有C ++異常似乎是合理的,但捕獲所有結構化異常是另一回事。 SEH 似乎可以讓你在那里大部分時間,因為它允許你捕獲訪問沖突,被零除異常等。

但是,如果有錯誤的DLL碰巧從另一個線程的堆棧觸及一個未提交的頁面怎么辦? 內存訪問將頁面錯誤,異常處理程序將被調用,現在該頁面不再是一個保護頁面。 當該線程需要增加堆棧時,它將獲得訪問沖突,並且該進程將崩潰。 這些 帖子更詳細地描述了這個案例。)

另一個可能的問題:錯誤的DLL在持有同步對象時崩潰,但您使用SEH來捕獲異常。 如果您的進程嘗試獲取相同的同步對象,則它會死鎖而不是崩潰。 共享同步對象可能是C運行時或操作系統的一部分:如果有錯誤的DLL 1加載有錯誤的DLL 2,它在DllMain()崩潰,而有缺陷的DLL 1持有加載程序鎖,該怎么辦? 下次加載DLL時你的進程是否會死鎖?

有關為何(以及具有類似問題的IsBadReadPtr()等函數)濫用SEH的原因的更多信息:

在Windows上,C ++有兩種不同的異常樣式:C ++和SEH異常。

SEH是一種僅限Windows的異常形式( 有點類似於UNIX中的信號)。 這更像是系統級異常。 它們將被拋出進行無效指針訪問,對齊問題等操作......

如果你想捕獲Windows上的C ++應用程序可以拋出的每個異常,你需要同時捕獲它們。 幸運的是,有一種方法可以混合使用C ++和SEH異常。 我最近寫了一篇關於此的詳細博客文章,它應該會幫助你。

http://blogs.msdn.com/jaredpar/archive/2008/01/11/mixing-seh-and-c-exceptions.aspx

在標准庫容器上增加迭代器永遠不會拋出C ++異常。 它可能會給你未定義的行為。

下面的代碼取自Zeus IDE。 它將捕獲任何Windows生成的異常:

步驟#1:定義異常過濾器功能

  DWORD ExceptionFilter(EXCEPTION_POINTERS *pointers, DWORD dwException)
  {
    //-- we handle all exceptions
    DWORD dwResult = EXCEPTION_EXECUTE_HANDLER;

    switch (dwException)
    {
      case EXCEPTION_ACCESS_VIOLATION:
      case EXCEPTION_DATATYPE_MISALIGNMENT:
      case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
      case EXCEPTION_FLT_DENORMAL_OPERAND:
      case EXCEPTION_FLT_DIVIDE_BY_ZERO:
      case EXCEPTION_FLT_INEXACT_RESULT:
      case EXCEPTION_FLT_INVALID_OPERATION:
      case EXCEPTION_FLT_OVERFLOW:
      case EXCEPTION_FLT_STACK_CHECK:
      case EXCEPTION_FLT_UNDERFLOW:
      case EXCEPTION_INT_DIVIDE_BY_ZERO:
      case EXCEPTION_INT_OVERFLOW:
      case EXCEPTION_PRIV_INSTRUCTION:
      case EXCEPTION_NONCONTINUABLE_EXCEPTION:
      case EXCEPTION_BREAKPOINT:
        dwResult = EXCEPTION_EXECUTE_HANDLER;
        break;
    }

    return dwResult;
  }

步驟#2:將代碼包裝在__try__except中 ,如下所示:

  __try
  {
    // call your dll entry point here
  }
  __except(ExceptionFilter(GetExceptionInformation(), 
                           GetExceptionCode()))
  {
    //-- display the fatal error message
    MessageBox(0, "An unexpected error was caught here!", 
               "Unexpected Error", MB_OK);
  }

Konrad Rudolph:當然這段代碼包含一個“邏輯錯誤”,它用來說明可能出現的問題。 就像男人說他希望能夠保護他的dll免受任何可能的錯誤。 你認為這不是一個合理的問題嗎? 聽說過供應商的產品。 我們中的一些人生活在現實世界中,生活在真正的問題中。 只是不可能解決其他人的問題

代碼包含邏輯錯誤(如果有的話)。 由於邏輯錯誤構成錯誤,請不要吞下異常 - 修復錯誤

當然,這是特定於特定代碼的。 其他人提供了更多一般性建議。 然而,我發現,很多其實更喜歡固定邏輯錯誤捕獲異常,這是不可接受的。

你看過windows API函數SetUnhandledExceptionFilter嗎?

我通常在DllMain函數中調用它,並在DLL崩潰時生成一個小型轉儲。 但是:(a)我不知道它是否捕獲應用程序異常以及DLL異常,以及(b)我不知道您是否可以讓程序執行可以繼續返回處理程序。 文檔說是,但我從來沒有這樣做過。

在發現異常后你會做什么(特別是對於SEH例外)?

實際上,您不能對流程的狀態做出任何假設,實際上您唯一的選擇是(可選)轉儲核心並退出。

從長遠來看,任何企圖和程序都絕對會給你帶來麻煩。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM