Changeset - r25047:a8e131d1e25b
[Not reviewed]
master
0 5 0
Michael Lutz - 4 years ago 2021-03-13 20:34:51
michi@icosahedron.de
Fix #8860: [Win32] Crashlog window wasn't reliably shown for crashes not on the main thread.
5 files changed with 42 insertions and 19 deletions:
0 comments (0 inline, 0 general)
src/crashlog.h
Show inline comments
 
@@ -105,17 +105,23 @@ public:
 
	bool WriteSavegame(char *filename, const char *filename_last) const;
 
	bool WriteScreenshot(char *filename, const char *filename_last) const;
 

	
 
	bool MakeCrashLog() const;
 

	
 
	/**
 
	 * Initialiser for crash logs; do the appropriate things so crashes are
 
	 * handled by our crash handler instead of returning straight to the OS.
 
	 * @note must be implemented by all implementers of CrashLog.
 
	 */
 
	static void InitialiseCrashLog();
 

	
 
	/**
 
	 * Prepare crash log handler for a newly started thread.
 
	 * @note must be implemented by all implementers of CrashLog.
 
	 */
 
	static void InitThread();
 

	
 
	static void SetErrorMessage(const char *message);
 
	static void AfterCrashLogCleanup();
 
};
 

	
 
#endif /* CRASHLOG_H */
src/os/macosx/crashlog_osx.cpp
Show inline comments
 
@@ -248,12 +248,16 @@ void CDECL HandleCrash(int signum)
 
	}
 

	
 
	CrashLog::AfterCrashLogCleanup();
 
	abort();
 
}
 

	
 
/* static */ void CrashLog::InitialiseCrashLog()
 
{
 
	for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) {
 
		signal(*i, HandleCrash);
 
	}
 
}
 

	
 
/* static */ void CrashLog::InitThread()
 
{
 
}
src/os/unix/crashlog_unix.cpp
Show inline comments
 
@@ -172,12 +172,16 @@ static void CDECL HandleCrash(int signum
 
	log.MakeCrashLog();
 

	
 
	CrashLog::AfterCrashLogCleanup();
 
	abort();
 
}
 

	
 
/* static */ void CrashLog::InitialiseCrashLog()
 
{
 
	for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) {
 
		signal(*i, HandleCrash);
 
	}
 
}
 

	
 
/* static */ void CrashLog::InitThread()
 
{
 
}
src/os/windows/crashlog_win.cpp
Show inline comments
 
@@ -528,25 +528,25 @@ char *CrashLogWindows::AppendDecodedStac
 
	}
 
	return ret;
 
}
 
#endif /* _MSC_VER */
 

	
 
extern bool CloseConsoleLogIfActive();
 
static void ShowCrashlogWindow();
 

	
 
/**
 
 * Stack pointer for use when 'starting' the crash handler.
 
 * Not static as gcc's inline assembly needs it that way.
 
 */
 
void *_safe_esp = nullptr;
 
thread_local void *_safe_esp = nullptr;
 

	
 
static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep)
 
{
 
	/* Restore system timer resolution. */
 
	timeEndPeriod(1);
 

	
 
	/* Disable our event loop. */
 
	SetWindowLongPtr(GetActiveWindow(), GWLP_WNDPROC, (LONG_PTR)&DefWindowProc);
 

	
 
	if (CrashLogWindows::current != nullptr) {
 
		CrashLog::AfterCrashLogCleanup();
 
		ExitProcess(2);
 
@@ -596,54 +596,61 @@ static LONG WINAPI ExceptionHandler(EXCE
 

	
 
	CrashLog::AfterCrashLogCleanup();
 
	return EXCEPTION_EXECUTE_HANDLER;
 
}
 

	
 
static void CDECL CustomAbort(int signal)
 
{
 
	RaiseException(0xE1212012, 0, 0, nullptr);
 
}
 

	
 
/* static */ void CrashLog::InitialiseCrashLog()
 
{
 
	CrashLog::InitThread();
 

	
 
	/* SIGABRT is not an unhandled exception, so we need to intercept it. */
 
	signal(SIGABRT, CustomAbort);
 
#if defined(_MSC_VER)
 
	/* Don't show abort message as we will get the crashlog window anyway. */
 
	_set_abort_behavior(0, _WRITE_ABORT_MSG);
 
#endif
 
	SetUnhandledExceptionFilter(ExceptionHandler);
 
}
 

	
 
/* static */ void CrashLog::InitThread()
 
{
 
#if defined(_M_AMD64) || defined(_M_ARM64)
 
	CONTEXT ctx;
 
	RtlCaptureContext(&ctx);
 

	
 
	/* The stack pointer for AMD64 must always be 16-byte aligned inside a
 
	 * function. As we are simulating a function call with the safe ESP value,
 
	 * we need to subtract 8 for the imaginary return address otherwise stack
 
	 * alignment would be wrong in the called function. */
 
#if defined(_M_ARM64)
 
#	if defined(_M_ARM64)
 
	_safe_esp = (void *)(ctx.Sp - 8);
 
#else
 
#	else
 
	_safe_esp = (void *)(ctx.Rsp - 8);
 
#endif
 
#else
 
#if defined(_MSC_VER)
 
	_asm {
 
		mov _safe_esp, esp
 
	}
 
#	endif
 
#else
 
	asm("movl %esp, __safe_esp");
 
#endif
 
	void *safe_esp;
 
#	if defined(_MSC_VER)
 
	_asm {
 
		mov safe_esp, esp
 
	}
 
#	else
 
	asm("movl %esp, _safe_esp");
 
#	endif
 
	_safe_esp = safe_esp;
 
#endif
 

	
 
	/* SIGABRT is not an unhandled exception, so we need to intercept it. */
 
	signal(SIGABRT, CustomAbort);
 
#if defined(_MSC_VER)
 
	/* Don't show abort message as we will get the crashlog window anyway. */
 
	_set_abort_behavior(0, _WRITE_ABORT_MSG);
 
#endif
 
	SetUnhandledExceptionFilter(ExceptionHandler);
 
}
 

	
 
/* The crash log GUI */
 

	
 
static bool _expanded;
 

	
 
static const wchar_t _crash_desc[] =
 
	L"A serious fault condition occurred in the game. The game will shut down.\n"
 
	L"Please send the crash information and the crash.dmp file (if any) to the developers.\n"
 
	L"This will greatly help debugging. The correct place to do this is https://github.com/OpenTTD/OpenTTD/issues. "
 
	L"The information contained in the report is displayed below.\n"
 
	L"Press \"Emergency save\" to attempt saving the game. Generated file(s):\n"
src/thread.h
Show inline comments
 
@@ -2,24 +2,25 @@
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file thread.h Base of all threads. */
 

	
 
#ifndef THREAD_H
 
#define THREAD_H
 

	
 
#include "debug.h"
 
#include "crashlog.h"
 
#include <system_error>
 
#include <thread>
 

	
 
/**
 
 * Sleep on the current thread for a defined time.
 
 * @param milliseconds Time to sleep for in milliseconds.
 
 */
 
inline void CSleep(int milliseconds)
 
{
 
	std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
 
}
 

	
 
@@ -38,24 +39,25 @@ void SetCurrentThreadName(const char *na
 
 * @param name Name of the thread.
 
 * @param _Fx Function to call on the thread.
 
 * @param _Ax Arguments for the thread function.
 
 * @return True if the thread was successfully started, false otherwise.
 
 */
 
template<class TFn, class... TArgs>
 
inline bool StartNewThread(std::thread *thr, const char *name, TFn&& _Fx, TArgs&&... _Ax)
 
{
 
#ifndef NO_THREADS
 
	try {
 
		std::thread t([] (const char *name, TFn&& F, TArgs&&... A) {
 
				SetCurrentThreadName(name);
 
				CrashLog::InitThread();
 
				try {
 
					/* Call user function with the given arguments. */
 
					F(A...);
 
				} catch (...) {
 
					NOT_REACHED();
 
				}
 
			}, name, std::forward<TFn>(_Fx), std::forward<TArgs>(_Ax)...);
 

	
 
		if (thr != nullptr) {
 
			*thr = std::move(t);
 
		} else {
 
			t.detach();
0 comments (0 inline, 0 general)