Make QMetaObject::Connection check its state deeply

Since Connection can be copied, one copy could be used for
disconnecting, but the other's d_ptr wouldn't get updated and would
continue to report as still connected.

This patch fixes that by making it check the internal state. That is
only done after d_ptr is already known to be non-null. Unfortunately,
that is the common path:

  if (connect(sender, &Sender::signal, [] {}))

will call an out-of-line function. I don't see a way out.

Task-number: QTBUG-46213
Change-Id: I66a35ce5f88941f29aa6ffff13dfb45dca68a350
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
This commit is contained in:
Thiago Macieira 2015-05-19 11:49:37 -07:00
parent 54589f2932
commit b2be272d35
3 changed files with 18 additions and 2 deletions

View File

@ -4913,6 +4913,16 @@ QMetaObject::Connection::~Connection()
static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
}
/*! \internal Returns true if the object is still connected */
bool QMetaObject::Connection::isConnected_helper() const
{
Q_ASSERT(d_ptr); // we're only called from operator RestrictedBool() const
QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(d_ptr);
return c->receiver;
}
/*!
\fn QMetaObject::Connection::operator bool() const

View File

@ -472,6 +472,7 @@ class Q_CORE_EXPORT QMetaObject::Connection {
friend class QObject;
friend class QObjectPrivate;
friend struct QMetaObject;
bool isConnected_helper() const;
public:
~Connection();
Connection();
@ -481,7 +482,7 @@ public:
operator bool() const;
#else
typedef void *Connection::*RestrictedBool;
operator RestrictedBool() const { return d_ptr ? &Connection::d_ptr : 0; }
operator RestrictedBool() const { return d_ptr && isConnected_helper() ? &Connection::d_ptr : 0; }
#endif
#ifdef Q_COMPILER_RVALUE_REFS

View File

@ -918,6 +918,8 @@ void tst_QObject::connectDisconnectNotifyPMF()
QMetaObject::Connection conn = connect((SenderObject*)s, &SenderObject::signal1,
(ReceiverObject*)r, &ReceiverObject::slot1);
QVERIFY(conn);
// Test disconnectNotify when disconnecting by QMetaObject::Connection
QVERIFY(QObject::disconnect(conn));
// disconnectNotify() is not called, but it probably should be.
@ -5751,7 +5753,6 @@ void tst_QObject::connectFunctorWithContext()
{
int status = 1;
SenderObject obj;
QMetaObject::Connection handle;
ContextObject *context = new ContextObject;
QEventLoop e;
@ -6058,8 +6059,12 @@ void tst_QObject::disconnectDoesNotLeakFunctor()
QVERIFY(c2);
QCOMPARE(countedStructObjectsCount, 2);
QVERIFY(QObject::disconnect(c1));
QVERIFY(!c1);
QVERIFY(!c2);
// functor object has been destroyed
QCOMPARE(countedStructObjectsCount, 1);
QVERIFY(!QObject::disconnect(c2));
QCOMPARE(countedStructObjectsCount, 1);
}
QCOMPARE(countedStructObjectsCount, 0);
}