From 0b9ef5ab6d96094f3da4b7d44d1c16a77d6e96e4 Mon Sep 17 00:00:00 2001 From: Julian Brost Date: Wed, 14 Oct 2020 15:21:25 +0200 Subject: [PATCH] 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. --- lib/base/application.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/base/application.cpp b/lib/base/application.cpp index e8fd04704..22c02522c 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -33,6 +33,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 Application::OnReopenLogs; @@ -54,6 +62,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. */ @@ -881,6 +893,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; @@ -934,7 +955,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 */ }