From 6797570a59529b90b5a28923825b56703173fa56 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 27 Feb 2017 12:13:13 +0100 Subject: [PATCH] Fix UB in QFutureInterface: invalid casts from ResultStoreBase to ResultStore<> ResultStore never actually exists, only ResutStoreBase does. So casting to ResultStore and calling its member functions is UB. Put the type dependent function as template member functions within ResultStoreBase and so we don't need QtPrivate::ResultStore anymore. Same goes for the iterator. Change-Id: I739b9d234ba2238977863df77fde3a4471a9abd2 Reviewed-by: Marc Mutz --- src/corelib/thread/qfutureinterface.h | 28 +++--- src/corelib/thread/qresultstore.cpp | 6 ++ src/corelib/thread/qresultstore.h | 64 ++++---------- .../corelib/thread/qfuture/tst_qfuture.cpp | 87 ++++++++++--------- .../thread/qresultstore/tst_qresultstore.cpp | 82 ++++++++--------- 5 files changed, 122 insertions(+), 145 deletions(-) diff --git a/src/corelib/thread/qfutureinterface.h b/src/corelib/thread/qfutureinterface.h index 559d26e231..7b12f51e3e 100644 --- a/src/corelib/thread/qfutureinterface.h +++ b/src/corelib/thread/qfutureinterface.h @@ -159,7 +159,7 @@ public: ~QFutureInterface() { if (!derefT()) - resultStore().clear(); + resultStoreBase().template clear(); } static QFutureInterface canceledResult() @@ -169,7 +169,7 @@ public: { other.refT(); if (!derefT()) - resultStore().clear(); + resultStoreBase().template clear(); QFutureInterfaceBase::operator=(other); return *this; } @@ -184,11 +184,6 @@ public: inline const T &resultReference(int index) const; inline const T *resultPointer(int index) const; inline QList results(); -private: - QtPrivate::ResultStore &resultStore() - { return static_cast &>(resultStoreBase()); } - const QtPrivate::ResultStore &resultStore() const - { return static_cast &>(resultStoreBase()); } }; template @@ -199,15 +194,14 @@ inline void QFutureInterface::reportResult(const T *result, int index) return; } - QtPrivate::ResultStore &store = resultStore(); - + QtPrivate::ResultStoreBase &store = resultStoreBase(); if (store.filterMode()) { const int resultCountBefore = store.count(); - store.addResult(index, result); + store.addResult(index, result); this->reportResultsReady(resultCountBefore, resultCountBefore + store.count()); } else { - const int insertIndex = store.addResult(index, result); + const int insertIndex = store.addResult(index, result); this->reportResultsReady(insertIndex, insertIndex + 1); } } @@ -226,7 +220,7 @@ inline void QFutureInterface::reportResults(const QVector &_results, int b return; } - QtPrivate::ResultStore &store = resultStore(); + auto &store = resultStoreBase(); if (store.filterMode()) { const int resultCountBefore = store.count(); @@ -250,14 +244,14 @@ template inline const T &QFutureInterface::resultReference(int index) const { QMutexLocker lock(mutex()); - return resultStore().resultAt(index).value(); + return resultStoreBase().resultAt(index).template value(); } template inline const T *QFutureInterface::resultPointer(int index) const { QMutexLocker lock(mutex()); - return resultStore().resultAt(index).pointer(); + return resultStoreBase().resultAt(index).template pointer(); } template @@ -272,9 +266,9 @@ inline QList QFutureInterface::results() QList res; QMutexLocker lock(mutex()); - QtPrivate::ResultIterator it = resultStore().begin(); - while (it != resultStore().end()) { - res.append(it.value()); + QtPrivate::ResultIteratorBase it = resultStoreBase().begin(); + while (it != resultStoreBase().end()) { + res.append(it.value()); ++it; } diff --git a/src/corelib/thread/qresultstore.cpp b/src/corelib/thread/qresultstore.cpp index aa7ec02d6e..9a6fcec678 100644 --- a/src/corelib/thread/qresultstore.cpp +++ b/src/corelib/thread/qresultstore.cpp @@ -98,6 +98,12 @@ bool ResultIteratorBase::canIncrementVectorIndex() const ResultStoreBase::ResultStoreBase() : insertIndex(0), resultCount(0), m_filterMode(false), filteredResults(0) { } +ResultStoreBase::~ResultStoreBase() +{ + // QFutureInterface's dtor must delete the contents of m_results. + Q_ASSERT(m_results.isEmpty()); +} + void ResultStoreBase::setFilterMode(bool enable) { m_filterMode = enable; diff --git a/src/corelib/thread/qresultstore.h b/src/corelib/thread/qresultstore.h index 56cfcb6ed6..be9f632557 100644 --- a/src/corelib/thread/qresultstore.h +++ b/src/corelib/thread/qresultstore.h @@ -93,20 +93,14 @@ public: protected: QMap::const_iterator mapIterator; int m_vectorIndex; -}; - -template -class ResultIterator : public ResultIteratorBase -{ public: - ResultIterator(const ResultIteratorBase &base) - : ResultIteratorBase(base) { } - + template const T &value() const { - return *pointer(); + return *pointer(); } + template const T *pointer() const { if (mapIterator.value().isVector()) @@ -130,7 +124,7 @@ public: ResultIteratorBase resultAt(int index) const; bool contains(int index) const; int count() const; - virtual ~ResultStoreBase() { } + virtual ~ResultStoreBase(); protected: int insertResultItem(int index, ResultItem &resultItem); @@ -147,64 +141,44 @@ protected: QMap pendingResults; int filteredResults; -}; - -template -class ResultStore : public ResultStoreBase -{ public: - ResultStore() { } - - ResultStore(const ResultStoreBase &base) - : ResultStoreBase(base) { } - - int addResult(int index, const T *result) + template + int addResult(int index, const T *result) { if (result == 0) - return ResultStoreBase::addResult(index, result); + return addResult(index, static_cast(nullptr)); else - return ResultStoreBase::addResult(index, new T(*result)); + return addResult(index, static_cast(new T(*result))); } + template int addResults(int index, const QVector *results) { - return ResultStoreBase::addResults(index, new QVector(*results), results->count(), results->count()); + return addResults(index, new QVector(*results), results->count(), results->count()); } + template int addResults(int index, const QVector *results, int totalCount) { if (m_filterMode == true && results->count() != totalCount && 0 == results->count()) - return ResultStoreBase::addResults(index, 0, 0, totalCount); + return addResults(index, 0, 0, totalCount); else - return ResultStoreBase::addResults(index, new QVector(*results), results->count(), totalCount); + return addResults(index, new QVector(*results), results->count(), totalCount); } int addCanceledResult(int index) { - return addResult(index, 0); + return addResult(index, static_cast(nullptr)); } + template int addCanceledResults(int index, int _count) { QVector empty; return addResults(index, &empty, _count); } - ResultIterator begin() const - { - return static_cast >(ResultStoreBase::begin()); - } - - ResultIterator end() const - { - return static_cast >(ResultStoreBase::end()); - } - - ResultIterator resultAt(int index) const - { - return static_cast >(ResultStoreBase::resultAt(index)); - } - + template void clear() { QMap::const_iterator mapIterator = m_results.constBegin(); @@ -218,12 +192,6 @@ public: resultCount = 0; m_results.clear(); } - - ~ResultStore() - { - clear(); - } - }; } // namespace QtPrivate diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp index b8841bb6a3..a546cad225 100644 --- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp +++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp @@ -43,6 +43,11 @@ # undef interface #endif +struct ResultStoreInt : QtPrivate::ResultStoreBase +{ + ~ResultStoreInt() { clear(); } +}; + class tst_QFuture: public QObject { Q_OBJECT @@ -78,7 +83,7 @@ void tst_QFuture::resultStore() int int2 = 2; { - QtPrivate::ResultStore store; + ResultStoreInt store; QCOMPARE(store.begin(), store.end()); QCOMPARE(store.resultAt(0), store.end()); QCOMPARE(store.resultAt(1), store.end()); @@ -86,9 +91,9 @@ void tst_QFuture::resultStore() { - QtPrivate::ResultStoreBase store; - store.addResult(-1, &int0); // note to self: adding a pointer to the stack here is ok since - store.addResult(1, &int1); // ResultStoreBase does not take ownership, only ResultStore<> does. + ResultStoreInt store; + store.addResult(-1, &int0); + store.addResult(1, &int1); QtPrivate::ResultIteratorBase it = store.begin(); QCOMPARE(it.resultIndex(), 0); QVERIFY(it == store.begin()); @@ -108,9 +113,9 @@ void tst_QFuture::resultStore() QVector vec1 = QVector() << 4 << 5; { - QtPrivate::ResultStoreBase store; - store.addResults(-1, &vec0, 2, 2); - store.addResults(-1, &vec1, 2, 2); + ResultStoreInt store; + store.addResults(-1, &vec0, 2); + store.addResults(-1, &vec1, 2); QtPrivate::ResultIteratorBase it = store.begin(); QCOMPARE(it.resultIndex(), 0); QCOMPARE(it, store.begin()); @@ -131,9 +136,9 @@ void tst_QFuture::resultStore() QCOMPARE(it, store.end()); } { - QtPrivate::ResultStoreBase store; + ResultStoreInt store; store.addResult(-1, &int0); - store.addResults(-1, &vec1, 2, 2); + store.addResults(-1, &vec1, 2); store.addResult(-1, &int1); QtPrivate::ResultIteratorBase it = store.begin(); @@ -162,7 +167,7 @@ void tst_QFuture::resultStore() QCOMPARE(store.resultAt(4), store.end()); } { - QtPrivate::ResultStore store; + ResultStoreInt store; store.addResult(-1, &int0); store.addResults(-1, &vec0); store.addResult(-1, &int1); @@ -186,36 +191,36 @@ void tst_QFuture::resultStore() ++it; QVERIFY(it == store.end()); - QCOMPARE(store.resultAt(0).value(), int0); - QCOMPARE(store.resultAt(1).value(), vec0[0]); - QCOMPARE(store.resultAt(2).value(), vec0[1]); - QCOMPARE(store.resultAt(3).value(), int1); + QCOMPARE(store.resultAt(0).value(), int0); + QCOMPARE(store.resultAt(1).value(), vec0[0]); + QCOMPARE(store.resultAt(2).value(), vec0[1]); + QCOMPARE(store.resultAt(3).value(), int1); } { - QtPrivate::ResultStore store; + ResultStoreInt store; store.addResult(-1, &int0); store.addResults(-1, &vec0); store.addResult(200, &int1); - QCOMPARE(store.resultAt(0).value(), int0); - QCOMPARE(store.resultAt(1).value(), vec0[0]); - QCOMPARE(store.resultAt(2).value(), vec0[1]); - QCOMPARE(store.resultAt(200).value(), int1); + QCOMPARE(store.resultAt(0).value(), int0); + QCOMPARE(store.resultAt(1).value(), vec0[0]); + QCOMPARE(store.resultAt(2).value(), vec0[1]); + QCOMPARE(store.resultAt(200).value(), int1); } { - QtPrivate::ResultStore store; + ResultStoreInt store; store.addResult(1, &int1); store.addResult(0, &int0); store.addResult(-1, &int2); - QCOMPARE(store.resultAt(0).value(), int0); - QCOMPARE(store.resultAt(1).value(), int1); - QCOMPARE(store.resultAt(2).value(), int2); + QCOMPARE(store.resultAt(0).value(), int0); + QCOMPARE(store.resultAt(1).value(), int1); + QCOMPARE(store.resultAt(2).value(), int2); } { - QtPrivate::ResultStore store; + ResultStoreInt store; QCOMPARE(store.contains(0), false); QCOMPARE(store.contains(1), false); QCOMPARE(store.contains(INT_MAX), false); @@ -223,7 +228,7 @@ void tst_QFuture::resultStore() { // Test filter mode, where "gaps" in the result array aren't allowed. - QtPrivate::ResultStore store; + ResultStoreInt store; store.setFilterMode(true); store.addResult(0, &int0); @@ -257,7 +262,7 @@ void tst_QFuture::resultStore() { // test canceled results - QtPrivate::ResultStore store; + ResultStoreInt store; store.setFilterMode(true); store.addResult(0, &int0); @@ -294,7 +299,7 @@ void tst_QFuture::resultStore() { // test addResult return value - QtPrivate::ResultStore store; + ResultStoreInt store; store.setFilterMode(true); store.addResult(0, &int0); @@ -340,7 +345,7 @@ void tst_QFuture::resultStore() { // test resultCount in non-filtered mode. It should always be possible // to iterate through the results 0 to resultCount. - QtPrivate::ResultStore store; + ResultStoreInt store; store.addResult(0, &int0); QCOMPARE(store.count(), 1); @@ -354,7 +359,7 @@ void tst_QFuture::resultStore() } { - QtPrivate::ResultStore store; + ResultStoreInt store; store.addResult(2, &int0); QCOMPARE(store.count(), 0); @@ -366,7 +371,7 @@ void tst_QFuture::resultStore() } { - QtPrivate::ResultStore store; + ResultStoreInt store; store.addResults(2, &vec1); QCOMPARE(store.count(), 0); @@ -378,7 +383,7 @@ void tst_QFuture::resultStore() } { - QtPrivate::ResultStore store; + ResultStoreInt store; store.addResults(2, &vec1); QCOMPARE(store.count(), 0); @@ -386,7 +391,7 @@ void tst_QFuture::resultStore() QCOMPARE(store.count(), 4); } { - QtPrivate::ResultStore store; + ResultStoreInt store; store.addResults(3, &vec1); QCOMPARE(store.count(), 0); @@ -398,7 +403,7 @@ void tst_QFuture::resultStore() } { - QtPrivate::ResultStore store; + ResultStoreInt store; store.setFilterMode(true); store.addResults(3, &vec1); QCOMPARE(store.count(), 0); @@ -411,22 +416,22 @@ void tst_QFuture::resultStore() } { - QtPrivate::ResultStore store; + ResultStoreInt store; store.setFilterMode(true); store.addResults(3, &vec1); QCOMPARE(store.count(), 0); - store.addCanceledResults(0, 3); + store.addCanceledResults(0, 3); QCOMPARE(store.count(), 2); } { - QtPrivate::ResultStore store; + ResultStoreInt store; store.setFilterMode(true); store.addResults(3, &vec1); QCOMPARE(store.count(), 0); - store.addCanceledResults(0, 3); + store.addCanceledResults(0, 3); QCOMPARE(store.count(), 2); // results at 3 and 4 become available at index 0, 1 store.addResult(5, &int0); @@ -434,7 +439,7 @@ void tst_QFuture::resultStore() } { - QtPrivate::ResultStore store; + ResultStoreInt store; store.addResult(1, &int0); store.addResult(3, &int0); store.addResults(6, &vec0); @@ -449,7 +454,7 @@ void tst_QFuture::resultStore() } { - QtPrivate::ResultStore store; + ResultStoreInt store; store.setFilterMode(true); store.addResult(1, &int0); store.addResult(3, &int0); @@ -465,7 +470,7 @@ void tst_QFuture::resultStore() store.addCanceledResult(0); store.addCanceledResult(2); - store.addCanceledResults(4, 2); + store.addCanceledResults(4, 2); QCOMPARE(store.contains(0), true); QCOMPARE(store.contains(1), true); @@ -477,7 +482,7 @@ void tst_QFuture::resultStore() QCOMPARE(store.contains(7), false); } { - QtPrivate::ResultStore store; + ResultStoreInt store; store.setFilterMode(true); store.addCanceledResult(0); QCOMPARE(store.contains(0), false); diff --git a/tests/auto/corelib/thread/qresultstore/tst_qresultstore.cpp b/tests/auto/corelib/thread/qresultstore/tst_qresultstore.cpp index 3626b8db33..fba617e34d 100644 --- a/tests/auto/corelib/thread/qresultstore/tst_qresultstore.cpp +++ b/tests/auto/corelib/thread/qresultstore/tst_qresultstore.cpp @@ -32,6 +32,11 @@ using namespace QtPrivate; +struct ResultStoreInt : ResultStoreBase +{ + ~ResultStoreInt() { clear(); } +}; + class tst_QtConcurrentResultStore : public QObject { Q_OBJECT @@ -67,20 +72,20 @@ void tst_QtConcurrentResultStore::init() void tst_QtConcurrentResultStore::construction() { - ResultStore store; + ResultStoreBase store; QCOMPARE(store.count(), 0); } void tst_QtConcurrentResultStore::iterators() { { - ResultStore store; + ResultStoreBase store; QCOMPARE(store.begin(), store.end()); QCOMPARE(store.resultAt(0), store.end()); QCOMPARE(store.resultAt(1), store.end()); } { - ResultStoreBase storebase; + ResultStoreInt storebase; storebase.addResult(-1, &int0); // note to self: adding a pointer to the stack here is ok since storebase.addResult(1, &int1); // ResultStoreBase does not take ownership, only ResultStore<> does. ResultIteratorBase it = storebase.begin(); @@ -103,7 +108,7 @@ void tst_QtConcurrentResultStore::addResult() { { // test addResult return value - ResultStore store; + ResultStoreInt store; store.setFilterMode(true); QCOMPARE(store.addResult(0, &int0), 0); @@ -149,10 +154,9 @@ void tst_QtConcurrentResultStore::addResult() void tst_QtConcurrentResultStore::addResults() { - - ResultStoreBase store; - store.addResults(-1, &vec0, 2, 2); - store.addResults(-1, &vec1, 2, 2); + ResultStoreInt store; + store.addResults(-1, &vec0); + store.addResults(-1, &vec1); ResultIteratorBase it = store.begin(); QCOMPARE(it.resultIndex(), 0); QCOMPARE(it, store.begin()); @@ -175,7 +179,7 @@ void tst_QtConcurrentResultStore::addResults() void tst_QtConcurrentResultStore::resultIndex() { - ResultStore store; + ResultStoreInt store; store.addResult(-1, &int0); store.addResults(-1, &vec0); store.addResult(-1, &int1); @@ -199,41 +203,41 @@ void tst_QtConcurrentResultStore::resultIndex() ++it; QVERIFY(it == store.end()); - QCOMPARE(store.resultAt(0).value(), int0); - QCOMPARE(store.resultAt(1).value(), vec0[0]); - QCOMPARE(store.resultAt(2).value(), vec0[1]); - QCOMPARE(store.resultAt(3).value(), int1); + QCOMPARE(store.resultAt(0).value(), int0); + QCOMPARE(store.resultAt(1).value(), vec0[0]); + QCOMPARE(store.resultAt(2).value(), vec0[1]); + QCOMPARE(store.resultAt(3).value(), int1); } void tst_QtConcurrentResultStore::resultAt() { { - ResultStore store; + ResultStoreInt store; store.addResult(-1, &int0); store.addResults(-1, &vec0); store.addResult(200, &int1); - QCOMPARE(store.resultAt(0).value(), int0); - QCOMPARE(store.resultAt(1).value(), vec0[0]); - QCOMPARE(store.resultAt(2).value(), vec0[1]); - QCOMPARE(store.resultAt(200).value(), int1); + QCOMPARE(store.resultAt(0).value(), int0); + QCOMPARE(store.resultAt(1).value(), vec0[0]); + QCOMPARE(store.resultAt(2).value(), vec0[1]); + QCOMPARE(store.resultAt(200).value(), int1); } { - ResultStore store; + ResultStoreInt store; store.addResult(1, &int1); store.addResult(0, &int0); store.addResult(-1, &int2); - QCOMPARE(store.resultAt(0).value(), int0); - QCOMPARE(store.resultAt(1).value(), int1); - QCOMPARE(store.resultAt(2).value(), int2); + QCOMPARE(store.resultAt(0).value(), int0); + QCOMPARE(store.resultAt(1).value(), int1); + QCOMPARE(store.resultAt(2).value(), int2); } } void tst_QtConcurrentResultStore::contains() { { - ResultStore store; + ResultStoreInt store; QCOMPARE(store.contains(0), false); QCOMPARE(store.contains(1), false); QCOMPARE(store.contains(INT_MAX), false); @@ -245,7 +249,7 @@ void tst_QtConcurrentResultStore::contains() QVERIFY(store.contains(int2)); } { - ResultStore store; + ResultStoreInt store; store.addResult(1, &int0); store.addResult(3, &int0); store.addResults(6, &vec0); @@ -260,7 +264,7 @@ void tst_QtConcurrentResultStore::contains() } { - ResultStore store; + ResultStoreInt store; store.setFilterMode(true); store.addResult(1, &int0); store.addResult(3, &int0); @@ -276,7 +280,7 @@ void tst_QtConcurrentResultStore::contains() store.addCanceledResult(0); store.addCanceledResult(2); - store.addCanceledResults(4, 2); + store.addCanceledResults(4, 2); QCOMPARE(store.contains(0), true); QCOMPARE(store.contains(1), true); @@ -288,7 +292,7 @@ void tst_QtConcurrentResultStore::contains() QCOMPARE(store.contains(7), false); } { - ResultStore store; + ResultStoreInt store; store.setFilterMode(true); store.addCanceledResult(0); QCOMPARE(store.contains(0), false); @@ -302,7 +306,7 @@ void tst_QtConcurrentResultStore::contains() void tst_QtConcurrentResultStore::filterMode() { // Test filter mode, where "gaps" in the result array aren't allowed. - ResultStore store; + ResultStoreInt store; QCOMPARE(store.filterMode(), false); store.setFilterMode(true); QVERIFY(store.filterMode()); @@ -339,7 +343,7 @@ void tst_QtConcurrentResultStore::filterMode() void tst_QtConcurrentResultStore::addCanceledResult() { // test canceled results - ResultStore store; + ResultStoreInt store; store.setFilterMode(true); store.addResult(0, &int0); @@ -379,7 +383,7 @@ void tst_QtConcurrentResultStore::count() { // test resultCount in non-filtered mode. It should always be possible // to iterate through the results 0 to resultCount. - ResultStore store; + ResultStoreInt store; store.addResult(0, &int0); QCOMPARE(store.count(), 1); @@ -393,7 +397,7 @@ void tst_QtConcurrentResultStore::count() } { - ResultStore store; + ResultStoreInt store; store.addResult(2, &int0); QCOMPARE(store.count(), 0); @@ -405,7 +409,7 @@ void tst_QtConcurrentResultStore::count() } { - ResultStore store; + ResultStoreInt store; store.addResults(2, &vec1); QCOMPARE(store.count(), 0); @@ -417,7 +421,7 @@ void tst_QtConcurrentResultStore::count() } { - ResultStore store; + ResultStoreInt store; store.addResults(2, &vec1); QCOMPARE(store.count(), 0); @@ -425,7 +429,7 @@ void tst_QtConcurrentResultStore::count() QCOMPARE(store.count(), 4); } { - ResultStore store; + ResultStoreInt store; store.addResults(3, &vec1); QCOMPARE(store.count(), 0); @@ -437,7 +441,7 @@ void tst_QtConcurrentResultStore::count() } { - ResultStore store; + ResultStoreInt store; store.setFilterMode(true); store.addResults(3, &vec1); QCOMPARE(store.count(), 0); @@ -450,22 +454,22 @@ void tst_QtConcurrentResultStore::count() } { - ResultStore store; + ResultStoreInt store; store.setFilterMode(true); store.addResults(3, &vec1); QCOMPARE(store.count(), 0); - store.addCanceledResults(0, 3); + store.addCanceledResults(0, 3); QCOMPARE(store.count(), 2); } { - ResultStore store; + ResultStoreInt store; store.setFilterMode(true); store.addResults(3, &vec1); QCOMPARE(store.count(), 0); - store.addCanceledResults(0, 3); + store.addCanceledResults(0, 3); QCOMPARE(store.count(), 2); // results at 3 and 4 become available at index 0, 1 store.addResult(5, &int0);