Enabled vectored exception crash handling, it can also be turned off easily with a define

cmake -DENABLE_VECTORED_EXCEPTIONHANDLING=OFF
This commit is contained in:
Kjell Hedstrom 2015-02-16 01:37:55 -07:00
parent 9e3ed03310
commit 81885e4456
6 changed files with 74 additions and 33 deletions

View File

@ -31,7 +31,7 @@ ELSEIF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
ELSEIF(MSVC) ELSEIF (MSVC OR MINGW)
set(PLATFORM_LINK_LIBRIES dbghelp) set(PLATFORM_LINK_LIBRIES dbghelp)
# VC11 bug: http://code.google.com/p/googletest/issues/detail?id=408 # VC11 bug: http://code.google.com/p/googletest/issues/detail?id=408
# add_definition(-D_VARIADIC_MAX=10) # add_definition(-D_VARIADIC_MAX=10)

View File

@ -1,13 +1,10 @@
# -DUSE_DYNAMIC_LOGGING_LEVELS=ON : run-type turn on/off levels # -DUSE_DYNAMIC_LOGGING_LEVELS=ON : run-type turn on/off levels
option (USE_DYNAMIC_LOGGING_LEVELS option (USE_DYNAMIC_LOGGING_LEVELS
"Turn ON/OFF log levels. An disabled level will not push logs of that level to the sink. By default dynamic logging is disabled" OFF) "Turn ON/OFF log levels. An disabled level will not push logs of that level to the sink. By default dynamic logging is disabled" OFF)
IF(USE_DYNAMIC_LOGGING_LEVELS) IF(USE_DYNAMIC_LOGGING_LEVELS)
add_definitions(-DG2_DYNAMIC_LOGGING) add_definitions(-DG2_DYNAMIC_LOGGING)
MESSAGE("-DUSE_DYNAMIC_LOGGING_LEVELS=ON MESSAGE("-DUSE_DYNAMIC_LOGGING_LEVELS=ON")
\tDynamic logging levels can be turned on. Make sure to have \n\t\t[#define G2_DYNAMIC_LOGGING 1] in your source code") MESSAGE("\tDynamic logging levels can be turned on. Make sure to have \n\t\t[#define G2_DYNAMIC_LOGGING 1] in your source code")
MESSAGE("\t\tUse [g2::setLogLevel(LEVEL boolean)] to enable/disable logging on specified levels") MESSAGE("\t\tUse [g2::setLogLevel(LEVEL boolean)] to enable/disable logging on specified levels")
ELSE() ELSE()
MESSAGE("-DUSE_DYNAMIC_LOGGING_LEVELS=OFF") MESSAGE("-DUSE_DYNAMIC_LOGGING_LEVELS=OFF")
@ -20,13 +17,32 @@ ENDIF(USE_DYNAMIC_LOGGING_LEVELS)
# predefined DEBUG for their own purposes # predefined DEBUG for their own purposes
option (CHANGE_G3LOG_DEBUG_TO_DBUG option (CHANGE_G3LOG_DEBUG_TO_DBUG
"Use DBUG logging level instead of DEBUG. By default DEBUG is the debugging level" OFF) "Use DBUG logging level instead of DEBUG. By default DEBUG is the debugging level" OFF)
IF(CHANGE_G3LOG_DEBUG_TO_DBUG) IF(CHANGE_G3LOG_DEBUG_TO_DBUG)
add_definitions(-DCHANGE_G3LOG_DEBUG_TO_DBUG) add_definitions(-DCHANGE_G3LOG_DEBUG_TO_DBUG)
MESSAGE("-DCHANGE_G3LOG_DEBUG_TO_DBUG=ON MESSAGE("-DCHANGE_G3LOG_DEBUG_TO_DBUG=ON")
\tDBUG instead of DEBUG logging level can be used. Make sure to have \n\t\t[#define CHANGE_G3LOG_DEBUG_TO_DBUG 1] in your source code") MESSAGE("\tDBUG instead of DEBUG logging level can be used. Make sure to have \n\t\t[#define CHANGE_G3LOG_DEBUG_TO_DBUG 1] in your source code")
ELSE() ELSE()
MESSAGE("-DCHANGE_G3LOG_DEBUG_TO_DBUG=OFF. Debuggin logging level is 'DEBUG'") MESSAGE("-DCHANGE_G3LOG_DEBUG_TO_DBUG=OFF")
MESSAGE("\tDebuggin logging level is 'DEBUG'")
ENDIF(CHANGE_G3LOG_DEBUG_TO_DBUG) ENDIF(CHANGE_G3LOG_DEBUG_TO_DBUG)
# WINDOWS OPTION
# -DENABLE_VECTORED_EXCEPTIONHANDLING=ON : defualt change the
# By default vectored exception handling is enabled, you can disable it with this option.
# Please know that only known fatal exceptions will be caught, these exceptions are the ones
# enumerated in src/stacktrace_windows.cpp
IF (MSVC OR MINGW)
option (ENABLE_VECTORED_EXCEPTIONHANDLING
"Vectored exception / crash handling with improved stack trace" ON)
IF(NOT ENABLE_VECTORED_EXCEPTIONHANDLING)
add_definitions(-DDISABLE_VECTORED_EXCEPTIONHANDLING)
MESSAGE("-DENABLE_VECTORED_EXCEPTIONHANDLING=OFF")
MESSAGE("\tVectored exception handling is disabled")
ELSE()
MESSAGE("-DENABLE_VECTORED_EXCEPTIONHANDLING=ON")
MESSAGE("\tVectored exception handling is enabled")
ENDIF(NOT ENABLE_VECTORED_EXCEPTIONHANDLING)
ENDIF (MSVC OR MINGW)

View File

@ -136,6 +136,7 @@ void ExecuteDeathFunction(const bool runInNewThread, int fatalChoice) {
case 8: exitFunction = &OutOfBoundsArrayIndexing; break; case 8: exitFunction = &OutOfBoundsArrayIndexing; break;
case 9: exitFunction = &AccessViolation; break; case 9: exitFunction = &AccessViolation; break;
case 10: exitFunction = &RaiseSIGABRTAndAccessViolation; break; case 10: exitFunction = &RaiseSIGABRTAndAccessViolation; break;
case 11: throw 123456789; break;
default: break; default: break;
} }
if (runInNewThread) { if (runInNewThread) {
@ -191,12 +192,14 @@ int ChoiceOfFatalExit() {
std::cout << "[8] Out of bounds array indexing " << std::endl; std::cout << "[8] Out of bounds array indexing " << std::endl;
std::cout << "[9] Access violation" << std::endl; std::cout << "[9] Access violation" << std::endl;
std::cout << "[10] Rasing SIGABRT + Access Violation in two separate threads" << std::endl; std::cout << "[10] Rasing SIGABRT + Access Violation in two separate threads" << std::endl;
std::cout << "[11] Just throw" << std::endl;
std::cout << std::flush; std::cout << std::flush;
try { try {
std::getline(std::cin, option); std::getline(std::cin, option);
choice = std::stoi(option); choice = std::stoi(option);
if (choice <= 0 || choice > 10) { if (choice <= 0 || choice > 11) {
std::cout << "Invalid choice: [" << option << "\n\n"; std::cout << "Invalid choice: [" << option << "\n\n";
} else { } else {
return choice; return choice;

View File

@ -24,20 +24,24 @@
#include "g2logmessage.hpp" #include "g2logmessage.hpp"
#include "g2logmessagecapture.hpp" #include "g2logmessagecapture.hpp"
namespace { namespace {
std::atomic<bool> gBlockForFatal {true}; std::atomic<bool> gBlockForFatal {true};
//void* g_vector_exception_handler = nullptr;
LPTOP_LEVEL_EXCEPTION_FILTER g_previous_unexpected_exception_handler = nullptr; LPTOP_LEVEL_EXCEPTION_FILTER g_previous_unexpected_exception_handler = nullptr;
g2_thread_local bool g_installed_thread_signal_handler = false; g2_thread_local bool g_installed_thread_signal_handler = false;
#if !(defined(DISABLE_VECTORED_EXCEPTIONHANDLING))
void* g_vector_exception_handler = nullptr;
#endif
// Restore back to default fatal event handling // Restore back to default fatal event handling
void ReverseToOriginalFatalHandling() { void ReverseToOriginalFatalHandling() {
SetUnhandledExceptionFilter (g_previous_unexpected_exception_handler); SetUnhandledExceptionFilter (g_previous_unexpected_exception_handler);
//RemoveVectoredExceptionHandler (g_vector_exception_handler);
#if !(defined(DISABLE_VECTORED_EXCEPTIONHANDLING))
RemoveVectoredExceptionHandler (g_vector_exception_handler);
#endif
if (SIG_ERR == signal(SIGABRT, SIG_DFL)) if (SIG_ERR == signal(SIGABRT, SIG_DFL))
perror("signal - SIGABRT"); perror("signal - SIGABRT");
@ -73,37 +77,41 @@ void signalHandler(int signal_number) {
// Unhandled exception catching // Unhandled exception catching
LONG WINAPI exceptionHandling(EXCEPTION_POINTERS* info) { LONG WINAPI exceptionHandling(EXCEPTION_POINTERS* info, const std::string& handler) {
std::string dump = stacktrace::stackdump(info); std::string dump = stacktrace::stackdump(info);
std::ostringstream fatal_stream; std::ostringstream fatal_stream;
const g2::SignalType exception_code = info->ExceptionRecord->ExceptionCode; const g2::SignalType exception_code = info->ExceptionRecord->ExceptionCode;
fatal_stream << "\n***** Received fatal exception " << g2::internal::exitReasonName(g2::internal::FATAL_EXCEPTION, exception_code); fatal_stream << "\n***** " << handler << ": Received fatal exception " << g2::internal::exitReasonName(g2::internal::FATAL_EXCEPTION, exception_code);
fatal_stream << "\tPID: " << getpid() << std::endl; fatal_stream << "\tPID: " << getpid() << std::endl;
const auto fatal_id = static_cast<g2::SignalType>(exception_code); const auto fatal_id = static_cast<g2::SignalType>(exception_code);
LogCapture trigger(g2::internal::FATAL_EXCEPTION, fatal_id, dump.c_str()); LogCapture trigger(g2::internal::FATAL_EXCEPTION, fatal_id, dump.c_str());
trigger.stream() << fatal_stream.str(); trigger.stream() << fatal_stream.str();
return EXCEPTION_CONTINUE_SEARCH; //EXCEPTION_EXECUTE_HANDLER; return EXCEPTION_EXECUTE_HANDLER; // FATAL Exception: It stops here
} }
// Unhandled exception catching // Unhandled exception catching
LONG WINAPI unexpectedExceptionHandling(EXCEPTION_POINTERS* info) { LONG WINAPI unexpectedExceptionHandling(EXCEPTION_POINTERS* info) {
ReverseToOriginalFatalHandling(); ReverseToOriginalFatalHandling();
return exceptionHandling(info); return exceptionHandling(info, "Unexpected Exception Handler");
} }
/// Setup through (Windows API) AddVectoredExceptionHandler /// Setup through (Windows API) AddVectoredExceptionHandler
/// Ref: http://blogs.msdn.com/b/zhanli/archive/2010/06/25/c-tips-addvectoredexceptionhandler-addvectoredcontinuehandler-and-setunhandledexceptionfilter.aspx /// Ref: http://blogs.msdn.com/b/zhanli/archive/2010/06/25/c-tips-addvectoredexceptionhandler-addvectoredcontinuehandler-and-setunhandledexceptionfilter.aspx
#if 0 #if !(defined(DISABLE_VECTORED_EXCEPTIONHANDLING))
LONG WINAPI vectorExceptionHandling(PEXCEPTION_POINTERS p) { LONG WINAPI vectorExceptionHandling(PEXCEPTION_POINTERS p) {
ReverseToOriginalFatalHandling(); const g2::SignalType exception_code = p->ExceptionRecord->ExceptionCode;
return exceptionHandling(p); if (false == stacktrace::isKnownException(exception_code)) {
} LOG(WARNING) << "Vectored exception handling received an UNKNOWN exception: " << exception_code << ". The exception is IGNORED and hopefully caught by another exception handler";
return EXCEPTION_CONTINUE_SEARCH;
} else {
ReverseToOriginalFatalHandling();
return exceptionHandling(p, "Vectored Exception Handler");
}
}
#endif #endif
@ -209,10 +217,15 @@ void installSignalHandlerForThread() {
void installCrashHandler() { void installCrashHandler() {
internal::installSignalHandler(); internal::installSignalHandler();
//const size_t kFirstExceptionHandler = 1; // Kept here for documentational purposes. last exception seems more what we want
const size_t kLastExceptionHandler = 0;
//g_vector_exception_handler = AddVectoredExceptionHandler(kLastExceptionHandler, vectorExceptionHandling);
g_previous_unexpected_exception_handler = SetUnhandledExceptionFilter(unexpectedExceptionHandling); g_previous_unexpected_exception_handler = SetUnhandledExceptionFilter(unexpectedExceptionHandling);
#if !(defined(DISABLE_VECTORED_EXCEPTIONHANDLING))
// const size_t kFirstExceptionHandler = 1;
// kFirstExeptionsHandler is kept here for documentational purposes.
// The last exception seems more what we want
const size_t kLastExceptionHandler = 0;
g_vector_exception_handler = AddVectoredExceptionHandler(kLastExceptionHandler, vectorExceptionHandling);
#endif
} }
} // end namespace g2 } // end namespace g2

View File

@ -146,19 +146,24 @@ std::string convertFramesToText(std::vector<uint64_t>& frame_pointers) {
namespace stacktrace { namespace stacktrace {
const std::string kUnknown = {"UNKNOWN EXCEPTION"};
/// return the text description of a Windows exception code /// return the text description of a Windows exception code
/// From MSDN GetExceptionCode http://msdn.microsoft.com/en-us/library/windows/desktop/ms679356(v=vs.85).aspx /// From MSDN GetExceptionCode http://msdn.microsoft.com/en-us/library/windows/desktop/ms679356(v=vs.85).aspx
std::string exceptionIdToText(g2::SignalType id) { std::string exceptionIdToText(g2::SignalType id) {
const auto iter = kExceptionsAsText.find(id); const auto iter = kExceptionsAsText.find(id);
if ( iter == kExceptionsAsText.end()) { if ( iter == kExceptionsAsText.end()) {
std::string unknown {"Unknown/" + std::to_string(id)}; std::string unknown = {kUnknown + ":" + std::to_string(id)};
return unknown; return unknown;
} }
return iter->second; return iter->second;
} }
/// Yes a double lookup: first for isKnownException and then exceptionIdToText
/// for vectored exceptions we only deal with known exceptions so this tiny
/// overhead we can live with
bool isKnownException(g2::SignalType id) {
return (kExceptionsAsText.end() != kExceptionsAsText.find(id));
}
/// helper function: retrieve stackdump from no excisting exception pointer /// helper function: retrieve stackdump from no excisting exception pointer
std::string stackdump() { std::string stackdump() {

View File

@ -27,6 +27,10 @@ namespace stacktrace {
/// return the text description of a Windows exception code /// return the text description of a Windows exception code
std::string exceptionIdToText(g2::SignalType id); std::string exceptionIdToText(g2::SignalType id);
/// return whether or not the exception is a known exception, i.e.
/// an exception that we should treat as a fatal event
bool isKnownException(g2::SignalType id);
/// helper function: retrieve stackdump from no excisting exception pointer /// helper function: retrieve stackdump from no excisting exception pointer
std::string stackdump(); std::string stackdump();