summaryrefslogtreecommitdiffstats
path: root/tests/auto/qthreadstorage
diff options
context:
space:
mode:
authorOlivier Goffart <olivier.goffart@nokia.com>2010-11-04 13:37:48 +0100
committerOlivier Goffart <olivier.goffart@nokia.com>2010-11-22 15:09:06 +0100
commited8f3b6c98f1b305f0d183bc70c5f810a9c45ef2 (patch)
tree22aef970e281ab956b34d1f25ca6f7d037f57caa /tests/auto/qthreadstorage
parentfb026f81bfe64be232a819fdac5b8dbcdd4fae4d (diff)
QThreadStorage: fix memory leak if thread storage are added while destroying
The destructor(q) function could use itself and create new QThreadStorage. This might be the case for example, when using qDebug in a destructor. Task-number: QTBUG-14579 Reveiwed-by: Joao Reviewed-by: Brad
Diffstat (limited to 'tests/auto/qthreadstorage')
-rw-r--r--tests/auto/qthreadstorage/tst_qthreadstorage.cpp72
1 files changed, 72 insertions, 0 deletions
diff --git a/tests/auto/qthreadstorage/tst_qthreadstorage.cpp b/tests/auto/qthreadstorage/tst_qthreadstorage.cpp
index ed86165731..54f8bd9b37 100644
--- a/tests/auto/qthreadstorage/tst_qthreadstorage.cpp
+++ b/tests/auto/qthreadstorage/tst_qthreadstorage.cpp
@@ -77,6 +77,7 @@ private slots:
void adoptedThreads();
void ensureCleanupOrder();
void QTBUG13877_crashOnExit();
+ void QTBUG14579_leakInDestructor();
};
class Pointer
@@ -310,5 +311,76 @@ void tst_QThreadStorage::QTBUG13877_crashOnExit()
QVERIFY(process.exitStatus() != QProcess::CrashExit);
}
+// S stands for thread Safe.
+class SPointer
+{
+public:
+ static QBasicAtomicInt count;
+ inline SPointer() { count.ref(); }
+ inline ~SPointer() { count.deref(); }
+};
+QBasicAtomicInt SPointer::count = Q_BASIC_ATOMIC_INITIALIZER(0);
+
+Q_GLOBAL_STATIC(QThreadStorage<SPointer *>, QTBUG14579_pointers1)
+Q_GLOBAL_STATIC(QThreadStorage<SPointer *>, QTBUG14579_pointers2)
+
+class QTBUG14579_class
+{
+public:
+ SPointer member;
+ inline ~QTBUG14579_class() {
+ QVERIFY(!QTBUG14579_pointers1()->hasLocalData());
+ QVERIFY(!QTBUG14579_pointers2()->hasLocalData());
+ QTBUG14579_pointers2()->setLocalData(new SPointer);
+ QTBUG14579_pointers1()->setLocalData(new SPointer);
+ QVERIFY(QTBUG14579_pointers1()->hasLocalData());
+ QVERIFY(QTBUG14579_pointers2()->hasLocalData());
+ }
+};
+
+
+void tst_QThreadStorage::QTBUG14579_leakInDestructor()
+{
+ class Thread : public QThread
+ {
+ public:
+ QThreadStorage<QTBUG14579_class *> &tls;
+
+ Thread(QThreadStorage<QTBUG14579_class *> &t) : tls(t) { }
+
+ void run()
+ {
+ QVERIFY(!tls.hasLocalData());
+ tls.setLocalData(new QTBUG14579_class);
+ QVERIFY(tls.hasLocalData());
+ }
+ };
+ int c = SPointer::count;
+
+ QThreadStorage<QTBUG14579_class *> tls;
+
+ QVERIFY(!QTBUG14579_pointers1()->hasLocalData());
+ QThreadStorage<int *> tls2; //add some more tls to make sure ids are not following each other too much
+ QThreadStorage<int *> tls3;
+ QVERIFY(!tls2.hasLocalData());
+ QVERIFY(!tls3.hasLocalData());
+ QVERIFY(!tls.hasLocalData());
+
+ Thread t1(tls);
+ Thread t2(tls);
+ Thread t3(tls);
+
+ t1.start();
+ t2.start();
+ t3.start();
+
+ QVERIFY(t1.wait());
+ QVERIFY(t2.wait());
+ QVERIFY(t3.wait());
+
+ //check all the constructed things have been destructed
+ QCOMPARE(int(SPointer::count), c);
+}
+
QTEST_MAIN(tst_QThreadStorage)
#include "tst_qthreadstorage.moc"