Run termination handler for uncaught C++ exceptions on Windows

On Windows, the termination handler is executed for uncaught C++
exceptions unless a SEH unhandled exception filter is also set. In this
case, this filter has to explicitly chain the default filter to keep
this behavior.
This commit is contained in:
Julian Brost 2020-10-14 15:21:25 +02:00
parent 0b26515c34
commit f8b7a1511b
1 changed files with 22 additions and 1 deletions

View File

@ -34,6 +34,14 @@
using namespace icinga;
#ifdef _WIN32
/* MSVC throws unhandled C++ exceptions as SEH exceptions with this specific error code.
* There seems to be no system header that actually defines this constant.
* See also https://devblogs.microsoft.com/oldnewthing/20160915-00/?p=94316
*/
#define EXCEPTION_CODE_CXX_EXCEPTION 0xe06d7363
#endif /* _WIN32 */
REGISTER_TYPE(Application);
boost::signals2::signal<void ()> Application::OnReopenLogs;
@ -55,6 +63,10 @@ double Application::m_StartTime;
bool Application::m_ScriptDebuggerEnabled = false;
double Application::m_LastReloadFailed;
#ifdef _WIN32
static LPTOP_LEVEL_EXCEPTION_FILTER l_DefaultUnhandledExceptionFilter = nullptr;
#endif /* _WIN32 */
/**
* Constructor for the Application class.
*/
@ -885,6 +897,15 @@ void Application::ExceptionHandler()
#ifdef _WIN32
LONG CALLBACK Application::SEHUnhandledExceptionFilter(PEXCEPTION_POINTERS exi)
{
/* If an unhandled C++ exception occurs with both a termination handler (std::set_terminate()) and an unhandled
* SEH filter (SetUnhandledExceptionFilter()) set, the latter one is called. However, our termination handler is
* better suited for dealing with C++ exceptions. In this case, the SEH exception will have a specific code and
* we can just call the default filter function which will take care of calling the termination handler.
*/
if (exi->ExceptionRecord->ExceptionCode == EXCEPTION_CODE_CXX_EXCEPTION) {
return l_DefaultUnhandledExceptionFilter(exi);
}
if (l_InExceptionHandler)
return EXCEPTION_CONTINUE_SEARCH;
@ -938,7 +959,7 @@ void Application::InstallExceptionHandlers()
sa.sa_handler = &Application::SigAbrtHandler;
sigaction(SIGABRT, &sa, nullptr);
#else /* _WIN32 */
SetUnhandledExceptionFilter(&Application::SEHUnhandledExceptionFilter);
l_DefaultUnhandledExceptionFilter = SetUnhandledExceptionFilter(&Application::SEHUnhandledExceptionFilter);
#endif /* _WIN32 */
}