diff options
author | Thomas McGuire <thomas.mcguire@kdab.com> | 2014-02-05 16:58:24 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-02-08 14:32:53 +0100 |
commit | 6f5db32abee3826151b9230ee7dca56ada4a3a89 (patch) | |
tree | 0784416e7ca10b573e4581f7fc73264215cc483a /tests/auto/corelib/kernel | |
parent | f34b7f42e5c9d2a50da51dbba5fa18467d0262c0 (diff) |
Don't deadlock when deleting slot objects in QMetaObject::activate()
The slot object was deleted after the mutex was relocked, which caused
a deadlock in case the functor destructor locked the same mutex again.
Change-Id: I5b4fb22fdb4483f91c89915872bfd548c31b0eea
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
Diffstat (limited to 'tests/auto/corelib/kernel')
-rw-r--r-- | tests/auto/corelib/kernel/qobject/tst_qobject.cpp | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index f1e04511cd..f0df10744d 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -146,6 +146,7 @@ private slots: void connectFunctorOverloads(); void connectFunctorQueued(); void connectFunctorWithContext(); + void connectFunctorDeadlock(); void connectStaticSlotWithObject(); void disconnectDoesNotLeakFunctor(); void contextDoesNotLeakFunctor(); @@ -5698,6 +5699,47 @@ void tst_QObject::connectFunctorWithContext() context->deleteLater(); } +class MyFunctor +{ +public: + explicit MyFunctor(QObject *objectToDisconnect) + : m_objectToDisconnect(objectToDisconnect) + {} + + ~MyFunctor() { + // Do operations that will lock the internal signalSlotLock mutex on many QObjects. + // The more QObjects, the higher the chance that the signalSlotLock mutex used + // is already in use. If the number of objects is higher than the number of mutexes in + // the pool (currently 131), the deadlock should always trigger. Use an even higher number + // to be on the safe side. + const int objectCount = 1024; + SenderObject lotsOfObjects[objectCount]; + for (int i = 0; i < objectCount; ++i) { + QObject::connect(&lotsOfObjects[i], &SenderObject::signal1, + &lotsOfObjects[i], &SenderObject::aPublicSlot); + } + } + + void operator()() { + // This will cause the slot object associated with this functor to be destroyed after + // this function returns. That in turn will destroy this functor. + // If our dtor runs with the signalSlotLock held, the bunch of connect() + // performed there will deadlock trying to lock that lock again. + m_objectToDisconnect->disconnect(); + } + +private: + QObject *m_objectToDisconnect; +}; + +void tst_QObject::connectFunctorDeadlock() +{ + SenderObject sender; + MyFunctor functor(&sender); + QObject::connect(&sender, &SenderObject::signal1, functor); + sender.emitSignal1(); +} + static int s_static_slot_checker = 1; class StaticSlotChecker : public QObject |