How to use std::set_terminate with SetUnhandledExceptionFilter?

Is there any way I can get the .what() of an uncaught C++ exception while also having a windows unhandled exception filter installed?

To demonstrate, the following program...

#include <windows.h>
#include <iostream>

static LONG WINAPI WindowsExceptionHandler(LPEXCEPTION_POINTERS ep) {
    std::cerr << "FOO" << std::endl;
    return EXCEPTION_EXECUTE_HANDLER;
}

void TerminateHandler() {
    std::exception_ptr exception_ptr = std::current_exception();
    try {
        if (exception_ptr) std::rethrow_exception(exception_ptr);
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
}

int main() {
    SetUnhandledExceptionFilter(WindowsExceptionHandler);
    std::set_terminate(TerminateHandler);
    throw std::runtime_error("BAR");
}

outputs:

FOO

I want it to output either BAR or FOOBAR

Commenting out the SetUnhandledExceptionFilter makes it work (but that's unacceptable as it won't catch the other windows exception types).

Clearly SetUnhandledExceptionFilter somehow overrides std::set_terminate in some way?

1 answer

  • answered 2020-01-14 07:14 RbMm

    all c++ exceptions internal use throw keyword. internal it use _CxxThrowException and this api call RaiseException function with 0xE06D7363 in place dwExceptionCode. so you need call previous exception filter returned by SetUnhandledExceptionFilter for C++ exceptions if want handle it with TerminateHandler.

    g_prevlpTopLevelExceptionFilter = SetUnhandledExceptionFilter(WindowsExceptionHandler);
    

    and

    if (ExceptionRecord->ExceptionCode == 0xE06D7363) {
        return g_prevlpTopLevelExceptionFilter(ep);
    }
    

    LPTOP_LEVEL_EXCEPTION_FILTER g_prevlpTopLevelExceptionFilter;
    
    LONG WINAPI WindowsExceptionHandler(LPEXCEPTION_POINTERS ep) {
    
        PEXCEPTION_RECORD ExceptionRecord = ep->ExceptionRecord;
    
        printf("%s: %x at %p", __FUNCTION__, 
            ExceptionRecord->ExceptionCode, ExceptionRecord->ExceptionAddress);
    
        if (ULONG NumberParameters = ExceptionRecord->NumberParameters)
        {
            printf(" { ");
            PULONG_PTR ExceptionInformation = ExceptionRecord->ExceptionInformation;
            do 
            {
                printf(" %p", (void*)*ExceptionInformation++);
            } while (--NumberParameters);
            printf(" } ");
        }
    
        printf("\n");
    
        if (ExceptionRecord->ExceptionCode == 0xE06D7363) {
            return g_prevlpTopLevelExceptionFilter(ep);
        }
    
        return EXCEPTION_EXECUTE_HANDLER;
    }
    
    void TerminateHandler() {
        MessageBoxW(0, 0, __FUNCTIONW__, MB_ICONWARNING);
        exit(-1);
    }
    
    void main() {
        g_prevlpTopLevelExceptionFilter = 
            SetUnhandledExceptionFilter(WindowsExceptionHandler);
        set_terminate(TerminateHandler);
        throw "888";
    }