From d49f7168aba2770cc39d463adeeffc4e9635f4dc Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Sat, 5 Jul 2014 16:24:17 +0200 Subject: QObject: don't hold mutex when copying arguments in a QueuedConnection QMetaType::create can call user code and we should not keep mutex held as this may cause dead lock. Make sure the tst_qobjectrace actually emit some signal so the test check there is no race if the receiver object is destroyed while the mutex is unlocked. Task-number: QTBUG-39990 Change-Id: I56ca1ae7a11cd7b33c1a68727370972862e11c2f Reviewed-by: Thiago Macieira --- src/corelib/kernel/qobject.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 6670311353..fb01df3099 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -3512,7 +3512,8 @@ void QMetaObject::connectSlotsByName(QObject *o) \a signal must be in the signal index range (see QObjectPrivate::signalIndex()). */ -static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv) +static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv, + QMutexLocker &locker) { const int *argumentTypes = c->argumentTypes.load(); if (!argumentTypes && argumentTypes != &DIRECT_CONNECTION_ONLY) { @@ -3537,8 +3538,28 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect Q_CHECK_PTR(args); types[0] = 0; // return type args[0] = 0; // return value - for (int n = 1; n < nargs; ++n) - args[n] = QMetaType::create((types[n] = argumentTypes[n-1]), argv[n]); + + if (nargs > 1) { + for (int n = 1; n < nargs; ++n) + types[n] = argumentTypes[n-1]; + + locker.unlock(); + for (int n = 1; n < nargs; ++n) + args[n] = QMetaType::create(types[n], argv[n]); + locker.relock(); + + if (!c->receiver) { + locker.unlock(); + // we have been disconnected while the mutex was unlocked + for (int n = 1; n < nargs; ++n) + QMetaType::destroy(types[n], args[n]); + free(types); + free(args); + locker.relock(); + return; + } + } + QMetaCallEvent *ev = c->isSlotObject ? new QMetaCallEvent(c->slotObj, sender, signal, nargs, types, args) : new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs, types, args); @@ -3638,7 +3659,7 @@ void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_i // put into the event queue if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread) || (c->connectionType == Qt::QueuedConnection)) { - queued_activate(sender, signal_index, c, argv ? argv : empty_argv); + queued_activate(sender, signal_index, c, argv ? argv : empty_argv, locker); continue; #ifndef QT_NO_THREAD } else if (c->connectionType == Qt::BlockingQueuedConnection) { -- cgit v1.2.3