diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index a0ee963713f..b5838d2e7b0 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -5275,11 +5275,20 @@ bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, const Q /*! \internal \threadsafe + + Thread-safety warning: this function may be called from any thread and is + thread-safe, \b{so long as the sender is not being deleted}. At the time of + this writing, this function is called from QObject::disconnect() and from + the multiple places where a single-shot connection is activated; in both + cases, the construction of the user code is already such that the sender + object cannot be undergoing deletion in another thread. */ bool QObjectPrivate::disconnect(QObjectPrivate::Connection *c) { if (!c) return false; + + // double-checked locking on this pointer QObject *receiver = c->receiver.loadRelaxed(); if (!receiver) return false; @@ -5300,7 +5309,6 @@ bool QObjectPrivate::disconnect(QObjectPrivate::Connection *c) Q_ASSERT(connections); connections->removeConnection(c); - c->sender->disconnectNotify(QMetaObjectPrivate::signal(c->sender->metaObject(), c->signal_index)); // We must not hold the receiver mutex, else we risk dead-locking; we also only need the sender mutex // It is however vital to hold the senderMutex before calling cleanOrphanedConnections, as otherwise // another thread might modify/delete the connection @@ -5312,6 +5320,8 @@ bool QObjectPrivate::disconnect(QObjectPrivate::Connection *c) locker.dismiss(); // so we dismiss the QOrderedMutexLocker } + // this is safe if the condition in the documentation is correct + c->sender->disconnectNotify(QMetaObjectPrivate::signal(c->sender->metaObject(), c->signal_index)); return true; }