Fix race condition between destruction of QObjects

If the two QObjecs are connected and destroyed at the same time, it
is possible to hit a case where QObject::metaObject and QObject::disconnectNotify
is called on a destroyed object.

This patch moves the calls up before the removal of the connection. This
ensure the sender object will have to block on the receivers connection
mutex and can not finish destruction before disconnectNotify is called.

Task-number: QTBUG-34131
Change-Id: I398116fe7bc6a195991aff9961d89a8b0ac8d53c
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
Allan Sandfeld Jensen 2013-11-21 15:22:53 +01:00 committed by The Qt Project
parent bb090fa76e
commit 3f97e38440

View File

@ -868,6 +868,10 @@ QObject::~QObject()
QObjectPrivate::Connection *node = d->senders;
while (node) {
QObject *sender = node->sender;
// Send disconnectNotify before removing the connection from sender's connection list.
// This ensures any eventual destructor of sender will block on getting receiver's lock
// and not finish until we release it.
sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), node->signal_index));
QMutex *m = signalSlotLock(sender);
node->prev = &node;
bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
@ -881,8 +885,6 @@ QObject::~QObject()
if (senderLists)
senderLists->dirty = true;
int signal_index = node->signal_index;
QtPrivate::QSlotObjectBase *slotObj = Q_NULLPTR;
if (node->isSlotObject) {
slotObj = node->slotObj;
@ -899,7 +901,6 @@ QObject::~QObject()
locker.relock();
}
sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), signal_index));
}
}