web-dev-qa-db-ja.com

SetUnhandledExceptionFilterが一部の例外をキャプチャできないが、AddVectoredExceptionHandlerはできる理由

SetUnhandledExceptionFilter に渡した関数が、例外コードc0000374が発生したときに呼び出されないという問題が発生しました。ただし、例外コードc0000005では問題なく機能します。次に、代わりに AddVectoredExceptionHandler を使用しようとしましたが、問題はありませんでした。ハンドラー関数が正しく呼び出されます。

それはAPIバグですか?どこでもSetUnhandledExceptionFilterの代わりにAddVectoredExceptionHandlerを使用できますか?

両方の機能は正しく動作します

// Exception code c0000005
int* p1 = NULL;
*p1 = 99;

AddVectoredExceptionHandlerのみがこの例外をキャプチャできます。 (ランタイムライブラリに依存しないことを証明するために、手動で例外を発生させると同じ結果になります。)

// Exception code c0000374
RaiseException(0xc0000374, 0, 0, NULL);

テストプログラム。

#include <tchar.h>
#include <fstream>
#include <Windows.h>

LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
{
    std::ofstream f;
    f.open("VectoredExceptionHandler.txt", std::ios::out | std::ios::trunc);
    f << std::hex << pExceptionInfo->ExceptionRecord->ExceptionCode << std::endl;
    f.close();

    return EXCEPTION_CONTINUE_SEARCH;
}

LONG WINAPI TopLevelExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
{
    std::ofstream f;
    f.open("TopLevelExceptionHandler.txt", std::ios::out | std::ios::trunc);
    f << std::hex << pExceptionInfo->ExceptionRecord->ExceptionCode << std::endl;
    f.close();

    return EXCEPTION_CONTINUE_SEARCH;
}


int _tmain(int argc, _TCHAR* argv[])
{
    AddVectoredExceptionHandler(1, VectoredExceptionHandler);
    SetUnhandledExceptionFilter(TopLevelExceptionHandler);

    // Exception code c0000374
    RaiseException(0xc0000374, 0, 0, NULL);     

    // Exception code c0000005
    // int* p1 = NULL;
    // *p1 = 99;        


    return 0;
}
23
wrongite

これは、MSVC CRTスタートアップの次のコードが原因で発生します。

    /*
     * Enable app termination when heap corruption is detected on
     * Windows Vista and above. This is a no-op on down-level OS's
     * and enabled by default for 64-bit processes.
     */

    if (!_NoHeapEnableTerminationOnCorruption)
    {
        HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
    }

無効にしたい場合(not推奨)、リンクnohetoc.objをプログラムに追加します。

14
Igor Skochinsky

例外は実際にはRtlReportCriticalFailureのソースで直接キャッチされ、ヒープの破損が検出されるとヒープマネージャによって呼び出されます。この関数に登録されたSEHハンドラーはRtlReportExceptionを呼び出し、すぐにNtTerminateProcessを呼び出します。

私は、SEHハンドラーが意図的に回避されていると結論付けることができるだけです-ヒープが破損しているため、スタックの内容(したがってSEH登録)も疑わしいです。とにかく、アプリケーションはヒープの破損から合理的に回復できません。

4
avakar