qFatal: Prevent deadlocks on Windows

We began using abort() on 25d6f312ac
(5.8), which improved since we stopped using exit() with MSVC. However,
abort() with MinGW and on debug-mode MSVC's CRT calls _exit(), which
attempts to cleanly unload the DLLs, which in turn may run global
destructors.

[ChangeLog][QtCore][Important behavior changes] qFatal() no longer uses
std::abort() on Windows, as there are circumstances where global
destructors are still run after that call, leading to possible
deadlocks.

Task-number: QTBUG-34460
Change-Id: I2bec439d0e9841f58c7ffffd152200e45f1df982
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Reviewed-by: Kai Koehne <kai.koehne@qt.io>
bb10
Thiago Macieira 2018-04-03 11:36:44 -07:00
parent f240efaa35
commit f4394c86b6
1 changed files with 28 additions and 1 deletions

View File

@ -2,7 +2,7 @@
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
** Copyright (C) 2016 Intel Corporation.
** Copyright (C) 2018 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -61,6 +61,9 @@
#ifdef Q_OS_WIN
#include <qt_windows.h>
#endif
#ifdef Q_CC_MSVC
#include <intrin.h>
#endif
#if QT_CONFIG(slog2)
#include <sys/slog2.h>
#endif
@ -1839,7 +1842,31 @@ static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, const
Q_UNUSED(message);
#endif
#ifdef Q_OS_WIN
// std::abort() in the MSVC runtime will call _exit(3) if the abort
// behavior is _WRITE_ABORT_MSG - see also _set_abort_behavior(). This is
// the default for a debug-mode build of the runtime. Worse, MinGW's
// std::abort() implementation (in msvcrt.dll) is basically a call to
// _exit(3) too. Unfortunately, _exit() and _Exit() *do* run the static
// destructors of objects in DLLs, a violation of the C++ standard (see
// [support.start.term]). So we bypass std::abort() and directly
// terminate the application.
# ifdef Q_CC_MSVC
if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))
__fastfail(FAST_FAIL_FATAL_APP_EXIT);
# else
RaiseFailFastException(nullptr, nullptr, 0);
# endif
// Fallback
TerminateProcess(GetCurrentProcess(), STATUS_FATAL_APP_EXIT);
// Tell the compiler the application has stopped.
Q_UNREACHABLE_IMPL();
#else // !Q_OS_WIN
std::abort();
#endif
}