diff options
author | Dario Freddi <dario.freddi@ispirata.com> | 2013-08-07 11:17:25 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-08-07 12:42:45 +0200 |
commit | 5885b8f775998c30d53f40b7f368c5f6364e6df4 (patch) | |
tree | 7921f5dc1d9dfde2fd45cfe53ca2dcde46ed7e7a /src/corelib | |
parent | 4881f9db7cf338f8dc5233591bd5c11ecd2f8ca9 (diff) |
qobject: Do not destroy slot objects inside a lock
This prevents deadlocks in case the destructor re-enters.
(Example: a functor containing a QSharedPointer of a QObject)
This also fixes a leaked slot object in disconnectHelper.
Change-Id: Ia939790e3b54e64067b99540974306b4808a77f2
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 34 |
1 files changed, 26 insertions, 8 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 02794e9fe3..33e2adf5ba 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -816,6 +816,14 @@ QObject::~QObject() m->unlock(); connectionList.first = c->nextConnectionList; + + // The destroy operation must happen outside the lock + if (c->isSlotObject) { + locker.unlock(); + c->slotObj->destroyIfLastRef(); + c->isSlotObject = false; + locker.relock(); + } c->deref(); } } @@ -3135,6 +3143,13 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, c->receiver = 0; + if (c->isSlotObject) { + senderMutex->unlock(); + c->slotObj->destroyIfLastRef(); + c->isSlotObject = false; + senderMutex->lock(); + } + success = true; if (disconnectType == DisconnectOne) @@ -4363,16 +4378,19 @@ bool QObject::disconnect(const QMetaObject::Connection &connection) QMutex *senderMutex = signalSlotLock(c->sender); QMutex *receiverMutex = signalSlotLock(c->receiver); - QOrderedMutexLocker locker(senderMutex, receiverMutex); - QObjectConnectionListVector *connectionLists = QObjectPrivate::get(c->sender)->connectionLists; - Q_ASSERT(connectionLists); - connectionLists->dirty = true; + { + QOrderedMutexLocker locker(senderMutex, receiverMutex); - *c->prev = c->next; - if (c->next) - c->next->prev = c->prev; - c->receiver = 0; + QObjectConnectionListVector *connectionLists = QObjectPrivate::get(c->sender)->connectionLists; + Q_ASSERT(connectionLists); + connectionLists->dirty = true; + + *c->prev = c->next; + if (c->next) + c->next->prev = c->prev; + c->receiver = 0; + } // destroy the QSlotObject, if possible if (c->isSlotObject) { |