qDebug: fix data race in qt_message_print

The setting of (static) messageHandler to qDefaultMessageHandler if null
was happening in multiple threads simultaneously, so it needs synchronization.

Used an atomic pointer in case qInstallMessageHandler is called from a thread,
but more importantly, initialized the static vars right away.

Improve auto test to ensure that qInstallMessageHandler(0) still sets the
default message handler.

Change-Id: I70335af38c1d28a1cdba1df8a79c6006f227422e
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
David Faure 2014-06-08 14:10:56 +02:00
parent 0272ce6417
commit 9ee27005ee
2 changed files with 24 additions and 27 deletions

View File

@ -1148,8 +1148,13 @@ typedef void (*QtMsgHandler)(QtMsgType, const char *);
Q_CORE_EXPORT QtMsgHandler qInstallMsgHandler(QtMsgHandler);
#endif
static QtMsgHandler msgHandler = 0; // pointer to debug handler (without context)
static QtMessageHandler messageHandler = 0; // pointer to debug handler (with context)
static void qDefaultMsgHandler(QtMsgType type, const char *buf);
static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &buf);
// pointer to QtMsgHandler debug handler (without context)
static QBasicAtomicPointer<void (QtMsgType, const char*)> msgHandler = Q_BASIC_ATOMIC_INITIALIZER(qDefaultMsgHandler);
// pointer to QtMessageHandler debug handler (with context)
static QBasicAtomicPointer<void (QtMsgType, const QMessageLogContext &, const QString &)> messageHandler = Q_BASIC_ATOMIC_INITIALIZER(qDefaultMessageHandler);
#if defined(QT_USE_JOURNALD) && !defined(QT_BOOTSTRAPPED)
static void systemd_default_message_handler(QtMsgType type,
@ -1315,20 +1320,15 @@ static void qt_message_print(QtMsgType msgType, const QMessageLogContext &contex
}
#endif
if (!msgHandler)
msgHandler = qDefaultMsgHandler;
if (!messageHandler)
messageHandler = qDefaultMessageHandler;
// 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);
if (msgHandler.load() == qDefaultMsgHandler
|| messageHandler.load() != qDefaultMessageHandler) {
(*messageHandler.load())(msgType, context, message);
} else {
(*msgHandler)(msgType, message.toLocal8Bit().constData());
(*msgHandler.load())(msgType, message.toLocal8Bit().constData());
}
ungrabMessageHandler();
} else {
@ -1530,22 +1530,18 @@ void qErrnoWarning(int code, const char *msg, ...)
QtMessageHandler qInstallMessageHandler(QtMessageHandler h)
{
if (!messageHandler)
messageHandler = qDefaultMessageHandler;
QtMessageHandler old = messageHandler;
messageHandler = h;
return old;
if (!h)
h = qDefaultMessageHandler;
//set 'h' and return old message handler
return messageHandler.fetchAndStoreRelaxed(h);
}
QtMsgHandler qInstallMsgHandler(QtMsgHandler h)
{
//if handler is 0, set it to the
//default message handler
if (!msgHandler)
msgHandler = qDefaultMsgHandler;
QtMsgHandler old = msgHandler;
msgHandler = h;
return old;
if (!h)
h = qDefaultMsgHandler;
//set 'h' and return old message handler
return msgHandler.fetchAndStoreRelaxed(h);
}
void qSetMessagePattern(const QString &pattern)

View File

@ -299,12 +299,13 @@ void tst_QDebug::textStreamModifiers() const
void tst_QDebug::defaultMessagehandler() const
{
MessageHandlerSetter mhs(0);
QtMessageHandler defaultMessageHandler1 = qInstallMessageHandler((QtMessageHandler)0);
QtMessageHandler defaultMessageHandler2 = qInstallMessageHandler(myMessageHandler);
MessageHandlerSetter mhs(0); // set 0, should set default handler
QtMessageHandler defaultMessageHandler1 = qInstallMessageHandler((QtMessageHandler)0); // set 0, should set and return default handler
QVERIFY(defaultMessageHandler1);
QtMessageHandler defaultMessageHandler2 = qInstallMessageHandler(myMessageHandler); // set myMessageHandler and return default handler
bool same = (*defaultMessageHandler1 == *defaultMessageHandler2);
QVERIFY(same);
QtMessageHandler messageHandler = qInstallMessageHandler((QtMessageHandler)0);
QtMessageHandler messageHandler = qInstallMessageHandler((QtMessageHandler)0); // set 0, should set default and return myMessageHandler
same = (*messageHandler == *myMessageHandler);
QVERIFY(same);
}