diff options
author | Olivier Goffart <ogoffart@woboq.com> | 2014-07-05 16:24:17 +0200 |
---|---|---|
committer | Olivier Goffart <ogoffart@woboq.com> | 2014-07-07 08:45:56 +0200 |
commit | d49f7168aba2770cc39d463adeeffc4e9635f4dc (patch) | |
tree | d0c00b3ebfd5241535de6cf6cc86b465919c971d /src/corelib | |
parent | 7e488626ab484ef8f62be6f80791a0b3adae80ab (diff) |
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 <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 29 |
1 files changed, 25 insertions, 4 deletions
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) { |