QLogging: Avoid infinite loop in error case

If the user code installs a message handler that uses
any API that prints logs (handled by qt_message_print)
then this will lead to an infinite loop.

This patch adds a thread local storage to check
if the message handler is done before the thread
is calling it again.

Note: This check is performed only if the compiler
supports thread_local (__declspec(thread) for MSVC).

Change-Id: I43b0460b8f39b26a18de48a5652a5e55f0b336f8
Reviewed-by: Rafael Roquetto <rafael.roquetto@kdab.com>
bb10
El Mehdi Fekari 2013-12-19 11:15:34 +01:00 committed by The Qt Project
parent e5fd241770
commit 61e1bcb4dd
1 changed files with 38 additions and 5 deletions

View File

@ -925,6 +925,32 @@ static void qDefaultMsgHandler(QtMsgType type, const char *buf)
qDefaultMessageHandler(type, emptyContext, QString::fromLocal8Bit(buf));
}
#if defined(Q_COMPILER_THREAD_LOCAL) || (defined(Q_CC_MSVC) && !defined(Q_OS_WINCE))
#if defined(Q_CC_MSVC)
static __declspec(thread) bool msgHandlerGrabbed = false;
#else
static thread_local bool msgHandlerGrabbed = false;
#endif
static bool grabMessageHandler()
{
if (msgHandlerGrabbed)
return false;
msgHandlerGrabbed = true;
return true;
}
static void ungrabMessageHandler()
{
msgHandlerGrabbed = false;
}
#else
static bool grabMessageHandler() { return true; }
static void ungrabMessageHandler() { }
#endif // (Q_COMPILER_THREAD_LOCAL) || ((Q_CC_MSVC) && !(Q_OS_WINCE))
static void qt_message_print(QtMsgType msgType, const QMessageLogContext &context, const QString &message)
{
#ifndef QT_BOOTSTRAPPED
@ -942,12 +968,19 @@ static void qt_message_print(QtMsgType msgType, const QMessageLogContext &contex
if (!messageHandler)
messageHandler = qDefaultMessageHandler;
// prefer new message handler over the old one
if (msgHandler == qDefaultMsgHandler
|| messageHandler != qDefaultMessageHandler) {
(*messageHandler)(msgType, context, message);
// prevent recursion in case the message handler generates messages
// itself, e.g. by using Qt API
if (grabMessageHandler()) {
// prefer new message handler over the old one
if (msgHandler == qDefaultMsgHandler
|| messageHandler != qDefaultMessageHandler) {
(*messageHandler)(msgType, context, message);
} else {
(*msgHandler)(msgType, message.toLocal8Bit().constData());
}
ungrabMessageHandler();
} else {
(*msgHandler)(msgType, message.toLocal8Bit().constData());
fprintf(stderr, "%s", message.toLocal8Bit().constData());
}
}