Selaa lähdekoodia

Enabled terminate handler and call stack writing on all platforms

Attempt to get a bit more debug info from crashes. VCMI will now:
- use c++ terminate handler on any platform in release builds
- attempt to write call stack to log file using boost::callstack

Since I use std::set_terminate this will only affect c++ exceptions, e.g.
std::runtime_error and will not affect OS signals, e.g. SIGSEGV. Handling
signals is OS-specific and has a lot of limitations that I don't want to
investigate. Besides - most of our crashes are now caused by c++
exceptions.

Haven't tested on other platforms, but should at the very least write
exception information (`e.what()`) for all exceptions and function names
for methods exported from dll's (libvcmi.so & AI's). Possibly more, if
debug information is present.
Ivan Savenko 1 vuosi sitten
vanhempi
sitoutus
13b2008f79
2 muutettua tiedostoa jossa 43 lisäystä ja 25 poistoa
  1. 6 0
      Global.h
  2. 37 25
      lib/CConsoleHandler.cpp

+ 6 - 0
Global.h

@@ -102,6 +102,12 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
 #  define STRONG_INLINE inline
 #endif
 
+// Required for building boost::stacktrace on macOS.
+// See https://github.com/boostorg/stacktrace/issues/88
+#if defined(VCMI_APPLE)
+#define _GNU_SOURCE
+#endif
+
 #define _USE_MATH_DEFINES
 
 #include <algorithm>

+ 37 - 25
lib/CConsoleHandler.cpp

@@ -13,6 +13,8 @@
 
 #include "CThreadHelper.h"
 
+#include <boost/stacktrace.hpp>
+
 VCMI_LIB_NAMESPACE_BEGIN
 
 std::mutex CConsoleHandler::smx;
@@ -142,6 +144,30 @@ static void createMemoryDump(MINIDUMP_EXCEPTION_INFORMATION * meinfo)
 	MessageBoxA(0, "VCMI has crashed. We are sorry. File with information about encountered problem has been created.", "VCMI Crashhandler", MB_OK | MB_ICONERROR);
 }
 
+LONG WINAPI onUnhandledException(EXCEPTION_POINTERS* exception)
+{
+	logGlobal->error("Disaster happened.");
+
+	PEXCEPTION_RECORD einfo = exception->ExceptionRecord;
+	logGlobal->error("Reason: 0x%x - %s at %04x:%x", einfo->ExceptionCode, exceptionName(einfo->ExceptionCode), exception->ContextRecord->SegCs, (void*)einfo->ExceptionAddress);
+
+	if (einfo->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+	{
+		logGlobal->error("Attempt to %s 0x%8x", (einfo->ExceptionInformation[0] == 1 ? "write to" : "read from"), (void*)einfo->ExceptionInformation[1]);
+	}
+	const DWORD threadId = ::GetCurrentThreadId();
+	logGlobal->error("Thread ID: %d", threadId);
+
+	//exception info to be placed in the dump
+	MINIDUMP_EXCEPTION_INFORMATION meinfo = {threadId, exception, TRUE};
+
+	createMemoryDump(&meinfo);
+
+	return EXCEPTION_EXECUTE_HANDLER;
+}
+
+#endif
+
 [[noreturn]] static void onTerminate()
 {
 	logGlobal->error("Disaster happened.");
@@ -166,37 +192,20 @@ static void createMemoryDump(MINIDUMP_EXCEPTION_INFORMATION * meinfo)
 		logGlobal->error("Reason: unknown exception!");
 	}
 
+	logGlobal->error("Call stack information:");
+	std::stringstream stream;
+	stream << boost::stacktrace::stacktrace();
+	logGlobal->error("%s", stream.str());
+
+#ifdef VCMI_WINDOWS
 	const DWORD threadId = ::GetCurrentThreadId();
 	logGlobal->error("Thread ID: %d", threadId);
 
 	createMemoryDump(nullptr);
+#endif
 	std::abort();
 }
 
-LONG WINAPI onUnhandledException(EXCEPTION_POINTERS* exception)
-{
-	logGlobal->error("Disaster happened.");
-
-	PEXCEPTION_RECORD einfo = exception->ExceptionRecord;
-	logGlobal->error("Reason: 0x%x - %s at %04x:%x", einfo->ExceptionCode, exceptionName(einfo->ExceptionCode), exception->ContextRecord->SegCs, (void*)einfo->ExceptionAddress);
-
-	if (einfo->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
-	{
-		logGlobal->error("Attempt to %s 0x%8x", (einfo->ExceptionInformation[0] == 1 ? "write to" : "read from"), (void*)einfo->ExceptionInformation[1]);
-	}
-	const DWORD threadId = ::GetCurrentThreadId();
-	logGlobal->error("Thread ID: %d", threadId);
-
-	//exception info to be placed in the dump
-	MINIDUMP_EXCEPTION_INFORMATION meinfo = {threadId, exception, TRUE};
-
-	createMemoryDump(&meinfo);
-
-	return EXCEPTION_EXECUTE_HANDLER;
-}
-#endif
-
-
 void CConsoleHandler::setColor(EConsoleTextColor::EConsoleTextColor color)
 {
 	TColor colorCode;
@@ -289,11 +298,14 @@ CConsoleHandler::CConsoleHandler():
 	defErrColor = csbi.wAttributes;
 #ifndef _DEBUG
 	SetUnhandledExceptionFilter(onUnhandledException);
-	std::set_terminate(onTerminate);
 #endif
 #else
 	defColor = "\x1b[0m";
 #endif
+
+#ifndef _DEBUG
+	std::set_terminate(onTerminate);
+#endif
 }
 CConsoleHandler::~CConsoleHandler()
 {