Rory Claasen

C++ Unhandled Exceptions

2 min read
Table of Contents

Unhandled exceptions can be caught and handled in C++ using the SetUnhandledExceptionFilter function. This function allows you to set a custom exception handler that will be called when an unhandled exception occurs. This can be useful for logging or reporting exceptions, or for performing cleanup operations before the program exits.

Main exception handler

Main.cpp
#include <iostream>
#include <windows.h>
LONG WINAPI BasicUnhandledExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo)
{
// Do something with the exception...
// Write a minidump or register the exception with a crash reporting service
return EXCEPTION_CONTINUE_SEARCH;
}
int main()
{
SetUnhandledExceptionFilter(BasicUnhandledExceptionHandler);
// Run the main program
return 0;
}

Exception Filtering

To prevent the exception handler from being called recursively, or to prevent the exception handler from being called again if it throws an exception, you can use a spin-wait exception handler.

Main.cpp
__declspec(noinline) void SpinForever()
{
while (true)
{
SwitchToThread();
}
}
DWORD s_ExceptionThreadID = 0;
LONG WINAPI SpinWaitExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo)
{
if (s_ExceptionThreadID == GetCurrentThreadId())
{
// Prevent recursive exception locking the dump process
std::cout << "EXCEPTION HANDLER: Recursive exception encountered, skipping inner exception" << std::endl;
}
else
{
SpinForever();
}
return 0;
}
LONG WINAPI BasicUnhandledExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo)
{
s_ExceptionThreadID = GetCurrentThreadId();
SetUnhandledExceptionFilter(SpinWaitExceptionHandler);
...
return EXCEPTION_CONTINUE_SEARCH;
}

Writing a crash dump

When putting this into practice, you may want to write a minidump file when an unhandled exception occurs. This can be done using the MiniDumpWriteDump function.

Main.cpp
#include <DbgHelp.h>
BOOL WriteDump(const TCHAR* Path, EXCEPTION_POINTERS* ExceptionInfo, bool bIsFullMemory, DWORD ExceptionThreadId)
{
HANDLE FileHandle = CreateFileW(Path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (FileHandle == INVALID_HANDLE_VALUE)
{
return false;
}
MINIDUMP_EXCEPTION_INFORMATION DumpExceptionInfo;
DumpExceptionInfo.ThreadId = ExceptionThreadId;
DumpExceptionInfo.ExceptionPointers = ExceptionInfo;
DumpExceptionInfo.ClientPointers = FALSE;
MINIDUMP_TYPE mdt = MiniDumpNormal;
if (bIsFullMemory)
{
mdt = MiniDumpWithFullMemory;
}
const BOOL Result = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), FileHandle, mdt, (ExceptionInfo ? &DumpExceptionInfo : NULL), NULL, NULL);
CloseHandle(FileHandle);
return Result;
}

Demonstrating of how these functions can be used together, along with reporting the exception through the Windows Error Reporting API can be found in WERCrashApp.