2011-10-21 110 views
1

我有一個C++應用程序內置MS Visual Studio 2005鏈接到第三方庫。對於某個輸入,應用程序在第三方庫中崩潰(顯然在realloc.c中的某處;因此必須是某種內存問題)。我在發佈中運行,因爲輸入是巨大的。所以我跑了,直到它崩潰,然後選擇調試。當我單獨調試有罪功能時,我希望使用一些異常處理來防止應用程序崩潰,而不是乾脆地退出。所以我用了類似的東西:MS Visual Studio 2005 C++異常處理

try { 
    //- call 3rd party application function that fails 
} 
catch(...) { 
    //- handle exception or whatever 
    Logger::Fatal("Fatal error: Exiting..."); 
    return false; 
} 

但令我驚訝的是,應用程序仍然崩潰!我期待看到它顯示錯誤消息,因爲我大概已經用省略號(...)捕獲了所有異常;我在這裏錯過了什麼?我甚至嘗試在項目屬性 - > C/C++ - >代碼配置 - >啓用異常處理中設置/ EHca(was/EHsc)。在有關可能導致問題的相關說明中,以下用法是否正確?

my_class* mc[] = {nil, nil, nil}; 
for (int i = 0; i < 3; ++i) { 
    mc[i] = new my_class(); 
    //-Do stuff with mc[i] 
    if (mc[i] != nil) { 
     delete mc[i]; 
     mc[i] = nil; 
    } 
} 

未能獲取異常處理工作是相當令人費解。我當然會欣賞C++大師們的想法/見解。順便說一句,同樣的問題也發生在Linux(RHEL5),但我目前正試圖讓異常處理在Windows上工作。

注:當我讓它調試後墜毀。我確實收到「訪問衝突......無法讀取位置」消息。有了這個更新的信息,我希望在C++中的某些東西仍然可以在Windows上運行,用於這種崩潰的Linux操作系統。

+1

好像你期待一個'C'功能在這裏拋出異常。 –

+0

嗯...它可能的第三方應用程序調用C函數是有罪的。但是,你的意思是不行嗎?那麼我怎麼能從C++中處理這些異常? –

+0

除非你知道拋出了一個異常,你怎麼能捕捉到它呢?也許第三方庫只是崩潰而不會拋出任何異常。您需要確保第三方庫發出異常。 –

回答

1

您是否嘗試過通過調用SetUnhandledExceptionFilter捕捉崩潰?

+0

謝謝@Miguel。是否有任何標準處理程序可以在Linux上運行?由於這看起來是MS Visual Studio特定的。 –

+1

我給你的是一個OS級異常處理程序,它與C或C++或Visual Studio無關。不知道它是否會起作用,但可能會起作用。是的,它只是Windows。我建議您不要嘗試解決在應用程序中看似嚴重的問題,而是花一些時間調試和修復內存問題。在Linux上,我確信Valgrind可以提供幫助。 – Miguel

+0

謝謝@Miguel。當然,我會調試它..但由於它發生在第三方應用程序,我正在尋找提交異常處理程序,以便它不會在用戶調試時遇到用戶崩潰。 –

0

由於米格爾建議,以解決您的問題以正確的方式可能是使用SetUnhandledExceptionFilter。但我想詳細解釋你的現象。

首先,並不是所有的程序「崩潰」都涉及到異常。例如,CRT可能在錯誤時觸發程序終止,例如vector中的無效元素訪問或純虛擬析構函數調用。如果你想覆蓋的情況下,以及 - 見set_unexpectedset_terminate

除了這一點,catch塊僅可趕上從適當的代碼塊拋出的異常。 OTOH有可能是在其他地方調用的函數,比如窗口的程序(如適用),其他線程等

現在,關於你的問題。我們首先要明白爲什麼像catch(...)這樣的東西可能會遇到訪問衝突等問題,以及爲什麼這並不總是會發生(就像你的情況一樣)。

Windows提供了自己的異常處理機制 - SEH,結構化異常處理。它遠遠優於C++異常處理。此外,硬件中斷(由CPU引起)會自動「轉換」爲SEH異常,因此使用SEH的代碼可處理軟件異常和硬件故障。

Microsoft C++編譯器實際上通過SEH實現了C++異常。也就是說throw經由RaiseException實現與指定C++ - 專用的異常代碼和參數,catch是一個C++ - 用於__except特定包裝,以及用於與析構函數的每個對象的編譯器生成類似於__finally塊的東西。反之亦然。當引發非C++異常時 - 執行爲C++異常生成的相同代碼。

此外還有一些同時影響編譯器的異常處理代碼生成,它在運行時的行爲所謂的編譯器的異常處理選項。他們被稱爲異常處理模型:

  • 同步。編譯器生成的代碼只有在明確提出異常時才能保證正常工作。這包括throw statments,所有的「洋」的功能,其代碼是不編譯器(在一些變化 - 只有C++外國功能)可見。特別是從記憶中讀取被認爲是「安全的」。
  • 異步。編譯器不允許假設任何有關可能出現異常的地方。因此,即使存取地址發生異常,它也會生成應該正常工作的代碼。

此外,這是一個在catch (...)故意調用CRT代碼忽略非C++異常,除非異步EH模型choosen

所以,如果你想catch (...)趕上非C++異常 - 你必須選擇異步EH模型。

有一次,我寫了一個article on the codeproject,之後我在驅動程序的開發相關的問題。它詳細解釋了這一切。