summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/kernel
diff options
context:
space:
mode:
authorThomas McGuire <thomas.mcguire@kdab.com>2014-02-05 16:58:24 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-08 14:32:53 +0100
commit6f5db32abee3826151b9230ee7dca56ada4a3a89 (patch)
tree0784416e7ca10b573e4581f7fc73264215cc483a /tests/auto/corelib/kernel
parentf34b7f42e5c9d2a50da51dbba5fa18467d0262c0 (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.cpp42
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