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 */ }