diff options
author | Jędrzej Nowacki <jedrzej.nowacki@digia.com> | 2013-02-12 14:08:48 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-02-20 15:22:55 +0100 |
commit | dacc222d5a3327fb27d69e57d99111cdf9084304 (patch) | |
tree | de03a59bba5f628b51fa03a4230b43c215da12ee /tests | |
parent | d3a4230757931a704f36dd1eb4917a5ce61f80b4 (diff) |
Fix QVector detaching in one thread while another destroys it.
The patch adds handling for a case when a QVector is shared between two
threads. In such scenario detaching in one thread could collide with
destruction in the other one, causing a memory leak or assert in debug
mode.
Task-number: QTBUG-29134
Change-Id: Idbff250d9cfc6cf83174954ea91dbf41f8ea4aa4
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/corelib/tools/qvector/tst_qvector.cpp | 78 |
1 files changed, 77 insertions, 1 deletions
diff --git a/tests/auto/corelib/tools/qvector/tst_qvector.cpp b/tests/auto/corelib/tools/qvector/tst_qvector.cpp index c5ed44b952..7738a2c797 100644 --- a/tests/auto/corelib/tools/qvector/tst_qvector.cpp +++ b/tests/auto/corelib/tools/qvector/tst_qvector.cpp @@ -41,6 +41,8 @@ #include <QtTest/QtTest> #include <QAtomicInt> +#include <QThread> +#include <QSemaphore> #include <qvector.h> struct Movable { @@ -272,6 +274,9 @@ private slots: void detachInt() const; void detachMovable() const; void detachCustom() const; + void detachThreadSafetyInt() const; + void detachThreadSafetyMovable() const; + void detachThreadSafetyCustom() const; private: template<typename T> void copyConstructor() const; @@ -295,6 +300,7 @@ private: template<typename T> void setSharable_data() const; template<typename T> void setSharable() const; template<typename T> void detach() const; + template<typename T> void detachThreadSafety() const; }; @@ -2213,5 +2219,75 @@ void tst_QVector::detachCustom() const QCOMPARE(instancesCount, Custom::counter.loadAcquire()); } -QTEST_APPLESS_MAIN(tst_QVector) +static QAtomicPointer<QVector<int> > detachThreadSafetyDataInt; +static QAtomicPointer<QVector<Movable> > detachThreadSafetyDataMovable; +static QAtomicPointer<QVector<Custom> > detachThreadSafetyDataCustom; + +template<typename T> QAtomicPointer<QVector<T> > *detachThreadSafetyData(); +template<> QAtomicPointer<QVector<int> > *detachThreadSafetyData() { return &detachThreadSafetyDataInt; } +template<> QAtomicPointer<QVector<Movable> > *detachThreadSafetyData() { return &detachThreadSafetyDataMovable; } +template<> QAtomicPointer<QVector<Custom> > *detachThreadSafetyData() { return &detachThreadSafetyDataCustom; } + +static QSemaphore detachThreadSafetyLock; + +template<typename T> +void tst_QVector::detachThreadSafety() const +{ + delete detachThreadSafetyData<T>()->fetchAndStoreOrdered(new QVector<T>(SimpleValue<T>::vector(400))); + + static const uint threadsCount = 5; + + struct : QThread { + void run() Q_DECL_OVERRIDE + { + QVector<T> copy(*detachThreadSafetyData<T>()->load()); + QVERIFY(!copy.isDetached()); + detachThreadSafetyLock.release(); + detachThreadSafetyLock.acquire(100); + copy.detach(); + } + } threads[threadsCount]; + + for (uint i = 0; i < threadsCount; ++i) + threads[i].start(); + QThread::yieldCurrentThread(); + detachThreadSafetyLock.acquire(threadsCount); + + // destroy static original data + delete detachThreadSafetyData<T>()->fetchAndStoreOrdered(0); + + QVERIFY(threadsCount < 100); + detachThreadSafetyLock.release(threadsCount * 100); + QThread::yieldCurrentThread(); + + for (uint i = 0; i < threadsCount; ++i) + threads[i].wait(); +} + +void tst_QVector::detachThreadSafetyInt() const +{ + for (uint i = 0; i < 128; ++i) + detachThreadSafety<int>(); +} + +void tst_QVector::detachThreadSafetyMovable() const +{ + const int instancesCount = Movable::counter.loadAcquire(); + for (uint i = 0; i < 128; ++i) { + detachThreadSafety<Movable>(); + QCOMPARE(Movable::counter.loadAcquire(), instancesCount); + } +} + +void tst_QVector::detachThreadSafetyCustom() const +{ + const int instancesCount = Custom::counter.loadAcquire(); + for (uint i = 0; i < 128; ++i) { + detachThreadSafety<Custom>(); + QCOMPARE(Custom::counter.loadAcquire(), instancesCount); + } +} + + +QTEST_MAIN(tst_QVector) #include "tst_qvector.moc" |