From 61e1bcb4dd4995c9a8385aad6f3da10f53de2265 Mon Sep 17 00:00:00 2001 From: El Mehdi Fekari Date: Thu, 19 Dec 2013 11:15:34 +0100 Subject: 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 --- src/corelib/global/qlogging.cpp | 43 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 5b7a674ddb..cff8846cdc 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -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()); } } -- cgit v1.2.3